Skip to content

Commit ff3dc03

Browse files
geetfunclaude
andcommitted
Add Phase 4: Testing utilities and release documentation
Testing module: - Checkend::Testing.setup! / teardown! for test isolation - FakeClient captures notices instead of sending - Methods: notices, last_notice, first_notice, notice_count, notices? - Thread-safe implementation with Mutex Documentation: - Complete README with all features, configuration, integrations - Testing API table with Minitest and RSpec examples - CHANGELOG.md with 1.0.0 release notes CI/CD: - GitHub Actions workflow for tests (Ruby 2.7-3.4) - RuboCop linting job 190 tests, 348 assertions, 0 failures 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 504eab9 commit ff3dc03

File tree

5 files changed

+664
-21
lines changed

5 files changed

+664
-21
lines changed

.github/workflows/ci.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
fail-fast: false
14+
matrix:
15+
ruby-version:
16+
- '2.7'
17+
- '3.0'
18+
- '3.1'
19+
- '3.2'
20+
- '3.3'
21+
- '3.4'
22+
23+
steps:
24+
- uses: actions/checkout@v4
25+
26+
- name: Set up Ruby ${{ matrix.ruby-version }}
27+
uses: ruby/setup-ruby@v1
28+
with:
29+
ruby-version: ${{ matrix.ruby-version }}
30+
bundler-cache: true
31+
32+
- name: Run tests
33+
run: bundle exec rake test
34+
35+
lint:
36+
runs-on: ubuntu-latest
37+
steps:
38+
- uses: actions/checkout@v4
39+
40+
- name: Set up Ruby
41+
uses: ruby/setup-ruby@v1
42+
with:
43+
ruby-version: '3.3'
44+
bundler-cache: true
45+
46+
- name: Run RuboCop
47+
run: bundle exec rubocop

CHANGELOG.md

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,58 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [1.0.0] - 2024-12-24
11+
1012
### Added
11-
- Initial gem structure
12-
- Configuration class with environment variable support
13-
- HTTP client using Net::HTTP
14-
- Notice and NoticeBuilder classes
15-
- Main Checkend module with notify API
13+
14+
- **Core SDK**
15+
- `Checkend.configure` for SDK configuration
16+
- `Checkend.notify` for async error reporting
17+
- `Checkend.notify_sync` for synchronous error reporting
18+
- `Checkend.set_context` for thread-local context
19+
- `Checkend.set_user` for user tracking
20+
- `Checkend.clear!` to reset thread-local data
21+
22+
- **Configuration Options**
23+
- `api_key` - Required ingestion API key
24+
- `endpoint` - Checkend server URL (default: https://app.checkend.io)
25+
- `environment` - Auto-detected from Rails.env or RACK_ENV
26+
- `enabled` - Enable/disable reporting (default: true in production/staging)
27+
- `ignored_exceptions` - Exceptions to skip reporting
28+
- `filter_keys` - Keys to scrub from data (passwords, tokens, etc.)
29+
- `before_notify` - Callbacks to modify or skip notices
30+
- `async` - Async sending via background thread (default: true)
31+
- `max_queue_size` - Maximum notices to queue (default: 1000)
32+
- `shutdown_timeout` - Seconds to wait on shutdown (default: 5)
33+
- `timeout` - HTTP request timeout (default: 15s)
34+
- `open_timeout` - HTTP connection timeout (default: 5s)
35+
36+
- **Background Worker**
37+
- Thread-safe queue for async sending
38+
- Graceful shutdown with configurable timeout
39+
- Automatic drain on process exit
40+
41+
- **Filters**
42+
- `SanitizeFilter` - Scrubs sensitive keys from hashes
43+
- `IgnoreFilter` - Filters exceptions by class, name, or pattern
44+
45+
- **Integrations**
46+
- `Checkend::Integrations::Rack::Middleware` - Rack middleware for exception capture
47+
- `Checkend::Integrations::Rails::Railtie` - Auto-configuration for Rails apps
48+
- `Checkend::Integrations::Rails::ControllerMethods` - Controller context tracking
49+
- `Checkend::Integrations::Sidekiq` - Sidekiq error handler and middleware
50+
- `Checkend::Integrations::ActiveJob` - ActiveJob/Solid Queue integration
51+
52+
- **Testing**
53+
- `Checkend::Testing.setup!` - Enable test mode
54+
- `Checkend::Testing.teardown!` - Restore normal mode
55+
- `Checkend::Testing.notices` - Access captured notices
56+
- `Checkend::Testing::FakeClient` - Captures notices instead of sending
57+
58+
### Requirements
59+
60+
- Ruby >= 2.7.0
61+
- No runtime dependencies (uses Ruby stdlib only)
62+
63+
[Unreleased]: https://github.com/furvur/checkend-ruby/compare/v1.0.0...HEAD
64+
[1.0.0]: https://github.com/furvur/checkend-ruby/releases/tag/v1.0.0

README.md

Lines changed: 151 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@
66

77
Official Ruby SDK for [Checkend](https://github.com/furvur/checkend) error monitoring. Capture and report errors from Ruby applications with automatic Rails, Rack, Sidekiq, and Solid Queue integrations.
88

9+
## Features
10+
11+
- **Zero dependencies** - Uses only Ruby stdlib (Net::HTTP, JSON)
12+
- **Async sending** - Non-blocking error reporting via background thread
13+
- **Automatic context** - Captures request, user, and environment data
14+
- **Sensitive data filtering** - Automatically scrubs passwords, tokens, etc.
15+
- **Framework integrations** - Rails, Rack, Sidekiq, ActiveJob/Solid Queue
16+
917
## Installation
1018

1119
Add to your Gemfile:
@@ -42,6 +50,7 @@ That's it! The gem automatically:
4250

4351
```ruby
4452
require 'checkend-ruby'
53+
require 'checkend/integrations/rack'
4554

4655
Checkend.configure do |config|
4756
config.api_key = ENV['CHECKEND_API_KEY']
@@ -65,8 +74,12 @@ end
6574
Checkend.notify(exception,
6675
context: { order_id: 123 },
6776
user: { id: current_user.id, email: current_user.email },
68-
tags: ['checkout', 'payment']
77+
tags: ['checkout', 'payment'],
78+
fingerprint: 'custom-grouping-key'
6979
)
80+
81+
# Synchronous sending (blocks until sent)
82+
Checkend.notify_sync(exception)
7083
```
7184

7285
## Configuration
@@ -99,9 +112,26 @@ Checkend.configure do |config|
99112

100113
# Optional - Async sending (default: true)
101114
config.async = true
115+
config.max_queue_size = 1000 # Max notices to queue
116+
config.shutdown_timeout = 5 # Seconds to wait on shutdown
117+
118+
# Optional - HTTP settings
119+
config.timeout = 15 # Request timeout in seconds
120+
config.open_timeout = 5 # Connection timeout in seconds
102121
end
103122
```
104123

124+
### Environment Variables
125+
126+
The SDK respects these environment variables:
127+
128+
| Variable | Description |
129+
|----------|-------------|
130+
| `CHECKEND_API_KEY` | Your ingestion API key |
131+
| `CHECKEND_ENDPOINT` | Custom server endpoint |
132+
| `CHECKEND_ENVIRONMENT` | Override environment name |
133+
| `CHECKEND_DEBUG` | Enable debug logging (`true`/`false`) |
134+
105135
## Context and User Tracking
106136

107137
Set context that will be included with all errors:
@@ -119,9 +149,14 @@ Checkend.set_user(
119149
email: current_user.email,
120150
name: current_user.full_name
121151
)
152+
153+
# Clear context (automatically done after each request in Rails)
154+
Checkend.clear!
122155
```
123156

124-
## Sidekiq Integration
157+
## Integrations
158+
159+
### Sidekiq
125160

126161
Errors in Sidekiq jobs are automatically captured:
127162

@@ -131,36 +166,133 @@ require 'checkend/integrations/sidekiq'
131166
Checkend::Integrations::Sidekiq.install!
132167
```
133168

134-
## ActiveJob / Solid Queue Integration
169+
Job context (queue, class, jid, retry_count) is automatically included.
135170

136-
ActiveJob errors are automatically captured after the retry threshold:
171+
### ActiveJob / Solid Queue
172+
173+
For ActiveJob with backends other than Sidekiq/Resque:
137174

138175
```ruby
139-
# Automatically included via Rails Railtie
140-
# No additional configuration needed
176+
# config/initializers/checkend.rb
177+
require 'checkend/integrations/active_job'
178+
Checkend::Integrations::ActiveJob.install!
141179
```
142180

181+
Note: If using Sidekiq as your ActiveJob backend, use the Sidekiq integration instead for better context.
182+
143183
## Testing
144184

145-
Disable error reporting in tests:
185+
Use the Testing module to capture notices without sending them:
146186

147187
```ruby
148-
# test/test_helper.rb
188+
require 'checkend/testing'
189+
190+
# In your test setup
149191
Checkend::Testing.setup!
150192

151-
# In your tests
152-
def test_captures_error
153-
begin
154-
raise StandardError, 'Test error'
155-
rescue => e
156-
Checkend.notify(e)
193+
# In your test teardown
194+
Checkend::Testing.teardown!
195+
```
196+
197+
### Minitest Example
198+
199+
```ruby
200+
class MyTest < Minitest::Test
201+
def setup
202+
Checkend::Testing.setup!
157203
end
158204

159-
assert_equal 1, Checkend::Testing.notices.size
160-
assert_equal 'StandardError', Checkend::Testing.last_notice.error_class
205+
def teardown
206+
Checkend::Testing.teardown!
207+
end
208+
209+
def test_error_is_reported
210+
begin
211+
raise StandardError, 'Test error'
212+
rescue => e
213+
Checkend.notify(e)
214+
end
215+
216+
assert_equal 1, Checkend::Testing.notice_count
217+
assert_equal 'StandardError', Checkend::Testing.last_notice.error_class
218+
assert_equal 'Test error', Checkend::Testing.last_notice.message
219+
end
161220
end
162221
```
163222

223+
### RSpec Example
224+
225+
```ruby
226+
RSpec.configure do |config|
227+
config.before(:each) do
228+
Checkend::Testing.setup!
229+
end
230+
231+
config.after(:each) do
232+
Checkend::Testing.teardown!
233+
end
234+
end
235+
236+
RSpec.describe MyService do
237+
it 'reports errors' do
238+
expect { MyService.call }.to raise_error(StandardError)
239+
240+
expect(Checkend::Testing.notices?).to be true
241+
expect(Checkend::Testing.last_notice.error_class).to eq('StandardError')
242+
end
243+
end
244+
```
245+
246+
### Testing API
247+
248+
| Method | Description |
249+
|--------|-------------|
250+
| `Checkend::Testing.setup!` | Enable test mode, capture notices |
251+
| `Checkend::Testing.teardown!` | Restore normal mode, clear notices |
252+
| `Checkend::Testing.notices` | Array of captured Notice objects |
253+
| `Checkend::Testing.last_notice` | Most recent notice |
254+
| `Checkend::Testing.first_notice` | First captured notice |
255+
| `Checkend::Testing.notice_count` | Number of captured notices |
256+
| `Checkend::Testing.notices?` | True if any notices captured |
257+
| `Checkend::Testing.clear_notices!` | Clear captured notices |
258+
259+
## Filtering Sensitive Data
260+
261+
The SDK automatically filters sensitive data from:
262+
- Request parameters
263+
- Request headers
264+
- Context data
265+
- Job arguments
266+
267+
Default filtered keys: `password`, `secret`, `token`, `api_key`, `authorization`, `credit_card`, `cvv`, `ssn`
268+
269+
Add custom keys:
270+
271+
```ruby
272+
Checkend.configure do |config|
273+
config.filter_keys += ['social_security_number', 'bank_account']
274+
end
275+
```
276+
277+
## Ignoring Exceptions
278+
279+
Some exceptions don't need to be reported:
280+
281+
```ruby
282+
Checkend.configure do |config|
283+
# By class name (string)
284+
config.ignored_exceptions += ['MyNotFoundError']
285+
286+
# By class
287+
config.ignored_exceptions += [ActiveRecord::RecordNotFound]
288+
289+
# By pattern
290+
config.ignored_exceptions += [/NotFound$/]
291+
end
292+
```
293+
294+
Default ignored exceptions include `ActiveRecord::RecordNotFound`, `ActionController::RoutingError`, and other common "expected" errors.
295+
164296
## Requirements
165297

166298
- Ruby >= 2.7.0
@@ -177,6 +309,9 @@ bundle exec rake test
177309

178310
# Run linter
179311
bundle exec rubocop
312+
313+
# Build gem locally
314+
gem build checkend-ruby.gemspec
180315
```
181316

182317
## License

0 commit comments

Comments
 (0)