debugbundle 1.1.0 → 1.1.3
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/README.md +1 -1
- data/lib/debugbundle/client.rb +21 -11
- data/lib/debugbundle/relay/handler.rb +11 -8
- data/lib/debugbundle/version.rb +1 -1
- data/spec/fixtures/event-envelope.schema.json +5 -0
- data/spec/rack_middleware_spec.rb +6 -2
- data/spec/relay_spec.rb +34 -0
- data/spec/sidekiq_integration_spec.rb +1 -1
- data/spec/sidekiq_middleware_spec.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a7c3b7839eda588014c28fc36b2c0337a754c42b2c75db59b3a18569d0c18dad
|
|
4
|
+
data.tar.gz: 39dabc4e2221bebede01e96faf24f6baa517cdeddb6495f28c0c25d2c5cd41df
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 117cc67dd6b26bd728563e901abe113efbb83b3a661c572f0d29e02bdc1828d326e89f604701fe8320af2b31ba9b1c0c747d87c61dc6f6f3f9cb7bf5319cac52
|
|
7
|
+
data.tar.gz: ea39d1fd9cf648ba1341f9aeb72900f899bb8ab3f384f6f02c6e50ccdd51fd666cf213492933ecb53911d1c224da6a5432a6e9a0e42f36dd07c712fd870d0a0b
|
data/README.md
CHANGED
|
@@ -314,7 +314,7 @@ This repository also ships a clean-install app-driven smoke harness that validat
|
|
|
314
314
|
|
|
315
315
|
```sh
|
|
316
316
|
make smoke
|
|
317
|
-
make smoke-published VERSION=1.1.
|
|
317
|
+
make smoke-published VERSION=1.1.2
|
|
318
318
|
```
|
|
319
319
|
|
|
320
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.
|
data/lib/debugbundle/client.rb
CHANGED
|
@@ -41,9 +41,7 @@ module DebugBundle
|
|
|
41
41
|
class << self
|
|
42
42
|
attr_accessor :thread_exception_client
|
|
43
43
|
|
|
44
|
-
def dispatch_thread_exception(error)
|
|
45
|
-
thread_exception_client&.__send__(:capture_thread_exception, error)
|
|
46
|
-
end
|
|
44
|
+
def dispatch_thread_exception(error) = thread_exception_client&.__send__(:capture_thread_exception, error)
|
|
47
45
|
|
|
48
46
|
def install_thread_exception_hook!
|
|
49
47
|
THREAD_HOOK_MUTEX.synchronize do
|
|
@@ -128,18 +126,17 @@ module DebugBundle
|
|
|
128
126
|
}
|
|
129
127
|
|
|
130
128
|
causes = exception_causes(error)
|
|
131
|
-
payload['causes'] = causes unless causes.empty?
|
|
132
129
|
|
|
133
130
|
probe_data = probe_snapshot
|
|
134
131
|
payload['probe_data'] = probe_data unless probe_data.empty?
|
|
135
132
|
|
|
136
133
|
extra_context = merged_context.except('request', 'response', 'correlation')
|
|
137
|
-
|
|
134
|
+
extra_context['causes'] = causes unless causes.empty?
|
|
138
135
|
|
|
139
136
|
suppression_key = [payload['name'], payload['message'], payload['stack']].join(':')
|
|
140
137
|
return unless @suppression.should_capture(suppression_key, now: monotonic_now)
|
|
141
138
|
|
|
142
|
-
enqueue_event(base_event('backend_exception', payload,
|
|
139
|
+
enqueue_event(base_event('backend_exception', payload, extra_context))
|
|
143
140
|
end
|
|
144
141
|
|
|
145
142
|
def capture_error(error, context: nil, handled: true) = capture_exception(error, context: context, handled: handled)
|
|
@@ -181,8 +178,6 @@ module DebugBundle
|
|
|
181
178
|
'response_status' => response_status,
|
|
182
179
|
'duration_ms' => extract_duration_ms(merged_context, sanitized_response),
|
|
183
180
|
'route_template' => merged_context['route_template'],
|
|
184
|
-
'controller' => merged_context['controller'],
|
|
185
|
-
'action' => merged_context['action'],
|
|
186
181
|
'response_headers' => sanitized_response['headers'],
|
|
187
182
|
'response_body' => sanitized_response['body']
|
|
188
183
|
}
|
|
@@ -414,8 +409,8 @@ module DebugBundle
|
|
|
414
409
|
def request_payload(request)
|
|
415
410
|
source = object_to_hash(request)
|
|
416
411
|
{
|
|
417
|
-
'method' => source['method'],
|
|
418
|
-
'path' => source['path'],
|
|
412
|
+
'method' => source['method'] || 'UNKNOWN',
|
|
413
|
+
'path' => source['path'] || '/',
|
|
419
414
|
'query' => @redactor.redact_value(source['query'] || {}),
|
|
420
415
|
'headers' => sanitized_headers(source['headers'] || {}),
|
|
421
416
|
'body' => @redactor.redact_value(source['body'] || {})
|
|
@@ -494,7 +489,7 @@ module DebugBundle
|
|
|
494
489
|
end
|
|
495
490
|
|
|
496
491
|
def base_event(event_type, payload, context)
|
|
497
|
-
{
|
|
492
|
+
event = {
|
|
498
493
|
'schema_version' => SCHEMA_VERSION,
|
|
499
494
|
'event_id' => SecureRandom.uuid,
|
|
500
495
|
'event_type' => event_type,
|
|
@@ -511,6 +506,9 @@ module DebugBundle
|
|
|
511
506
|
'correlation' => correlation_payload(context),
|
|
512
507
|
'payload' => @redactor.redact_value(payload)
|
|
513
508
|
}
|
|
509
|
+
envelope_context = event_context(context)
|
|
510
|
+
event['context'] = envelope_context unless envelope_context.empty?
|
|
511
|
+
event
|
|
514
512
|
end
|
|
515
513
|
|
|
516
514
|
def service_name = config.service || DEFAULT_SERVICE_NAME
|
|
@@ -528,6 +526,18 @@ module DebugBundle
|
|
|
528
526
|
}
|
|
529
527
|
end
|
|
530
528
|
|
|
529
|
+
def event_context(context)
|
|
530
|
+
object_to_hash(context).except(
|
|
531
|
+
'request',
|
|
532
|
+
'response',
|
|
533
|
+
'correlation',
|
|
534
|
+
'request_id',
|
|
535
|
+
'trace_id',
|
|
536
|
+
'session_id',
|
|
537
|
+
'user_id_hash'
|
|
538
|
+
)
|
|
539
|
+
end
|
|
540
|
+
|
|
531
541
|
def object_to_hash(value)
|
|
532
542
|
case value
|
|
533
543
|
when Hash
|
|
@@ -11,6 +11,7 @@ module DebugBundle
|
|
|
11
11
|
frontend_breadcrumb
|
|
12
12
|
request_event
|
|
13
13
|
probe_event
|
|
14
|
+
analytics_event
|
|
14
15
|
].freeze
|
|
15
16
|
BROWSER_SDK_NAME = '@debugbundle/sdk-browser'
|
|
16
17
|
DEFAULT_MAX_BODY_BYTES = 262_144
|
|
@@ -192,20 +193,22 @@ module DebugBundle
|
|
|
192
193
|
'name' => @service || service['name'].to_s,
|
|
193
194
|
'environment' => @environment || service['environment'].to_s
|
|
194
195
|
},
|
|
195
|
-
'correlation' => sanitize_correlation(correlation),
|
|
196
|
+
'correlation' => sanitize_correlation(correlation, event_type),
|
|
196
197
|
'payload' => payload,
|
|
197
198
|
'project_token' => @project_token
|
|
198
199
|
}
|
|
199
200
|
end
|
|
200
201
|
|
|
201
|
-
def sanitize_correlation(value)
|
|
202
|
+
def sanitize_correlation(value, event_type)
|
|
202
203
|
correlation = value.is_a?(Hash) ? value : {}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
}
|
|
204
|
+
keys = if event_type == 'analytics_event'
|
|
205
|
+
%w[session_id visitor_id_hash user_id_hash trace_id deploy_id]
|
|
206
|
+
else
|
|
207
|
+
%w[request_id trace_id session_id user_id_hash]
|
|
208
|
+
end
|
|
209
|
+
keys.each_with_object({}) do |key, sanitized|
|
|
210
|
+
sanitized[key] = string_or_nil(correlation[key]) if correlation.key?(key)
|
|
211
|
+
end
|
|
209
212
|
end
|
|
210
213
|
|
|
211
214
|
def string_or_nil(value)
|
data/lib/debugbundle/version.rb
CHANGED
|
@@ -57,11 +57,16 @@
|
|
|
57
57
|
"event_id": { "type": "string", "format": "uuid" },
|
|
58
58
|
"event_type": { "type": "string", "minLength": 1 },
|
|
59
59
|
"project_token": { "type": "string", "minLength": 1 },
|
|
60
|
+
"project_id": { "type": ["string", "null"], "format": "uuid" },
|
|
60
61
|
"sdk_name": { "type": "string", "minLength": 1 },
|
|
61
62
|
"sdk_version": { "type": "string", "minLength": 1 },
|
|
62
63
|
"service": { "$ref": "#/$defs/service" },
|
|
63
64
|
"occurred_at": { "type": "string", "format": "date-time" },
|
|
64
65
|
"correlation": { "$ref": "#/$defs/correlation" },
|
|
66
|
+
"context": {
|
|
67
|
+
"type": "object",
|
|
68
|
+
"additionalProperties": true
|
|
69
|
+
},
|
|
65
70
|
"payload": {}
|
|
66
71
|
}
|
|
67
72
|
},
|
|
@@ -195,10 +195,14 @@ RSpec.describe DebugBundle::Rack::Middleware do
|
|
|
195
195
|
)
|
|
196
196
|
|
|
197
197
|
client.flush
|
|
198
|
-
|
|
198
|
+
event = transport_events.fetch(0).fetch(:events).fetch(0)
|
|
199
|
+
payload = event.fetch('payload')
|
|
200
|
+
context = event.fetch('context')
|
|
199
201
|
|
|
200
202
|
expect(payload).to include(
|
|
201
|
-
'route_template' => '/patients/:patient_id/checkouts'
|
|
203
|
+
'route_template' => '/patients/:patient_id/checkouts'
|
|
204
|
+
)
|
|
205
|
+
expect(context).to include(
|
|
202
206
|
'controller' => 'checkouts',
|
|
203
207
|
'action' => 'create'
|
|
204
208
|
)
|
data/spec/relay_spec.rb
CHANGED
|
@@ -57,6 +57,40 @@ RSpec.describe DebugBundle::Relay::Handler do
|
|
|
57
57
|
end
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
+
it 'preserves analytics correlation fields for analytics relay events' do
|
|
61
|
+
analytics_event = browser_event.merge(
|
|
62
|
+
'event_type' => 'analytics_event',
|
|
63
|
+
'correlation' => {
|
|
64
|
+
'session_id' => 'session-analytics',
|
|
65
|
+
'visitor_id_hash' => "sha256:#{'a' * 64}",
|
|
66
|
+
'user_id_hash' => nil,
|
|
67
|
+
'trace_id' => 'trace-analytics',
|
|
68
|
+
'deploy_id' => 'deploy-analytics'
|
|
69
|
+
},
|
|
70
|
+
'payload' => { 'kind' => 'page_view', 'privacy' => { 'mode' => 'standard', 'consent_granted' => true } }
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
Dir.mktmpdir do |directory|
|
|
74
|
+
handler = described_class.new(project_mode: :local_only, project_token: 'dbundle_proj_server',
|
|
75
|
+
local_events_dir: directory)
|
|
76
|
+
response = handler.handle(
|
|
77
|
+
method: 'POST',
|
|
78
|
+
headers: {
|
|
79
|
+
'host' => 'app.example.com',
|
|
80
|
+
'origin' => 'https://app.example.com',
|
|
81
|
+
'content-type' => 'application/json'
|
|
82
|
+
},
|
|
83
|
+
body: JSON.generate('batch' => [analytics_event]),
|
|
84
|
+
ip_address: '127.0.0.2'
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
expect(response.status).to eq(202)
|
|
88
|
+
file_name = Dir.children(directory).find { |entry| entry.end_with?('.events.json') }
|
|
89
|
+
event = JSON.parse(File.read(File.join(directory, file_name))).fetch(0)
|
|
90
|
+
expect(event.fetch('correlation')).to eq(analytics_event.fetch('correlation'))
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
60
94
|
it 'rejects wrong origins' do
|
|
61
95
|
handler = described_class.new(project_mode: :local_only, project_token: 'dbundle_proj_server')
|
|
62
96
|
response = handler.handle(
|
|
@@ -50,7 +50,7 @@ if defined?(Sidekiq)
|
|
|
50
50
|
|
|
51
51
|
expect(event.fetch('event_type')).to eq('backend_exception')
|
|
52
52
|
expect(event.fetch('correlation')).to include('trace_id' => 'trace-chain-1')
|
|
53
|
-
expect(event.fetch('
|
|
53
|
+
expect(event.fetch('context').fetch('job')).to include(
|
|
54
54
|
'class' => 'CheckoutWorker',
|
|
55
55
|
'queue' => 'critical',
|
|
56
56
|
'jid' => 'jid-chain-1'
|
|
@@ -40,7 +40,7 @@ RSpec.describe DebugBundle::Sidekiq::ServerMiddleware do
|
|
|
40
40
|
|
|
41
41
|
expect(event.fetch('event_type')).to eq('backend_exception')
|
|
42
42
|
expect(event.fetch('correlation')).to include('trace_id' => 'trace-job-1')
|
|
43
|
-
expect(event.fetch('
|
|
43
|
+
expect(event.fetch('context').fetch('job')).to include(
|
|
44
44
|
'class' => 'CheckoutWorker',
|
|
45
45
|
'queue' => 'critical',
|
|
46
46
|
'jid' => 'jid-1',
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: debugbundle
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.1.
|
|
4
|
+
version: 1.1.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- DebugBundle
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-
|
|
10
|
+
date: 2026-07-16 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: base64
|