brainzlab 0.1.2 → 0.1.4
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/LICENSE +6 -21
- data/README.md +16 -2
- data/lib/brainzlab/beacon/client.rb +38 -40
- data/lib/brainzlab/beacon/provisioner.rb +1 -1
- data/lib/brainzlab/beacon.rb +15 -15
- data/lib/brainzlab/configuration.rb +112 -90
- data/lib/brainzlab/context.rb +2 -3
- data/lib/brainzlab/cortex/client.rb +29 -31
- data/lib/brainzlab/cortex/provisioner.rb +1 -1
- data/lib/brainzlab/cortex.rb +7 -11
- data/lib/brainzlab/dendrite/client.rb +42 -44
- data/lib/brainzlab/dendrite/provisioner.rb +1 -1
- data/lib/brainzlab/dendrite.rb +4 -4
- data/lib/brainzlab/devtools/data/collector.rb +22 -22
- data/lib/brainzlab/devtools/middleware/asset_server.rb +14 -14
- data/lib/brainzlab/devtools/middleware/database_handler.rb +52 -55
- data/lib/brainzlab/devtools/middleware/debug_panel.rb +19 -19
- data/lib/brainzlab/devtools/middleware/error_page.rb +45 -44
- data/lib/brainzlab/devtools/renderers/debug_panel_renderer.rb +39 -35
- data/lib/brainzlab/devtools/renderers/error_page_renderer.rb +13 -9
- data/lib/brainzlab/devtools.rb +11 -11
- data/lib/brainzlab/flux/buffer.rb +3 -3
- data/lib/brainzlab/flux/client.rb +14 -16
- data/lib/brainzlab/flux/provisioner.rb +13 -13
- data/lib/brainzlab/flux.rb +8 -8
- data/lib/brainzlab/instrumentation/action_cable.rb +351 -0
- data/lib/brainzlab/instrumentation/action_controller.rb +649 -0
- data/lib/brainzlab/instrumentation/action_dispatch.rb +259 -0
- data/lib/brainzlab/instrumentation/action_mailbox.rb +197 -0
- data/lib/brainzlab/instrumentation/action_mailer.rb +14 -13
- data/lib/brainzlab/instrumentation/action_view.rb +380 -0
- data/lib/brainzlab/instrumentation/active_job.rb +569 -0
- data/lib/brainzlab/instrumentation/active_record.rb +467 -36
- data/lib/brainzlab/instrumentation/active_storage.rb +541 -0
- data/lib/brainzlab/instrumentation/active_support_cache.rb +700 -0
- data/lib/brainzlab/instrumentation/aws.rb +43 -39
- data/lib/brainzlab/instrumentation/dalli.rb +20 -20
- data/lib/brainzlab/instrumentation/delayed_job.rb +27 -29
- data/lib/brainzlab/instrumentation/elasticsearch.rb +23 -24
- data/lib/brainzlab/instrumentation/excon.rb +27 -27
- data/lib/brainzlab/instrumentation/faraday.rb +3 -4
- data/lib/brainzlab/instrumentation/good_job.rb +28 -28
- data/lib/brainzlab/instrumentation/grape.rb +24 -24
- data/lib/brainzlab/instrumentation/graphql.rb +24 -23
- data/lib/brainzlab/instrumentation/httparty.rb +13 -14
- data/lib/brainzlab/instrumentation/mongodb.rb +7 -7
- data/lib/brainzlab/instrumentation/net_http.rb +6 -6
- data/lib/brainzlab/instrumentation/rails_deprecation.rb +139 -0
- data/lib/brainzlab/instrumentation/railties.rb +134 -0
- data/lib/brainzlab/instrumentation/redis.rb +14 -21
- data/lib/brainzlab/instrumentation/resque.rb +23 -24
- data/lib/brainzlab/instrumentation/sidekiq.rb +29 -28
- data/lib/brainzlab/instrumentation/solid_queue.rb +37 -41
- data/lib/brainzlab/instrumentation/stripe.rb +36 -37
- data/lib/brainzlab/instrumentation/typhoeus.rb +19 -17
- data/lib/brainzlab/instrumentation.rb +111 -21
- data/lib/brainzlab/nerve/client.rb +38 -40
- data/lib/brainzlab/nerve/provisioner.rb +1 -1
- data/lib/brainzlab/nerve.rb +6 -6
- data/lib/brainzlab/pulse/client.rb +15 -11
- data/lib/brainzlab/pulse/instrumentation.rb +61 -57
- data/lib/brainzlab/pulse/propagation.rb +28 -28
- data/lib/brainzlab/pulse/provisioner.rb +12 -12
- data/lib/brainzlab/pulse/tracer.rb +3 -3
- data/lib/brainzlab/pulse.rb +13 -13
- data/lib/brainzlab/rails/log_formatter.rb +127 -121
- data/lib/brainzlab/rails/log_subscriber.rb +70 -76
- data/lib/brainzlab/rails/railtie.rb +66 -89
- data/lib/brainzlab/recall/buffer.rb +1 -1
- data/lib/brainzlab/recall/client.rb +14 -10
- data/lib/brainzlab/recall/logger.rb +16 -18
- data/lib/brainzlab/recall/provisioner.rb +16 -16
- data/lib/brainzlab/recall.rb +11 -13
- data/lib/brainzlab/reflex/breadcrumbs.rb +2 -2
- data/lib/brainzlab/reflex/client.rb +14 -10
- data/lib/brainzlab/reflex/provisioner.rb +12 -12
- data/lib/brainzlab/reflex.rb +29 -29
- data/lib/brainzlab/sentinel/client.rb +40 -42
- data/lib/brainzlab/sentinel/provisioner.rb +1 -1
- data/lib/brainzlab/sentinel.rb +5 -5
- data/lib/brainzlab/signal/client.rb +12 -14
- data/lib/brainzlab/signal/provisioner.rb +12 -12
- data/lib/brainzlab/signal.rb +7 -7
- data/lib/brainzlab/synapse/client.rb +42 -44
- data/lib/brainzlab/synapse/provisioner.rb +1 -1
- data/lib/brainzlab/synapse.rb +6 -6
- data/lib/brainzlab/utilities/circuit_breaker.rb +37 -41
- data/lib/brainzlab/utilities/health_check.rb +53 -55
- data/lib/brainzlab/utilities/log_formatter.rb +38 -40
- data/lib/brainzlab/utilities/rate_limiter.rb +5 -5
- data/lib/brainzlab/utilities.rb +4 -4
- data/lib/brainzlab/vault/cache.rb +1 -1
- data/lib/brainzlab/vault/client.rb +39 -41
- data/lib/brainzlab/vault/provisioner.rb +1 -1
- data/lib/brainzlab/vault.rb +19 -25
- data/lib/brainzlab/version.rb +1 -1
- data/lib/brainzlab/vision/client.rb +20 -20
- data/lib/brainzlab/vision/provisioner.rb +21 -21
- data/lib/brainzlab/vision.rb +17 -19
- data/lib/brainzlab-sdk.rb +1 -1
- data/lib/brainzlab.rb +22 -24
- data/lib/generators/brainzlab/install/install_generator.rb +29 -27
- metadata +11 -1
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BrainzLab
|
|
4
|
+
module Instrumentation
|
|
5
|
+
class RailsDeprecation
|
|
6
|
+
class << self
|
|
7
|
+
def install!
|
|
8
|
+
return unless defined?(::Rails)
|
|
9
|
+
return if @installed
|
|
10
|
+
|
|
11
|
+
install_deprecation_subscriber!
|
|
12
|
+
|
|
13
|
+
@installed = true
|
|
14
|
+
BrainzLab.debug_log('Rails deprecation instrumentation installed')
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def installed?
|
|
18
|
+
@installed == true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
# ============================================
|
|
24
|
+
# deprecation.rails
|
|
25
|
+
# Fired when a deprecated Rails API is used
|
|
26
|
+
# ============================================
|
|
27
|
+
def install_deprecation_subscriber!
|
|
28
|
+
ActiveSupport::Notifications.subscribe('deprecation.rails') do |*args|
|
|
29
|
+
event = ActiveSupport::Notifications::Event.new(*args)
|
|
30
|
+
handle_deprecation(event)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def handle_deprecation(event)
|
|
35
|
+
payload = event.payload
|
|
36
|
+
|
|
37
|
+
message = payload[:message]
|
|
38
|
+
callstack = payload[:callstack]
|
|
39
|
+
gem_name = payload[:gem_name]
|
|
40
|
+
deprecation_horizon = payload[:deprecation_horizon]
|
|
41
|
+
|
|
42
|
+
# Extract relevant caller info
|
|
43
|
+
caller_info = extract_caller_info(callstack)
|
|
44
|
+
|
|
45
|
+
# Record breadcrumb with warning level
|
|
46
|
+
if BrainzLab.configuration.reflex_effectively_enabled?
|
|
47
|
+
BrainzLab::Reflex.add_breadcrumb(
|
|
48
|
+
"Deprecation: #{truncate_message(message)}",
|
|
49
|
+
category: 'rails.deprecation',
|
|
50
|
+
level: :warning,
|
|
51
|
+
data: {
|
|
52
|
+
message: truncate_message(message, 500),
|
|
53
|
+
gem_name: gem_name,
|
|
54
|
+
deprecation_horizon: deprecation_horizon,
|
|
55
|
+
caller: caller_info
|
|
56
|
+
}.compact
|
|
57
|
+
)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Log to Recall for tracking
|
|
61
|
+
if BrainzLab.configuration.recall_effectively_enabled?
|
|
62
|
+
BrainzLab::Recall.warn(
|
|
63
|
+
"Rails deprecation warning",
|
|
64
|
+
message: truncate_message(message, 500),
|
|
65
|
+
gem_name: gem_name,
|
|
66
|
+
deprecation_horizon: deprecation_horizon,
|
|
67
|
+
caller: caller_info,
|
|
68
|
+
callstack: truncate_callstack(callstack)
|
|
69
|
+
)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Track deprecation count in Pulse metrics
|
|
73
|
+
record_deprecation_metric(gem_name, deprecation_horizon)
|
|
74
|
+
rescue StandardError => e
|
|
75
|
+
BrainzLab.debug_log("Rails deprecation instrumentation failed: #{e.message}")
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# ============================================
|
|
79
|
+
# Helper Methods
|
|
80
|
+
# ============================================
|
|
81
|
+
def extract_caller_info(callstack)
|
|
82
|
+
return nil unless callstack.is_a?(Array) && callstack.any?
|
|
83
|
+
|
|
84
|
+
# Find the first non-Rails, non-gem caller
|
|
85
|
+
app_caller = callstack.find do |line|
|
|
86
|
+
line_str = line.to_s
|
|
87
|
+
!line_str.include?('/gems/') &&
|
|
88
|
+
!line_str.include?('/ruby/') &&
|
|
89
|
+
!line_str.include?('/bundler/')
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
(app_caller || callstack.first).to_s
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def truncate_callstack(callstack, max_lines = 5)
|
|
96
|
+
return nil unless callstack.is_a?(Array)
|
|
97
|
+
|
|
98
|
+
callstack.first(max_lines).map(&:to_s)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def truncate_message(message, max_length = 200)
|
|
102
|
+
return 'unknown' unless message
|
|
103
|
+
|
|
104
|
+
msg_str = message.to_s
|
|
105
|
+
if msg_str.length > max_length
|
|
106
|
+
"#{msg_str[0, max_length - 3]}..."
|
|
107
|
+
else
|
|
108
|
+
msg_str
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def record_deprecation_metric(gem_name, horizon)
|
|
113
|
+
return unless BrainzLab.configuration.pulse_effectively_enabled?
|
|
114
|
+
|
|
115
|
+
# If Pulse has a counter/metric API, use it here
|
|
116
|
+
# For now, we just add a span to track it
|
|
117
|
+
tracer = BrainzLab::Pulse.tracer
|
|
118
|
+
return unless tracer.current_trace
|
|
119
|
+
|
|
120
|
+
span_data = {
|
|
121
|
+
span_id: SecureRandom.uuid,
|
|
122
|
+
name: 'rails.deprecation',
|
|
123
|
+
kind: 'internal',
|
|
124
|
+
started_at: Time.now,
|
|
125
|
+
ended_at: Time.now,
|
|
126
|
+
duration_ms: 0,
|
|
127
|
+
error: false,
|
|
128
|
+
data: {
|
|
129
|
+
'deprecation.gem_name' => gem_name,
|
|
130
|
+
'deprecation.horizon' => horizon
|
|
131
|
+
}.compact
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
tracer.current_spans << span_data
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BrainzLab
|
|
4
|
+
module Instrumentation
|
|
5
|
+
class Railties
|
|
6
|
+
# Thresholds for slow initializers (in milliseconds)
|
|
7
|
+
SLOW_INITIALIZER_THRESHOLD = 100 # 100ms
|
|
8
|
+
VERY_SLOW_INITIALIZER_THRESHOLD = 500 # 500ms
|
|
9
|
+
|
|
10
|
+
class << self
|
|
11
|
+
def install!
|
|
12
|
+
return unless defined?(::Rails)
|
|
13
|
+
return if @installed
|
|
14
|
+
|
|
15
|
+
install_load_config_initializer_subscriber!
|
|
16
|
+
|
|
17
|
+
@installed = true
|
|
18
|
+
BrainzLab.debug_log('Railties instrumentation installed')
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def installed?
|
|
22
|
+
@installed == true
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
# ============================================
|
|
28
|
+
# load_config_initializer.railties
|
|
29
|
+
# Fired when each config initializer is loaded
|
|
30
|
+
# ============================================
|
|
31
|
+
def install_load_config_initializer_subscriber!
|
|
32
|
+
ActiveSupport::Notifications.subscribe('load_config_initializer.railties') do |*args|
|
|
33
|
+
event = ActiveSupport::Notifications::Event.new(*args)
|
|
34
|
+
handle_load_config_initializer(event)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def handle_load_config_initializer(event)
|
|
39
|
+
payload = event.payload
|
|
40
|
+
duration = event.duration.round(2)
|
|
41
|
+
|
|
42
|
+
initializer = payload[:initializer]
|
|
43
|
+
|
|
44
|
+
# Extract just the filename for cleaner display
|
|
45
|
+
initializer_name = extract_initializer_name(initializer)
|
|
46
|
+
|
|
47
|
+
# Determine level based on duration
|
|
48
|
+
level = case duration
|
|
49
|
+
when 0...SLOW_INITIALIZER_THRESHOLD then :info
|
|
50
|
+
when SLOW_INITIALIZER_THRESHOLD...VERY_SLOW_INITIALIZER_THRESHOLD then :warning
|
|
51
|
+
else :error
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Record breadcrumb (only for slow initializers to reduce noise during boot)
|
|
55
|
+
if duration >= 10 && BrainzLab.configuration.reflex_effectively_enabled?
|
|
56
|
+
BrainzLab::Reflex.add_breadcrumb(
|
|
57
|
+
"Initializer loaded: #{initializer_name} (#{duration}ms)",
|
|
58
|
+
category: 'rails.initializer',
|
|
59
|
+
level: level,
|
|
60
|
+
data: {
|
|
61
|
+
initializer: initializer_name,
|
|
62
|
+
path: initializer,
|
|
63
|
+
duration_ms: duration
|
|
64
|
+
}.compact
|
|
65
|
+
)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Add Pulse span for tracking boot time
|
|
69
|
+
record_initializer_span(event, initializer_name, initializer, duration)
|
|
70
|
+
|
|
71
|
+
# Log slow initializers
|
|
72
|
+
log_slow_initializer(initializer_name, initializer, duration) if duration >= SLOW_INITIALIZER_THRESHOLD
|
|
73
|
+
rescue StandardError => e
|
|
74
|
+
BrainzLab.debug_log("Railties load_config_initializer instrumentation failed: #{e.message}")
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# ============================================
|
|
78
|
+
# Span Recording
|
|
79
|
+
# ============================================
|
|
80
|
+
def record_initializer_span(event, name, path, duration)
|
|
81
|
+
return unless BrainzLab.configuration.pulse_effectively_enabled?
|
|
82
|
+
|
|
83
|
+
tracer = BrainzLab::Pulse.tracer
|
|
84
|
+
return unless tracer.current_trace
|
|
85
|
+
|
|
86
|
+
span_data = {
|
|
87
|
+
span_id: SecureRandom.uuid,
|
|
88
|
+
name: "rails.initializer.#{name}",
|
|
89
|
+
kind: 'internal',
|
|
90
|
+
started_at: event.time,
|
|
91
|
+
ended_at: event.end,
|
|
92
|
+
duration_ms: duration,
|
|
93
|
+
error: false,
|
|
94
|
+
data: {
|
|
95
|
+
'rails.initializer.name' => name,
|
|
96
|
+
'rails.initializer.path' => path
|
|
97
|
+
}.compact
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
tracer.current_spans << span_data
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# ============================================
|
|
104
|
+
# Logging
|
|
105
|
+
# ============================================
|
|
106
|
+
def log_slow_initializer(name, path, duration)
|
|
107
|
+
return unless BrainzLab.configuration.recall_effectively_enabled?
|
|
108
|
+
|
|
109
|
+
level = duration >= VERY_SLOW_INITIALIZER_THRESHOLD ? :error : :warn
|
|
110
|
+
|
|
111
|
+
BrainzLab::Recall.send(
|
|
112
|
+
level,
|
|
113
|
+
"Slow initializer: #{name} (#{duration}ms)",
|
|
114
|
+
initializer: name,
|
|
115
|
+
path: path,
|
|
116
|
+
duration_ms: duration,
|
|
117
|
+
threshold_exceeded: duration >= VERY_SLOW_INITIALIZER_THRESHOLD ? 'critical' : 'warning'
|
|
118
|
+
)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# ============================================
|
|
122
|
+
# Helper Methods
|
|
123
|
+
# ============================================
|
|
124
|
+
def extract_initializer_name(path)
|
|
125
|
+
return 'unknown' unless path
|
|
126
|
+
|
|
127
|
+
# Extract filename without extension from path
|
|
128
|
+
# e.g., "/app/config/initializers/devise.rb" -> "devise"
|
|
129
|
+
File.basename(path.to_s, '.*')
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
@@ -18,7 +18,7 @@ module BrainzLab
|
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
@installed = true
|
|
21
|
-
BrainzLab.debug_log(
|
|
21
|
+
BrainzLab.debug_log('Redis instrumentation installed')
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
def installed?
|
|
@@ -32,7 +32,7 @@ module BrainzLab
|
|
|
32
32
|
private
|
|
33
33
|
|
|
34
34
|
def redis_5_or_newer?
|
|
35
|
-
defined?(::Redis::VERSION) && Gem::Version.new(::Redis::VERSION) >= Gem::Version.new(
|
|
35
|
+
defined?(::Redis::VERSION) && Gem::Version.new(::Redis::VERSION) >= Gem::Version.new('5.0')
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
def install_middleware!
|
|
@@ -50,10 +50,6 @@ module BrainzLab
|
|
|
50
50
|
|
|
51
51
|
# Middleware for Redis 5+ (RedisClient)
|
|
52
52
|
module Middleware
|
|
53
|
-
def connect(redis_config)
|
|
54
|
-
super
|
|
55
|
-
end
|
|
56
|
-
|
|
57
53
|
def call(command, redis_config)
|
|
58
54
|
return super unless should_track?
|
|
59
55
|
|
|
@@ -78,10 +74,10 @@ module BrainzLab
|
|
|
78
74
|
ignore.map(&:downcase).include?(cmd_name)
|
|
79
75
|
end
|
|
80
76
|
|
|
81
|
-
def track_command(command
|
|
77
|
+
def track_command(command)
|
|
82
78
|
return yield if should_skip_command?(command)
|
|
79
|
+
|
|
83
80
|
started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
84
|
-
error_info = nil
|
|
85
81
|
|
|
86
82
|
begin
|
|
87
83
|
result = yield
|
|
@@ -94,9 +90,8 @@ module BrainzLab
|
|
|
94
90
|
end
|
|
95
91
|
end
|
|
96
92
|
|
|
97
|
-
def track_pipeline(commands
|
|
93
|
+
def track_pipeline(commands)
|
|
98
94
|
started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
99
|
-
error_info = nil
|
|
100
95
|
|
|
101
96
|
begin
|
|
102
97
|
result = yield
|
|
@@ -119,7 +114,7 @@ module BrainzLab
|
|
|
119
114
|
if BrainzLab.configuration.reflex_enabled
|
|
120
115
|
BrainzLab::Reflex.add_breadcrumb(
|
|
121
116
|
"Redis #{cmd_name}",
|
|
122
|
-
category:
|
|
117
|
+
category: 'redis',
|
|
123
118
|
level: level,
|
|
124
119
|
data: {
|
|
125
120
|
command: cmd_name,
|
|
@@ -138,14 +133,14 @@ module BrainzLab
|
|
|
138
133
|
|
|
139
134
|
def record_pipeline(commands, started_at, error = nil)
|
|
140
135
|
duration_ms = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - started_at) * 1000).round(2)
|
|
141
|
-
cmd_names = commands.map { |c| c.first.to_s.upcase }.uniq.join(
|
|
136
|
+
cmd_names = commands.map { |c| c.first.to_s.upcase }.uniq.join(', ')
|
|
142
137
|
level = error ? :error : :info
|
|
143
138
|
|
|
144
139
|
# Add breadcrumb for Reflex
|
|
145
140
|
if BrainzLab.configuration.reflex_enabled
|
|
146
141
|
BrainzLab::Reflex.add_breadcrumb(
|
|
147
142
|
"Redis PIPELINE (#{commands.size} commands)",
|
|
148
|
-
category:
|
|
143
|
+
category: 'redis',
|
|
149
144
|
level: level,
|
|
150
145
|
data: {
|
|
151
146
|
commands: cmd_names,
|
|
@@ -157,7 +152,7 @@ module BrainzLab
|
|
|
157
152
|
end
|
|
158
153
|
|
|
159
154
|
# Record span for Pulse APM
|
|
160
|
-
record_pulse_span(
|
|
155
|
+
record_pulse_span('PIPELINE', nil, duration_ms, error, commands.size)
|
|
161
156
|
rescue StandardError => e
|
|
162
157
|
BrainzLab.debug_log("Redis instrumentation error: #{e.message}")
|
|
163
158
|
end
|
|
@@ -169,7 +164,7 @@ module BrainzLab
|
|
|
169
164
|
span = {
|
|
170
165
|
span_id: SecureRandom.uuid,
|
|
171
166
|
name: "Redis #{command}",
|
|
172
|
-
kind:
|
|
167
|
+
kind: 'redis',
|
|
173
168
|
started_at: Time.now.utc - (duration_ms / 1000.0),
|
|
174
169
|
ended_at: Time.now.utc,
|
|
175
170
|
duration_ms: duration_ms,
|
|
@@ -210,7 +205,6 @@ module BrainzLab
|
|
|
210
205
|
return super if should_skip_command?(command)
|
|
211
206
|
|
|
212
207
|
started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
213
|
-
error_info = nil
|
|
214
208
|
|
|
215
209
|
begin
|
|
216
210
|
result = super
|
|
@@ -227,7 +221,6 @@ module BrainzLab
|
|
|
227
221
|
return super unless should_track?
|
|
228
222
|
|
|
229
223
|
started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
230
|
-
error_info = nil
|
|
231
224
|
commands = pipeline.commands
|
|
232
225
|
|
|
233
226
|
begin
|
|
@@ -262,7 +255,7 @@ module BrainzLab
|
|
|
262
255
|
if BrainzLab.configuration.reflex_enabled
|
|
263
256
|
BrainzLab::Reflex.add_breadcrumb(
|
|
264
257
|
"Redis #{cmd_name}",
|
|
265
|
-
category:
|
|
258
|
+
category: 'redis',
|
|
266
259
|
level: level,
|
|
267
260
|
data: {
|
|
268
261
|
command: cmd_name,
|
|
@@ -285,7 +278,7 @@ module BrainzLab
|
|
|
285
278
|
if BrainzLab.configuration.reflex_enabled
|
|
286
279
|
BrainzLab::Reflex.add_breadcrumb(
|
|
287
280
|
"Redis PIPELINE (#{commands.size} commands)",
|
|
288
|
-
category:
|
|
281
|
+
category: 'redis',
|
|
289
282
|
level: level,
|
|
290
283
|
data: {
|
|
291
284
|
count: commands.size,
|
|
@@ -295,7 +288,7 @@ module BrainzLab
|
|
|
295
288
|
)
|
|
296
289
|
end
|
|
297
290
|
|
|
298
|
-
record_pulse_span(
|
|
291
|
+
record_pulse_span('PIPELINE', nil, duration_ms, error, commands.size)
|
|
299
292
|
rescue StandardError => e
|
|
300
293
|
BrainzLab.debug_log("Redis instrumentation error: #{e.message}")
|
|
301
294
|
end
|
|
@@ -307,7 +300,7 @@ module BrainzLab
|
|
|
307
300
|
span = {
|
|
308
301
|
span_id: SecureRandom.uuid,
|
|
309
302
|
name: "Redis #{command}",
|
|
310
|
-
kind:
|
|
303
|
+
kind: 'redis',
|
|
311
304
|
started_at: Time.now.utc - (duration_ms / 1000.0),
|
|
312
305
|
ended_at: Time.now.utc,
|
|
313
306
|
duration_ms: duration_ms,
|
|
@@ -10,13 +10,13 @@ module BrainzLab
|
|
|
10
10
|
install_hooks!
|
|
11
11
|
install_failure_backend!
|
|
12
12
|
|
|
13
|
-
BrainzLab.debug_log(
|
|
13
|
+
BrainzLab.debug_log('[Instrumentation] Resque instrumentation installed')
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
private
|
|
17
17
|
|
|
18
18
|
def install_hooks!
|
|
19
|
-
::Resque.before_fork do |
|
|
19
|
+
::Resque.before_fork do |_job|
|
|
20
20
|
# Clear any stale connections before forking
|
|
21
21
|
BrainzLab::Recall.reset! if defined?(BrainzLab::Recall)
|
|
22
22
|
BrainzLab::Pulse.reset! if defined?(BrainzLab::Pulse)
|
|
@@ -38,31 +38,30 @@ module BrainzLab
|
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
def save
|
|
41
|
-
job_class = @payload[
|
|
41
|
+
job_class = @payload['class'] || 'Unknown'
|
|
42
42
|
|
|
43
43
|
if BrainzLab.configuration.reflex_effectively_enabled?
|
|
44
44
|
BrainzLab::Reflex.capture(@exception,
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
)
|
|
45
|
+
tags: { job_class: job_class, queue: @queue, source: 'resque' },
|
|
46
|
+
extra: {
|
|
47
|
+
worker: @worker.to_s,
|
|
48
|
+
args: @payload['args']
|
|
49
|
+
})
|
|
51
50
|
end
|
|
52
51
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
return unless BrainzLab.configuration.flux_effectively_enabled?
|
|
53
|
+
|
|
54
|
+
BrainzLab::Flux.increment('resque.job.failed', tags: { job_class: job_class, queue: @queue })
|
|
56
55
|
end
|
|
57
56
|
end
|
|
58
57
|
|
|
59
58
|
# Add our failure backend to the chain
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
59
|
+
return unless defined?(::Resque::Failure)
|
|
60
|
+
|
|
61
|
+
::Resque::Failure.backend = ::Resque::Failure::Multiple.new(
|
|
62
|
+
::Resque::Failure.backend,
|
|
63
|
+
failure_backend
|
|
64
|
+
)
|
|
66
65
|
end
|
|
67
66
|
end
|
|
68
67
|
|
|
@@ -73,9 +72,9 @@ module BrainzLab
|
|
|
73
72
|
end
|
|
74
73
|
|
|
75
74
|
module ClassMethods
|
|
76
|
-
def around_perform_brainzlab(*
|
|
77
|
-
job_class =
|
|
78
|
-
queue = Resque.queue_from_class(self) ||
|
|
75
|
+
def around_perform_brainzlab(*_args)
|
|
76
|
+
job_class = name
|
|
77
|
+
queue = Resque.queue_from_class(self) || 'default'
|
|
79
78
|
started_at = Time.now
|
|
80
79
|
|
|
81
80
|
BrainzLab::Context.current.set_context(
|
|
@@ -91,7 +90,7 @@ module BrainzLab
|
|
|
91
90
|
if BrainzLab.configuration.pulse_effectively_enabled?
|
|
92
91
|
BrainzLab::Pulse.record_trace(
|
|
93
92
|
"job.#{job_class}",
|
|
94
|
-
kind:
|
|
93
|
+
kind: 'job',
|
|
95
94
|
started_at: started_at,
|
|
96
95
|
ended_at: Time.now,
|
|
97
96
|
job_class: job_class,
|
|
@@ -101,8 +100,8 @@ module BrainzLab
|
|
|
101
100
|
|
|
102
101
|
if BrainzLab.configuration.flux_effectively_enabled?
|
|
103
102
|
tags = { job_class: job_class, queue: queue }
|
|
104
|
-
BrainzLab::Flux.distribution(
|
|
105
|
-
BrainzLab::Flux.increment(
|
|
103
|
+
BrainzLab::Flux.distribution('resque.job.duration_ms', duration_ms, tags: tags)
|
|
104
|
+
BrainzLab::Flux.increment('resque.job.processed', tags: tags)
|
|
106
105
|
end
|
|
107
106
|
|
|
108
107
|
BrainzLab.clear_context!
|
|
@@ -29,7 +29,7 @@ module BrainzLab
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
@installed = true
|
|
32
|
-
BrainzLab.debug_log(
|
|
32
|
+
BrainzLab.debug_log('Sidekiq instrumentation installed')
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def installed?
|
|
@@ -47,11 +47,11 @@ module BrainzLab
|
|
|
47
47
|
return yield unless should_trace?
|
|
48
48
|
|
|
49
49
|
started_at = Time.now.utc
|
|
50
|
-
job_class = job[
|
|
51
|
-
job_id = job[
|
|
50
|
+
job_class = job['class'] || worker.class.name
|
|
51
|
+
job_id = job['jid']
|
|
52
52
|
|
|
53
53
|
# Calculate queue wait time
|
|
54
|
-
enqueued_at = job[
|
|
54
|
+
enqueued_at = job['enqueued_at'] ? Time.at(job['enqueued_at']) : nil
|
|
55
55
|
queue_wait_ms = enqueued_at ? ((started_at - enqueued_at) * 1000).round(2) : nil
|
|
56
56
|
|
|
57
57
|
# Extract parent trace context if present (distributed tracing)
|
|
@@ -63,9 +63,9 @@ module BrainzLab
|
|
|
63
63
|
# Add breadcrumb
|
|
64
64
|
BrainzLab::Reflex.add_breadcrumb(
|
|
65
65
|
"Sidekiq #{job_class}",
|
|
66
|
-
category:
|
|
66
|
+
category: 'job.sidekiq',
|
|
67
67
|
level: :info,
|
|
68
|
-
data: { job_id: job_id, queue: queue, retry_count: job[
|
|
68
|
+
data: { job_id: job_id, queue: queue, retry_count: job['retry_count'] }
|
|
69
69
|
)
|
|
70
70
|
|
|
71
71
|
# Initialize Pulse tracing
|
|
@@ -85,7 +85,7 @@ module BrainzLab
|
|
|
85
85
|
queue: queue,
|
|
86
86
|
started_at: started_at,
|
|
87
87
|
queue_wait_ms: queue_wait_ms,
|
|
88
|
-
retry_count: job[
|
|
88
|
+
retry_count: job['retry_count'] || 0,
|
|
89
89
|
parent_context: parent_context,
|
|
90
90
|
error: error_occurred
|
|
91
91
|
)
|
|
@@ -102,11 +102,11 @@ module BrainzLab
|
|
|
102
102
|
|
|
103
103
|
def setup_context(job, queue)
|
|
104
104
|
BrainzLab::Context.current.set_context(
|
|
105
|
-
job_class: job[
|
|
106
|
-
job_id: job[
|
|
105
|
+
job_class: job['class'],
|
|
106
|
+
job_id: job['jid'],
|
|
107
107
|
queue_name: queue,
|
|
108
|
-
retry_count: job[
|
|
109
|
-
arguments: job[
|
|
108
|
+
retry_count: job['retry_count'],
|
|
109
|
+
arguments: job['args']&.map(&:to_s)&.first(5)
|
|
110
110
|
)
|
|
111
111
|
end
|
|
112
112
|
|
|
@@ -118,19 +118,20 @@ module BrainzLab
|
|
|
118
118
|
end
|
|
119
119
|
|
|
120
120
|
def extract_trace_context(job)
|
|
121
|
-
return nil unless job[
|
|
121
|
+
return nil unless job['_brainzlab_trace']
|
|
122
122
|
|
|
123
|
-
trace_data = job[
|
|
123
|
+
trace_data = job['_brainzlab_trace']
|
|
124
124
|
BrainzLab::Pulse::Propagation::Context.new(
|
|
125
|
-
trace_id: trace_data[
|
|
126
|
-
span_id: trace_data[
|
|
127
|
-
sampled: trace_data[
|
|
125
|
+
trace_id: trace_data['trace_id'],
|
|
126
|
+
span_id: trace_data['span_id'],
|
|
127
|
+
sampled: trace_data['sampled'] != false
|
|
128
128
|
)
|
|
129
129
|
rescue StandardError
|
|
130
130
|
nil
|
|
131
131
|
end
|
|
132
132
|
|
|
133
|
-
def record_trace(job_class:, job_id:, queue:, started_at:, queue_wait_ms:, retry_count:, parent_context:,
|
|
133
|
+
def record_trace(job_class:, job_id:, queue:, started_at:, queue_wait_ms:, retry_count:, parent_context:,
|
|
134
|
+
error:)
|
|
134
135
|
ended_at = Time.now.utc
|
|
135
136
|
duration_ms = ((ended_at - started_at) * 1000).round(2)
|
|
136
137
|
|
|
@@ -156,7 +157,7 @@ module BrainzLab
|
|
|
156
157
|
payload = {
|
|
157
158
|
trace_id: SecureRandom.uuid,
|
|
158
159
|
name: job_class,
|
|
159
|
-
kind:
|
|
160
|
+
kind: 'job',
|
|
160
161
|
started_at: started_at.utc.iso8601(3),
|
|
161
162
|
ended_at: ended_at.utc.iso8601(3),
|
|
162
163
|
duration_ms: duration_ms,
|
|
@@ -200,7 +201,7 @@ module BrainzLab
|
|
|
200
201
|
|
|
201
202
|
# Client middleware - runs when jobs are enqueued
|
|
202
203
|
class ClientMiddleware
|
|
203
|
-
def call(
|
|
204
|
+
def call(_worker_class, job, queue, _redis_pool)
|
|
204
205
|
# Inject trace context for distributed tracing
|
|
205
206
|
inject_trace_context(job)
|
|
206
207
|
|
|
@@ -208,9 +209,9 @@ module BrainzLab
|
|
|
208
209
|
if BrainzLab.configuration.reflex_enabled
|
|
209
210
|
BrainzLab::Reflex.add_breadcrumb(
|
|
210
211
|
"Enqueue #{job['class']}",
|
|
211
|
-
category:
|
|
212
|
+
category: 'job.sidekiq.enqueue',
|
|
212
213
|
level: :info,
|
|
213
|
-
data: { queue: queue, job_id: job[
|
|
214
|
+
data: { queue: queue, job_id: job['jid'] }
|
|
214
215
|
)
|
|
215
216
|
end
|
|
216
217
|
|
|
@@ -231,10 +232,10 @@ module BrainzLab
|
|
|
231
232
|
|
|
232
233
|
return unless ctx&.valid?
|
|
233
234
|
|
|
234
|
-
job[
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
235
|
+
job['_brainzlab_trace'] = {
|
|
236
|
+
'trace_id' => ctx.trace_id,
|
|
237
|
+
'span_id' => ctx.span_id,
|
|
238
|
+
'sampled' => ctx.sampled
|
|
238
239
|
}
|
|
239
240
|
rescue StandardError => e
|
|
240
241
|
BrainzLab.debug_log("Failed to inject Sidekiq trace context: #{e.message}")
|
|
@@ -247,13 +248,13 @@ module BrainzLab
|
|
|
247
248
|
spans << {
|
|
248
249
|
span_id: SecureRandom.uuid,
|
|
249
250
|
name: "Enqueue #{job['class']}",
|
|
250
|
-
kind:
|
|
251
|
+
kind: 'job',
|
|
251
252
|
started_at: Time.now.utc,
|
|
252
253
|
ended_at: Time.now.utc,
|
|
253
254
|
duration_ms: 0,
|
|
254
255
|
data: {
|
|
255
|
-
job_class: job[
|
|
256
|
-
job_id: job[
|
|
256
|
+
job_class: job['class'],
|
|
257
|
+
job_id: job['jid'],
|
|
257
258
|
queue: queue
|
|
258
259
|
}
|
|
259
260
|
}
|