debugbundle 1.4.0 → 1.4.1
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 +6 -0
- data/README.md +5 -1
- data/lib/debugbundle/logging.rb +30 -16
- data/lib/debugbundle/version.rb +1 -1
- data/spec/logger_integration_spec.rb +84 -0
- 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: cae31875b7ffe9d2005b62f2107fb4810061ec4362e7bf48c4dd521e43d415f6
|
|
4
|
+
data.tar.gz: 2e005a0112e3197aa9b19fed791b71cea7dbf1eefcfc6edebc5a2ce7c764f3d0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e2f99cad665ebbcd10ea0965ed97f16c1930567344848ead03aa2ff9d1ac297bf9260ba2915a72454d6843e2805e41ebc648525ab0250077c29ea3f8897a291a
|
|
7
|
+
data.tar.gz: 25a171fc0e6cd96c74a8cc7a85fde1dbfe52837d4c46cef69926e2b4c736df49912ffce294613b3c7738d4f6f7b8cdc2f4121f6898a1563c4e7056f237d52a55
|
data/Makefile
CHANGED
|
@@ -15,6 +15,12 @@ BUNDLE_ENV = BUNDLE_GEMFILE="$(BUNDLE_GEMFILE)"
|
|
|
15
15
|
.PHONY: bundle-install test lint build shell compat-rack compat-rails compat-sidekiq compat
|
|
16
16
|
.PHONY: smoke
|
|
17
17
|
.PHONY: smoke-published
|
|
18
|
+
.PHONY: test-focused check-docker
|
|
19
|
+
check-docker:
|
|
20
|
+
docker run --rm -v "$(CURDIR):$(WORKDIR)" -w "$(WORKDIR)" $(RUBY_IMAGE) sh -lc 'BUNDLE_PATH=vendor/bundle bundle exec rubocop && BUNDLE_PATH=vendor/bundle bundle exec rspec && gem build debugbundle.gemspec'
|
|
21
|
+
|
|
22
|
+
test-focused:
|
|
23
|
+
docker run --rm -v "$(CURDIR):$(WORKDIR)" -w "$(WORKDIR)" $(RUBY_IMAGE) sh -lc 'BUNDLE_PATH=vendor/bundle SIMPLECOV_MINIMUM_COVERAGE=0 bundle exec rspec $(TEST_FILES)'
|
|
18
24
|
|
|
19
25
|
bundle-install:
|
|
20
26
|
$(DOCKER_RUN) sh -lc "$(BUNDLE_ENV) bundle config set path vendor/bundle && $(BUNDLE_ENV) bundle install"
|
data/README.md
CHANGED
|
@@ -4,6 +4,10 @@ Ruby SDK for DebugBundle.
|
|
|
4
4
|
|
|
5
5
|
Use this gem to capture Ruby backend exceptions, request metadata, structured logs, runtime context, probe data, and browser relay traffic. It supports a singleton facade plus instance clients for Rack, Rails, Sidekiq, and explicit Ruby instrumentation.
|
|
6
6
|
|
|
7
|
+
## Automatic capture and application filtering
|
|
8
|
+
|
|
9
|
+
`capture_logger(logger)` respects the logger level, Rails silence and disabled output. Lazy message blocks are evaluated by the native logger: zero times when suppressed and once when accepted. Native return values and application block exceptions are preserved. DebugBundle applies its own configured minimum capture level after the logger accepts a message.
|
|
10
|
+
|
|
7
11
|
## Installation
|
|
8
12
|
|
|
9
13
|
```ruby
|
|
@@ -314,7 +318,7 @@ This repository also ships a clean-install app-driven smoke harness that validat
|
|
|
314
318
|
|
|
315
319
|
```sh
|
|
316
320
|
make smoke
|
|
317
|
-
make smoke-published VERSION=1.4.
|
|
321
|
+
make smoke-published VERSION=1.4.1
|
|
318
322
|
```
|
|
319
323
|
|
|
320
324
|
`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/logging.rb
CHANGED
|
@@ -16,24 +16,23 @@ module DebugBundle
|
|
|
16
16
|
|
|
17
17
|
def self.install_stdlib_logger(logger, client:)
|
|
18
18
|
interceptor = Module.new do
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
resolved_message = progname if resolved_message.nil?
|
|
19
|
+
%i[add log].each do |method_name|
|
|
20
|
+
define_method(method_name) do |severity, message = nil, progname = nil, &block|
|
|
21
|
+
normalized_severity = severity || ::Logger::UNKNOWN
|
|
22
|
+
# Match Logger's early return, including Rails' thread-local level.
|
|
23
|
+
disabled = normalized_severity < level || (is_a?(::Logger) && instance_variable_get(:@logdev).nil?)
|
|
24
|
+
next super(severity, message, progname, &block) if disabled || Thread.current[RECURSION_GUARD_KEY]
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
resolved_message = message
|
|
27
|
+
resolved_message = progname.nil? ? self.progname : progname if message.nil?
|
|
28
|
+
result = if message.nil? && block
|
|
29
|
+
super(severity, message, progname) { resolved_message = block.call }
|
|
30
|
+
else
|
|
31
|
+
super(severity, message, progname)
|
|
32
|
+
end
|
|
33
|
+
DebugBundle::Logging.capture_stdlib(client, resolved_message, normalized_severity, self.progname)
|
|
34
|
+
result
|
|
32
35
|
end
|
|
33
|
-
|
|
34
|
-
super(severity, message, progname, &block)
|
|
35
|
-
ensure
|
|
36
|
-
Thread.current[RECURSION_GUARD_KEY] = was_capturing
|
|
37
36
|
end
|
|
38
37
|
end
|
|
39
38
|
|
|
@@ -41,6 +40,21 @@ module DebugBundle
|
|
|
41
40
|
interceptor
|
|
42
41
|
end
|
|
43
42
|
|
|
43
|
+
def self.capture_stdlib(client, message, severity, progname)
|
|
44
|
+
was_capturing = Thread.current[RECURSION_GUARD_KEY]
|
|
45
|
+
Thread.current[RECURSION_GUARD_KEY] = true
|
|
46
|
+
client.capture_log(
|
|
47
|
+
message.to_s,
|
|
48
|
+
level: LOGGER_LEVEL_NAMES.fetch(severity, :warning),
|
|
49
|
+
context: { logger_name: progname }
|
|
50
|
+
)
|
|
51
|
+
rescue StandardError
|
|
52
|
+
# SDK failures must not change the result of the application's logger.
|
|
53
|
+
nil
|
|
54
|
+
ensure
|
|
55
|
+
Thread.current[RECURSION_GUARD_KEY] = was_capturing
|
|
56
|
+
end
|
|
57
|
+
|
|
44
58
|
def self.install_semantic_logger(client:)
|
|
45
59
|
return nil unless defined?(::SemanticLogger)
|
|
46
60
|
return nil unless ::SemanticLogger.respond_to?(:add_appender)
|
data/lib/debugbundle/version.rb
CHANGED
|
@@ -4,6 +4,90 @@ require 'spec_helper'
|
|
|
4
4
|
require 'stringio'
|
|
5
5
|
|
|
6
6
|
RSpec.describe 'stdlib logger integration' do
|
|
7
|
+
def instrument_logger(logger, &capture)
|
|
8
|
+
client = Object.new
|
|
9
|
+
client.define_singleton_method(:capture_log, &capture)
|
|
10
|
+
DebugBundle::Logging.install_stdlib_logger(logger, client: client)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'respects the current logger level without evaluating suppressed blocks' do
|
|
14
|
+
output = StringIO.new
|
|
15
|
+
logger = Logger.new(output, level: Logger::ERROR)
|
|
16
|
+
captured = []
|
|
17
|
+
instrument_logger(logger) { |message, **_options| captured << message }
|
|
18
|
+
evaluations = 0
|
|
19
|
+
result = logger.warn do
|
|
20
|
+
evaluations += 1
|
|
21
|
+
'suppressed'
|
|
22
|
+
end
|
|
23
|
+
expect(result).to be(true)
|
|
24
|
+
expect(captured).to be_empty
|
|
25
|
+
expect(evaluations).to eq(0)
|
|
26
|
+
logger.level = Logger::WARN
|
|
27
|
+
logger.warn do
|
|
28
|
+
evaluations += 1
|
|
29
|
+
'accepted'
|
|
30
|
+
end
|
|
31
|
+
expect(evaluations).to eq(1)
|
|
32
|
+
expect(captured).to eq(['accepted'])
|
|
33
|
+
expect(output.string).to include('accepted')
|
|
34
|
+
expect(output.string).not_to include('suppressed')
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'preserves logger message and progname semantics and evaluates accepted blocks once' do
|
|
38
|
+
output = StringIO.new
|
|
39
|
+
logger = Logger.new(output, progname: 'default-name')
|
|
40
|
+
captured = []
|
|
41
|
+
instrument_logger(logger) { |message, **_options| captured << message }
|
|
42
|
+
logger.add(Logger::WARN)
|
|
43
|
+
logger.add(Logger::WARN, nil, 'message-as-progname')
|
|
44
|
+
logger.add(nil, 'unknown-severity')
|
|
45
|
+
evaluations = 0
|
|
46
|
+
logger.warn('explicit-name') do
|
|
47
|
+
evaluations += 1
|
|
48
|
+
"block-#{evaluations}"
|
|
49
|
+
end
|
|
50
|
+
expect(captured).to eq(%w[default-name message-as-progname unknown-severity block-1])
|
|
51
|
+
expect(evaluations).to eq(1)
|
|
52
|
+
expect(output.string).to include('explicit-name: block-1')
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it 'does not evaluate blocks or capture when the logger has no output device' do
|
|
56
|
+
logger = Logger.new(nil)
|
|
57
|
+
instrument_logger(logger) { raise 'should not capture' }
|
|
58
|
+
expect(logger.warn { raise 'should not evaluate' }).to be(true)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it 'captures the log alias and preserves false messages and Rails silence' do
|
|
62
|
+
require 'active_support'
|
|
63
|
+
require 'active_support/logger'
|
|
64
|
+
output = StringIO.new
|
|
65
|
+
logger = ActiveSupport::Logger.new(output)
|
|
66
|
+
captured = []
|
|
67
|
+
instrument_logger(logger) { |message, **_options| captured << message }
|
|
68
|
+
logger.silence(Logger::ERROR) { logger.warn { raise 'suppressed block' } }
|
|
69
|
+
logger.log(Logger::WARN, false)
|
|
70
|
+
expect(captured).to eq(['false'])
|
|
71
|
+
expect(output.string).to include('false')
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it 'isolates capture failures and recursion while preserving application logging failures' do
|
|
75
|
+
output = StringIO.new
|
|
76
|
+
logger = Logger.new(output)
|
|
77
|
+
calls = 0
|
|
78
|
+
instrument_logger(logger) do |_message, **_options|
|
|
79
|
+
calls += 1
|
|
80
|
+
logger.warn('nested')
|
|
81
|
+
raise 'capture failed'
|
|
82
|
+
end
|
|
83
|
+
expect { logger.warn('outer') }.not_to raise_error
|
|
84
|
+
expect(calls).to eq(1)
|
|
85
|
+
expect(output.string).to include('outer', 'nested')
|
|
86
|
+
expect { logger.warn { raise 'application failure' } }.to raise_error('application failure')
|
|
87
|
+
expect { logger.warn('after failure') }.not_to raise_error
|
|
88
|
+
expect(calls).to eq(2)
|
|
89
|
+
end
|
|
90
|
+
|
|
7
91
|
it 'captures log events without changing logger output' do
|
|
8
92
|
transport_events = []
|
|
9
93
|
transport = Class.new do
|
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.4.
|
|
4
|
+
version: 1.4.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- DebugBundle
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-09-
|
|
10
|
+
date: 2026-09-15 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: base64
|