debugbundle 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Makefile +9 -0
- data/README.md +250 -58
- data/lib/debugbundle/version.rb +1 -1
- data/spec/fixtures/event-envelope.schema.json +137 -0
- data/spec/repository_metadata_spec.rb +65 -0
- metadata +5 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cd8a77046a7f20cf6971b6e73ca8e5c7557738706e32e3b30e741f3410f8d00a
|
|
4
|
+
data.tar.gz: 0bd638cf69ff2c6894706b1bc996f801e849b6f5a5c134543a3a18d1c598725f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c9431211f33958cf178a8ace0e01b3842a2a2ff1bed8e11129e053ceb6b8685ff17499d03c80bc3cfe3fc7fd6839eced529ab01238760f04a65f4181e6685507
|
|
7
|
+
data.tar.gz: f7a432f0dc42da84a44415c767610473d8f332577eeb658c1417e47e4227e2701f7143e67fb9a8fa40db700dfca9f9ba0f655fe270fbd779de0e499507dc6836
|
data/Makefile
CHANGED
|
@@ -3,6 +3,7 @@ SHELL := /bin/sh
|
|
|
3
3
|
RUBY_IMAGE ?= ruby:3.4.2
|
|
4
4
|
WORKDIR := /workspace
|
|
5
5
|
BUNDLE_GEMFILE ?= Gemfile
|
|
6
|
+
VERSION ?= $(shell ruby -e 'require "./lib/debugbundle/version"; print DebugBundle::VERSION')
|
|
6
7
|
|
|
7
8
|
DOCKER_RUN = docker run --rm -t \
|
|
8
9
|
-v "$(PWD):$(WORKDIR)" \
|
|
@@ -12,6 +13,8 @@ DOCKER_RUN = docker run --rm -t \
|
|
|
12
13
|
BUNDLE_ENV = BUNDLE_GEMFILE="$(BUNDLE_GEMFILE)"
|
|
13
14
|
|
|
14
15
|
.PHONY: bundle-install test lint build shell compat-rack compat-rails compat-sidekiq compat
|
|
16
|
+
.PHONY: smoke
|
|
17
|
+
.PHONY: smoke-published
|
|
15
18
|
|
|
16
19
|
bundle-install:
|
|
17
20
|
$(DOCKER_RUN) sh -lc "$(BUNDLE_ENV) bundle config set path vendor/bundle && $(BUNDLE_ENV) bundle install"
|
|
@@ -25,6 +28,12 @@ lint:
|
|
|
25
28
|
build:
|
|
26
29
|
$(DOCKER_RUN) sh -lc "$(BUNDLE_ENV) bundle config set path vendor/bundle && $(BUNDLE_ENV) bundle install && gem build debugbundle.gemspec"
|
|
27
30
|
|
|
31
|
+
smoke:
|
|
32
|
+
$(DOCKER_RUN) sh -lc "gem build debugbundle.gemspec && ruby smoke/run_app_driven_smoke.rb --source local --version $(VERSION)"
|
|
33
|
+
|
|
34
|
+
smoke-published:
|
|
35
|
+
$(DOCKER_RUN) sh -lc "ruby smoke/run_app_driven_smoke.rb --source published --version $(VERSION)"
|
|
36
|
+
|
|
28
37
|
compat-rack:
|
|
29
38
|
docker run --rm -t -v "$(PWD):$(WORKDIR)" -w "$(WORKDIR)" ruby:3.1.6 sh -lc 'SIMPLECOV_MINIMUM_COVERAGE=0 BUNDLE_GEMFILE="gemfiles/rack_2_2.gemfile" bundle config set path vendor/bundle && SIMPLECOV_MINIMUM_COVERAGE=0 BUNDLE_GEMFILE="gemfiles/rack_2_2.gemfile" bundle install && SIMPLECOV_MINIMUM_COVERAGE=0 BUNDLE_GEMFILE="gemfiles/rack_2_2.gemfile" bundle exec rspec spec/rack_integration_spec.rb spec/rack_middleware_spec.rb spec/relay_spec.rb'
|
|
30
39
|
docker run --rm -t -v "$(PWD):$(WORKDIR)" -w "$(WORKDIR)" ruby:3.4.2 sh -lc 'SIMPLECOV_MINIMUM_COVERAGE=0 BUNDLE_GEMFILE="gemfiles/rack_3.gemfile" bundle config set path vendor/bundle && SIMPLECOV_MINIMUM_COVERAGE=0 BUNDLE_GEMFILE="gemfiles/rack_3.gemfile" bundle install && SIMPLECOV_MINIMUM_COVERAGE=0 BUNDLE_GEMFILE="gemfiles/rack_3.gemfile" bundle exec rspec spec/rack_integration_spec.rb spec/rack_middleware_spec.rb spec/relay_spec.rb'
|
data/README.md
CHANGED
|
@@ -10,38 +10,33 @@ Use this gem to capture Ruby backend exceptions, request metadata, structured lo
|
|
|
10
10
|
gem "debugbundle"
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
## Quick
|
|
13
|
+
## Quick Start
|
|
14
14
|
|
|
15
15
|
```ruby
|
|
16
16
|
require "debugbundle"
|
|
17
|
+
require "logger"
|
|
17
18
|
|
|
18
19
|
DebugBundle.init(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
project_token: ENV.fetch("DEBUGBUNDLE_TOKEN"),
|
|
21
|
+
service: "checkout-api",
|
|
22
|
+
environment: ENV.fetch("APP_ENV", "production")
|
|
22
23
|
)
|
|
23
24
|
|
|
24
25
|
DebugBundle.capture_logger(Logger.new($stdout))
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
`DebugBundle.init(...)` arms best-effort process exception capture automatically through `at_exit` and thread exception hooks.
|
|
28
26
|
|
|
29
|
-
Capture handled exceptions, messages, requests, and probes explicitly:
|
|
30
|
-
|
|
31
|
-
```ruby
|
|
32
27
|
begin
|
|
33
|
-
|
|
28
|
+
perform_checkout
|
|
34
29
|
rescue => error
|
|
35
|
-
|
|
30
|
+
DebugBundle.capture_exception(error, context: { order_id: 123 })
|
|
36
31
|
end
|
|
37
32
|
|
|
38
|
-
DebugBundle.capture_log("payment retry failed", level: :warning, context: { order_id: 123 })
|
|
39
33
|
DebugBundle.capture_message("worker started", level: :info)
|
|
40
|
-
DebugBundle.probe("checkout.tax", { region: "us-east-1" })
|
|
41
34
|
DebugBundle.flush
|
|
42
35
|
```
|
|
43
36
|
|
|
44
|
-
|
|
37
|
+
`DebugBundle.init(...)` arms best-effort process exception capture automatically through `at_exit` and thread exception hooks.
|
|
38
|
+
|
|
39
|
+
## Framework Integrations
|
|
45
40
|
|
|
46
41
|
| Surface | Integration |
|
|
47
42
|
| --- | --- |
|
|
@@ -52,44 +47,20 @@ DebugBundle.flush
|
|
|
52
47
|
| Semantic Logger | `DebugBundle.capture_semantic_logger` |
|
|
53
48
|
| Browser relay | `DebugBundle::Relay::Handler` or `DebugBundle::Rack::RelayMiddleware` |
|
|
54
49
|
|
|
55
|
-
##
|
|
50
|
+
## Configuration Reference
|
|
56
51
|
|
|
57
|
-
|
|
52
|
+
Configuration sources and precedence:
|
|
58
53
|
|
|
59
|
-
|
|
54
|
+
1. Explicit arguments passed to `DebugBundle.init(...)`, `DebugBundle::Client.new(...)`, or `DebugBundle::Relay::Handler.new(...)`.
|
|
55
|
+
2. Rails `config.debugbundle.*` values when the Railtie wires the default client or relay route.
|
|
56
|
+
3. Environment variables only when your application chooses to pass them into those explicit Ruby calls. The gem does not auto-read arbitrary config env vars on its own.
|
|
57
|
+
4. Remote probe directives and capture policy returned by `GET /v1/sdk/config` after a connected client initializes.
|
|
60
58
|
|
|
61
|
-
-
|
|
62
|
-
- `config.debugbundle.relay_path = "/debugbundle/browser"` to change the mounted path
|
|
63
|
-
- `config.debugbundle.relay_allowed_origins = ["https://app.example.com"]` to pin allowed origins
|
|
64
|
-
- `config.debugbundle.relay_rate_limit_per_minute = 120` to adjust per-IP relay throttling
|
|
65
|
-
- `config.debugbundle.relay_rate_limit_store = Rails.cache` to share relay throttling across processes
|
|
66
|
-
- `config.debugbundle.relay_handler = custom_handler` to supply a custom relay handler
|
|
67
|
-
|
|
68
|
-
The relay:
|
|
69
|
-
|
|
70
|
-
- validates same-origin requests by default
|
|
71
|
-
- enforces `Content-Type: application/json`
|
|
72
|
-
- caps request bodies at 256 KB
|
|
73
|
-
- strips browser-supplied credentials and trust-sensitive fields
|
|
74
|
-
- preserves browser correlation fields such as `trace_id`
|
|
75
|
-
- supports local-only event writes and connected durable forwarding
|
|
76
|
-
|
|
77
|
-
## Remote probes
|
|
78
|
-
|
|
79
|
-
Probe buffers stay local and flush on captured exceptions by default. Paid-tier projects can also activate probes for immediate `probe_event` shipping through the polled remote config.
|
|
80
|
-
|
|
81
|
-
For one-off request diagnostics, the Ruby SDK also accepts signed trigger tokens:
|
|
82
|
-
|
|
83
|
-
- header: `X-DebugBundle-Probe-Trigger: dbundle_probe_...`
|
|
84
|
-
- query parameter: `?_debug_probe=dbundle_probe_...`
|
|
85
|
-
|
|
86
|
-
Matching probes still stay in the local ring buffer, but the triggered request also emits standalone `probe_event` records immediately when the token is valid.
|
|
87
|
-
|
|
88
|
-
## Configuration
|
|
59
|
+
Capture-policy fields are server-owned and must not be supplied in local SDK config. The Ruby SDK enforces the server response locally after initialization.
|
|
89
60
|
|
|
90
61
|
| Option | Default | Purpose |
|
|
91
62
|
| --- | --- | --- |
|
|
92
|
-
| `project_token` | required | Write-only DebugBundle project token. |
|
|
63
|
+
| `project_token` | required for connected capture | Write-only DebugBundle project token used by server-side transport. |
|
|
93
64
|
| `service` | `ruby-service` | Service name used in event envelopes. |
|
|
94
65
|
| `environment` | `development` | Runtime environment. |
|
|
95
66
|
| `endpoint` | `https://api.debugbundle.com/v1/events` | Connected ingestion endpoint. |
|
|
@@ -110,7 +81,178 @@ Matching probes still stay in the local ring buffer, but the triggered request a
|
|
|
110
81
|
| `probe_flush_on_error` | `true` | Attach probe buffers to captured exceptions. |
|
|
111
82
|
| `probes_poll_interval` | `60` | Remote config poll interval in seconds. |
|
|
112
83
|
|
|
113
|
-
##
|
|
84
|
+
## Install Examples by Mode
|
|
85
|
+
|
|
86
|
+
### Connected mode
|
|
87
|
+
|
|
88
|
+
```ruby
|
|
89
|
+
require "debugbundle"
|
|
90
|
+
|
|
91
|
+
DebugBundle.init(
|
|
92
|
+
project_token: ENV.fetch("DEBUGBUNDLE_TOKEN"),
|
|
93
|
+
service: "checkout-api",
|
|
94
|
+
environment: "production",
|
|
95
|
+
endpoint: "https://api.debugbundle.com/v1/events"
|
|
96
|
+
)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Local-only mode
|
|
100
|
+
|
|
101
|
+
```ruby
|
|
102
|
+
require "debugbundle"
|
|
103
|
+
|
|
104
|
+
DebugBundle.init(
|
|
105
|
+
project_token: ENV.fetch("DEBUGBUNDLE_TOKEN"),
|
|
106
|
+
service: "checkout-api",
|
|
107
|
+
environment: "development",
|
|
108
|
+
project_mode: :local_only,
|
|
109
|
+
local_events_dir: ".debugbundle/local/events"
|
|
110
|
+
)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Rack middleware
|
|
114
|
+
|
|
115
|
+
```ruby
|
|
116
|
+
require "debugbundle"
|
|
117
|
+
require "rack"
|
|
118
|
+
|
|
119
|
+
client = DebugBundle.init(
|
|
120
|
+
project_token: ENV.fetch("DEBUGBUNDLE_TOKEN"),
|
|
121
|
+
service: "checkout-api",
|
|
122
|
+
environment: "production"
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
app = Rack::Builder.new do
|
|
126
|
+
use DebugBundle::Rack::Middleware, client: client
|
|
127
|
+
|
|
128
|
+
run lambda { |_env|
|
|
129
|
+
[200, { "Content-Type" => "text/plain" }, ["ok"]]
|
|
130
|
+
}
|
|
131
|
+
end
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Rails initializer
|
|
135
|
+
|
|
136
|
+
```ruby
|
|
137
|
+
# config/initializers/debugbundle.rb
|
|
138
|
+
require "debugbundle"
|
|
139
|
+
|
|
140
|
+
DebugBundle.init(
|
|
141
|
+
project_token: ENV.fetch("DEBUGBUNDLE_TOKEN"),
|
|
142
|
+
service: "checkout-api",
|
|
143
|
+
environment: Rails.env
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
Rails.application.configure do
|
|
147
|
+
config.debugbundle.relay_allowed_origins = ["https://app.example.com"]
|
|
148
|
+
end
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Sidekiq server middleware
|
|
152
|
+
|
|
153
|
+
```ruby
|
|
154
|
+
require "debugbundle"
|
|
155
|
+
|
|
156
|
+
DebugBundle.init(
|
|
157
|
+
project_token: ENV.fetch("DEBUGBUNDLE_TOKEN"),
|
|
158
|
+
service: "checkout-worker",
|
|
159
|
+
environment: ENV.fetch("APP_ENV", "production")
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
Sidekiq.configure_server do |config|
|
|
163
|
+
config.server_middleware do |chain|
|
|
164
|
+
chain.add(DebugBundle::Sidekiq::ServerMiddleware, client: DebugBundle.client)
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Logger integration
|
|
170
|
+
|
|
171
|
+
```ruby
|
|
172
|
+
require "debugbundle"
|
|
173
|
+
require "logger"
|
|
174
|
+
|
|
175
|
+
DebugBundle.init(
|
|
176
|
+
project_token: ENV.fetch("DEBUGBUNDLE_TOKEN"),
|
|
177
|
+
service: "checkout-api"
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
logger = Logger.new($stdout)
|
|
181
|
+
DebugBundle.capture_logger(logger)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Runtime and Framework Support
|
|
185
|
+
|
|
186
|
+
| Surface | Minimum compatibility version | Recommended production version | Installed-base compatibility lane | Rolling CI lane | Out of scope |
|
|
187
|
+
| --- | --- | --- | --- | --- | --- |
|
|
188
|
+
| Ruby runtime | 3.1 | current maintained Ruby 3.4.x patch line | 3.1 and 3.2 remain supported for installed-base coverage | 3.1, 3.2, 3.3, 3.4 | 3.0 and older |
|
|
189
|
+
| Rails | 7.0 | latest 7.1 patch line | 7.0 compatibility support | 7.0 and 7.1 | 6.x and older |
|
|
190
|
+
| Rack | 2.2 | latest 3.x patch line | 2.2 compatibility support | 2.2 and 3.x | 2.1 and older |
|
|
191
|
+
| Sidekiq | 7.x | latest 8.x patch line | 7.x compatibility support | 7.x and 8.x | 6.x and older |
|
|
192
|
+
|
|
193
|
+
Post-V1 integrations remain out of scope here: Resque, Delayed Job, GoodJob, Sneakers, Shoryuken, Sinatra, Hanami, and deep ActiveRecord or SQL auto-instrumentation.
|
|
194
|
+
|
|
195
|
+
## Dependency Alignment
|
|
196
|
+
|
|
197
|
+
`debugbundle` ships as one gem in V1, so there is no multi-package version-alignment surface like an npm family rule or Maven BOM.
|
|
198
|
+
|
|
199
|
+
- Pin one `debugbundle` version across your Ruby web app and worker repos when you want identical SDK behavior everywhere.
|
|
200
|
+
- Keep Rack, Rails, and Sidekiq inside the supported lanes above.
|
|
201
|
+
- Do not mix unsupported framework majors into examples or deployment templates.
|
|
202
|
+
|
|
203
|
+
## Browser Relay
|
|
204
|
+
|
|
205
|
+
Ruby backends can receive browser events at `POST /debugbundle/browser` through the relay handler.
|
|
206
|
+
|
|
207
|
+
Rails applications can let the Railtie append that route automatically, or override it with:
|
|
208
|
+
|
|
209
|
+
- `config.debugbundle.relay_enabled = false` to disable automatic mounting
|
|
210
|
+
- `config.debugbundle.relay_path = "/debugbundle/browser"` to change the mounted path
|
|
211
|
+
- `config.debugbundle.relay_allowed_origins = ["https://app.example.com"]` to pin allowed origins
|
|
212
|
+
- `config.debugbundle.relay_rate_limit_per_minute = 120` to adjust per-IP rate limiting
|
|
213
|
+
- `config.debugbundle.relay_rate_limit_store = Rails.cache` to share rate limiting across processes
|
|
214
|
+
- `config.debugbundle.relay_handler = custom_handler` to supply a custom relay handler
|
|
215
|
+
|
|
216
|
+
Rack applications can mount the same handler explicitly:
|
|
217
|
+
|
|
218
|
+
```ruby
|
|
219
|
+
relay_handler = DebugBundle::Relay::Handler.new(
|
|
220
|
+
project_mode: :connected,
|
|
221
|
+
project_token: ENV.fetch("DEBUGBUNDLE_TOKEN"),
|
|
222
|
+
endpoint: "https://api.debugbundle.com/v1/events",
|
|
223
|
+
allowed_origins: ["https://app.example.com"]
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
use DebugBundle::Rack::RelayMiddleware, handler: relay_handler
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Relay behavior:
|
|
230
|
+
|
|
231
|
+
- same-origin is the safe default when you do not set explicit allowed origins
|
|
232
|
+
- use explicit allowed origins when the frontend and backend live on different hosts
|
|
233
|
+
- requests must use `Content-Type: application/json`
|
|
234
|
+
- request bodies are capped at 256 KB
|
|
235
|
+
- per-IP rate limiting defaults to 60 requests per minute
|
|
236
|
+
- browser-supplied DebugBundle credentials are stripped before delivery, preserving credential isolation
|
|
237
|
+
- browser `service`, `environment`, and correlation fields are preserved unless you explicitly override them in the relay handler
|
|
238
|
+
- local-only mode writes validated browser events to `.debugbundle/local/events`
|
|
239
|
+
- connected durable mode writes validated browser events to `.debugbundle/local/browser-relay-spool` before forwarding to the configured endpoint
|
|
240
|
+
- set `relay_durable_write: false` when you intentionally want connected forwarding without the local spool write
|
|
241
|
+
- to disable the relay entirely, leave the route unmounted or set `relay_enabled = false`
|
|
242
|
+
- a missing token means connected forwarding cannot succeed; treat that as a server config error and leave the route disabled until the server-side token is fixed
|
|
243
|
+
|
|
244
|
+
## Remote Probes
|
|
245
|
+
|
|
246
|
+
Probe buffers stay local and flush on captured exceptions by default. Paid-tier projects can also activate probes for immediate `probe_event` shipping through the polled remote config.
|
|
247
|
+
|
|
248
|
+
For one-off request diagnostics, the Ruby SDK also accepts signed trigger tokens:
|
|
249
|
+
|
|
250
|
+
- header: `X-DebugBundle-Probe-Trigger: dbundle_probe_...`
|
|
251
|
+
- query parameter: `?_debug_probe=dbundle_probe_...`
|
|
252
|
+
|
|
253
|
+
Matching probes still stay in the local ring buffer, but the triggered request also emits standalone `probe_event` records immediately when the token is valid.
|
|
254
|
+
|
|
255
|
+
## Safety Defaults
|
|
114
256
|
|
|
115
257
|
- SDK failures are isolated from host application failures.
|
|
116
258
|
- Sensitive values are redacted before buffering or transport.
|
|
@@ -121,13 +263,69 @@ Matching probes still stay in the local ring buffer, but the triggered request a
|
|
|
121
263
|
- `development`, `local`, and `test` environments write local event files by default.
|
|
122
264
|
- Browser relay requests cannot smuggle server-side credentials.
|
|
123
265
|
|
|
266
|
+
## Service Naming
|
|
267
|
+
|
|
268
|
+
Use distinct service names when one DebugBundle project receives events from multiple deployables:
|
|
269
|
+
|
|
270
|
+
- Browser frontend: `checkout-web`
|
|
271
|
+
- Rails or Rack API: `checkout-api`
|
|
272
|
+
- Sidekiq worker: `checkout-worker`
|
|
273
|
+
|
|
274
|
+
The Ruby relay preserves the browser-provided service name and environment by default. Only override relay-level `service` or `environment` when you intentionally want the backend relay host to rewrite browser event identity.
|
|
275
|
+
|
|
276
|
+
## Safe Startup and Status
|
|
277
|
+
|
|
278
|
+
The SDK never raises host-facing exceptions because of missing config, bad transport responses, or malformed remote config payloads.
|
|
279
|
+
|
|
280
|
+
- `DebugBundle.init(project_token: "")` leaves capture disabled and `DebugBundle.status` reports `:degraded`
|
|
281
|
+
- `DebugBundle.init(enabled: false)` keeps the SDK as a no-op and `DebugBundle.status` reports `:disconnected`
|
|
282
|
+
- `DebugBundle.last_event_at` stays `nil` until a successful flush completes
|
|
283
|
+
- `DebugBundle.flush` is a no-op when the SDK has no buffered events, no transport, or is still waiting out a retry window
|
|
284
|
+
|
|
285
|
+
Status meanings:
|
|
286
|
+
|
|
287
|
+
- `:healthy` — idle or the last flush succeeded
|
|
288
|
+
- `:degraded` — missing token or a temporary rate-limit window is preventing immediate delivery
|
|
289
|
+
- `:disconnected` — the SDK is disabled or repeated transport failures exhausted the connection path
|
|
290
|
+
|
|
291
|
+
The release rule here is fail-safe, not fail-open: connected mode with a missing token must never pretend capture is healthy.
|
|
292
|
+
|
|
293
|
+
## First-Event Verification
|
|
294
|
+
|
|
295
|
+
Use an explicit test message or exception during setup:
|
|
296
|
+
|
|
297
|
+
```ruby
|
|
298
|
+
require "debugbundle"
|
|
299
|
+
|
|
300
|
+
DebugBundle.init(
|
|
301
|
+
project_token: ENV.fetch("DEBUGBUNDLE_TOKEN"),
|
|
302
|
+
service: "debugbundle-first-event",
|
|
303
|
+
environment: "staging"
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
DebugBundle.capture_message("debugbundle first-event verification", level: :error)
|
|
307
|
+
DebugBundle.flush
|
|
308
|
+
puts [DebugBundle.status, DebugBundle.last_event_at].inspect
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Then confirm the event through your mock ingestion endpoint, a staging project, or the DebugBundle CLI verification flow.
|
|
312
|
+
|
|
313
|
+
This repository also ships a clean-install app-driven smoke harness that validates the built gem and the published gem path:
|
|
314
|
+
|
|
315
|
+
```sh
|
|
316
|
+
make smoke
|
|
317
|
+
make smoke-published VERSION=0.1.0
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
`make smoke` builds the gem, installs it into a fresh RubyGems home, drives a Rack request plus a browser relay batch through the public SDK surface, validates event envelope shape, and confirms the mock ingestion endpoint receives the expected service, environment, SDK metadata, and correlation fields.
|
|
321
|
+
|
|
124
322
|
## Examples
|
|
125
323
|
|
|
126
324
|
- Rack app: [examples/rack_app.rb](examples/rack_app.rb)
|
|
127
325
|
- Rails initializer: [examples/rails_initializer.rb](examples/rails_initializer.rb)
|
|
128
326
|
- Sidekiq server setup: [examples/sidekiq_initializer.rb](examples/sidekiq_initializer.rb)
|
|
129
327
|
|
|
130
|
-
##
|
|
328
|
+
## Development
|
|
131
329
|
|
|
132
330
|
The project defaults to Docker-backed commands:
|
|
133
331
|
|
|
@@ -137,9 +335,10 @@ make test
|
|
|
137
335
|
make compat
|
|
138
336
|
make lint
|
|
139
337
|
make build
|
|
338
|
+
make smoke
|
|
140
339
|
```
|
|
141
340
|
|
|
142
|
-
|
|
341
|
+
CI validates RSpec, RuboCop, compatibility lanes, gem build, and the clean-install smoke harness.
|
|
143
342
|
|
|
144
343
|
## Release
|
|
145
344
|
|
|
@@ -147,14 +346,7 @@ The repository ships a GitHub Actions release workflow at `.github/workflows/rel
|
|
|
147
346
|
|
|
148
347
|
- Push a `v*` tag or run the workflow manually with a `version` input.
|
|
149
348
|
- Configure the `RUBYGEMS_API_KEY` repository secret before enabling publish.
|
|
150
|
-
- The workflow runs lint, tests, gem build,
|
|
151
|
-
|
|
152
|
-
## Supported targets
|
|
153
|
-
|
|
154
|
-
- Ruby 3.1+
|
|
155
|
-
- Rails 7.0+
|
|
156
|
-
- Rack 2.2+
|
|
157
|
-
- Sidekiq 7.x+
|
|
349
|
+
- The workflow runs lint, tests, gem build, `make smoke`, RubyGems publish, and `make smoke-published VERSION=<tag>` before creating the GitHub release.
|
|
158
350
|
|
|
159
351
|
## Documentation
|
|
160
352
|
|
data/lib/debugbundle/version.rb
CHANGED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://debugbundle.com/schemas/event-envelope-ruby-fixture.json",
|
|
4
|
+
"oneOf": [
|
|
5
|
+
{
|
|
6
|
+
"$ref": "#/$defs/request_event_envelope"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"$ref": "#/$defs/log_event_envelope"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"$ref": "#/$defs/frontend_exception_envelope"
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"$defs": {
|
|
16
|
+
"string_map": {
|
|
17
|
+
"type": "object",
|
|
18
|
+
"additionalProperties": true
|
|
19
|
+
},
|
|
20
|
+
"service": {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"additionalProperties": false,
|
|
23
|
+
"required": ["name", "environment"],
|
|
24
|
+
"properties": {
|
|
25
|
+
"name": { "type": "string", "minLength": 1 },
|
|
26
|
+
"runtime": { "type": ["string", "null"], "minLength": 1 },
|
|
27
|
+
"framework": { "type": ["string", "null"], "minLength": 1 },
|
|
28
|
+
"environment": { "type": "string", "minLength": 1 }
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"correlation": {
|
|
32
|
+
"type": "object",
|
|
33
|
+
"additionalProperties": false,
|
|
34
|
+
"properties": {
|
|
35
|
+
"request_id": { "type": ["string", "null"] },
|
|
36
|
+
"trace_id": { "type": ["string", "null"] },
|
|
37
|
+
"session_id": { "type": ["string", "null"] },
|
|
38
|
+
"user_id_hash": { "type": ["string", "null"] }
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"envelope_base": {
|
|
42
|
+
"type": "object",
|
|
43
|
+
"additionalProperties": false,
|
|
44
|
+
"required": [
|
|
45
|
+
"schema_version",
|
|
46
|
+
"event_id",
|
|
47
|
+
"event_type",
|
|
48
|
+
"sdk_name",
|
|
49
|
+
"sdk_version",
|
|
50
|
+
"service",
|
|
51
|
+
"occurred_at",
|
|
52
|
+
"correlation",
|
|
53
|
+
"payload"
|
|
54
|
+
],
|
|
55
|
+
"properties": {
|
|
56
|
+
"schema_version": { "type": "string", "minLength": 1 },
|
|
57
|
+
"event_id": { "type": "string", "format": "uuid" },
|
|
58
|
+
"event_type": { "type": "string", "minLength": 1 },
|
|
59
|
+
"project_token": { "type": "string", "minLength": 1 },
|
|
60
|
+
"sdk_name": { "type": "string", "minLength": 1 },
|
|
61
|
+
"sdk_version": { "type": "string", "minLength": 1 },
|
|
62
|
+
"service": { "$ref": "#/$defs/service" },
|
|
63
|
+
"occurred_at": { "type": "string", "format": "date-time" },
|
|
64
|
+
"correlation": { "$ref": "#/$defs/correlation" },
|
|
65
|
+
"payload": {}
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"request_event_envelope": {
|
|
69
|
+
"allOf": [
|
|
70
|
+
{ "$ref": "#/$defs/envelope_base" },
|
|
71
|
+
{
|
|
72
|
+
"properties": {
|
|
73
|
+
"event_type": { "const": "request_event" },
|
|
74
|
+
"payload": {
|
|
75
|
+
"type": "object",
|
|
76
|
+
"additionalProperties": false,
|
|
77
|
+
"required": ["method", "path", "query", "headers", "response_status", "duration_ms"],
|
|
78
|
+
"properties": {
|
|
79
|
+
"method": { "type": "string", "minLength": 1 },
|
|
80
|
+
"path": { "type": "string", "minLength": 1 },
|
|
81
|
+
"query": { "$ref": "#/$defs/string_map" },
|
|
82
|
+
"headers": { "$ref": "#/$defs/string_map" },
|
|
83
|
+
"body": {},
|
|
84
|
+
"response_status": { "type": "integer", "minimum": 0 },
|
|
85
|
+
"duration_ms": { "type": "number", "minimum": 0 },
|
|
86
|
+
"route_template": { "type": ["string", "null"] },
|
|
87
|
+
"controller": { "type": ["string", "null"] },
|
|
88
|
+
"action": { "type": ["string", "null"] },
|
|
89
|
+
"response_headers": { "$ref": "#/$defs/string_map" },
|
|
90
|
+
"response_body": {}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
},
|
|
97
|
+
"log_event_envelope": {
|
|
98
|
+
"allOf": [
|
|
99
|
+
{ "$ref": "#/$defs/envelope_base" },
|
|
100
|
+
{
|
|
101
|
+
"properties": {
|
|
102
|
+
"event_type": { "const": "log_event" },
|
|
103
|
+
"payload": {
|
|
104
|
+
"type": "object",
|
|
105
|
+
"additionalProperties": false,
|
|
106
|
+
"required": ["level", "message", "attributes"],
|
|
107
|
+
"properties": {
|
|
108
|
+
"level": { "type": "string", "minLength": 1 },
|
|
109
|
+
"message": { "type": "string", "minLength": 1 },
|
|
110
|
+
"attributes": { "$ref": "#/$defs/string_map" }
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
},
|
|
117
|
+
"frontend_exception_envelope": {
|
|
118
|
+
"allOf": [
|
|
119
|
+
{ "$ref": "#/$defs/envelope_base" },
|
|
120
|
+
{
|
|
121
|
+
"properties": {
|
|
122
|
+
"event_type": { "const": "frontend_exception" },
|
|
123
|
+
"sdk_name": { "const": "@debugbundle/sdk-browser" },
|
|
124
|
+
"payload": {
|
|
125
|
+
"type": "object",
|
|
126
|
+
"additionalProperties": true,
|
|
127
|
+
"required": ["message"],
|
|
128
|
+
"properties": {
|
|
129
|
+
"message": { "type": "string", "minLength": 1 }
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
]
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
RSpec.describe 'repository metadata' do
|
|
6
|
+
let(:repo_root) { File.expand_path('..', __dir__) }
|
|
7
|
+
|
|
8
|
+
def read_repository_file(path)
|
|
9
|
+
File.read(File.join(repo_root, path))
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it 'ships the smoke harness and wires it into workflows' do
|
|
13
|
+
%w[
|
|
14
|
+
Makefile
|
|
15
|
+
smoke/run_app_driven_smoke.rb
|
|
16
|
+
smoke/app_driven_smoke_runner.rb
|
|
17
|
+
.github/workflows/ci.yml
|
|
18
|
+
.github/workflows/release.yml
|
|
19
|
+
].each do |relative_path|
|
|
20
|
+
expect(File).to exist(File.join(repo_root, relative_path))
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
makefile = read_repository_file('Makefile')
|
|
24
|
+
ci_workflow = read_repository_file('.github/workflows/ci.yml')
|
|
25
|
+
release_workflow = read_repository_file('.github/workflows/release.yml')
|
|
26
|
+
|
|
27
|
+
[
|
|
28
|
+
'.PHONY: smoke',
|
|
29
|
+
'.PHONY: smoke-published',
|
|
30
|
+
'smoke/run_app_driven_smoke.rb --source local',
|
|
31
|
+
'smoke/run_app_driven_smoke.rb --source published --version $(VERSION)'
|
|
32
|
+
].each do |fragment|
|
|
33
|
+
expect(makefile).to include(fragment)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
expect(ci_workflow).to include('make smoke')
|
|
37
|
+
expect(release_workflow).to include('make smoke')
|
|
38
|
+
expect(release_workflow).to include('make smoke-published VERSION=${RELEASE_VERSION}')
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'documents the Ruby release documentation gates in the README' do
|
|
42
|
+
readme = read_repository_file('README.md')
|
|
43
|
+
|
|
44
|
+
[
|
|
45
|
+
'## Configuration Reference',
|
|
46
|
+
'Configuration sources and precedence:',
|
|
47
|
+
'Capture-policy fields are server-owned',
|
|
48
|
+
'## Install Examples by Mode',
|
|
49
|
+
'## Runtime and Framework Support',
|
|
50
|
+
'## Dependency Alignment',
|
|
51
|
+
'## Browser Relay',
|
|
52
|
+
'## Service Naming',
|
|
53
|
+
'## Safe Startup and Status',
|
|
54
|
+
'## First-Event Verification',
|
|
55
|
+
'make smoke',
|
|
56
|
+
'same-origin',
|
|
57
|
+
'allowed origins',
|
|
58
|
+
'rate limiting',
|
|
59
|
+
'credential isolation',
|
|
60
|
+
'missing token'
|
|
61
|
+
].each do |fragment|
|
|
62
|
+
expect(readme).to include(fragment)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: debugbundle
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- DebugBundle
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date: 2026-05-
|
|
10
|
+
date: 2026-05-26 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: base64
|
|
@@ -71,6 +70,7 @@ files:
|
|
|
71
70
|
- spec/client_spec.rb
|
|
72
71
|
- spec/debugbundle_spec.rb
|
|
73
72
|
- spec/file_transport_spec.rb
|
|
73
|
+
- spec/fixtures/event-envelope.schema.json
|
|
74
74
|
- spec/logger_integration_spec.rb
|
|
75
75
|
- spec/rack_integration_spec.rb
|
|
76
76
|
- spec/rack_middleware_spec.rb
|
|
@@ -79,6 +79,7 @@ files:
|
|
|
79
79
|
- spec/redaction_spec.rb
|
|
80
80
|
- spec/relay_spec.rb
|
|
81
81
|
- spec/remote_config_spec.rb
|
|
82
|
+
- spec/repository_metadata_spec.rb
|
|
82
83
|
- spec/sidekiq_integration_spec.rb
|
|
83
84
|
- spec/sidekiq_middleware_spec.rb
|
|
84
85
|
- spec/spec_helper.rb
|
|
@@ -91,7 +92,6 @@ metadata:
|
|
|
91
92
|
source_code_uri: https://github.com/debugbundle/debugbundle-ruby
|
|
92
93
|
changelog_uri: https://github.com/debugbundle/debugbundle-ruby/blob/main/CHANGELOG.md
|
|
93
94
|
rubygems_mfa_required: 'true'
|
|
94
|
-
post_install_message:
|
|
95
95
|
rdoc_options: []
|
|
96
96
|
require_paths:
|
|
97
97
|
- lib
|
|
@@ -106,8 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
106
106
|
- !ruby/object:Gem::Version
|
|
107
107
|
version: '0'
|
|
108
108
|
requirements: []
|
|
109
|
-
rubygems_version: 3.
|
|
110
|
-
signing_key:
|
|
109
|
+
rubygems_version: 3.6.2
|
|
111
110
|
specification_version: 4
|
|
112
111
|
summary: DebugBundle SDK for Ruby
|
|
113
112
|
test_files: []
|