brainzlab 0.1.2 → 0.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/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 +92 -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_mailer.rb +14 -13
- data/lib/brainzlab/instrumentation/active_record.rb +13 -15
- 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/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 +20 -20
- 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 +1 -1
|
@@ -11,17 +11,13 @@ module BrainzLab
|
|
|
11
11
|
return if @installed
|
|
12
12
|
|
|
13
13
|
# Install lifecycle hooks
|
|
14
|
-
if defined?(::Delayed::Worker)
|
|
15
|
-
install_lifecycle_hooks!
|
|
16
|
-
end
|
|
14
|
+
install_lifecycle_hooks! if defined?(::Delayed::Worker)
|
|
17
15
|
|
|
18
16
|
# Install plugin if Delayed::Plugin is available
|
|
19
|
-
if defined?(::Delayed::Plugin)
|
|
20
|
-
::Delayed::Worker.plugins << Plugin
|
|
21
|
-
end
|
|
17
|
+
::Delayed::Worker.plugins << Plugin if defined?(::Delayed::Plugin)
|
|
22
18
|
|
|
23
19
|
@installed = true
|
|
24
|
-
BrainzLab.debug_log(
|
|
20
|
+
BrainzLab.debug_log('Delayed::Job instrumentation installed')
|
|
25
21
|
end
|
|
26
22
|
|
|
27
23
|
def installed?
|
|
@@ -35,15 +31,15 @@ module BrainzLab
|
|
|
35
31
|
private
|
|
36
32
|
|
|
37
33
|
def install_lifecycle_hooks!
|
|
38
|
-
::Delayed::Worker.lifecycle.around(:invoke_job) do |job, *
|
|
34
|
+
::Delayed::Worker.lifecycle.around(:invoke_job) do |job, *_args, &block|
|
|
39
35
|
around_invoke(job, &block)
|
|
40
36
|
end
|
|
41
37
|
|
|
42
|
-
::Delayed::Worker.lifecycle.after(:error) do |
|
|
38
|
+
::Delayed::Worker.lifecycle.after(:error) do |_worker, job|
|
|
43
39
|
record_error(job)
|
|
44
40
|
end
|
|
45
41
|
|
|
46
|
-
::Delayed::Worker.lifecycle.after(:failure) do |
|
|
42
|
+
::Delayed::Worker.lifecycle.after(:failure) do |_worker, job|
|
|
47
43
|
record_failure(job)
|
|
48
44
|
end
|
|
49
45
|
rescue StandardError => e
|
|
@@ -53,7 +49,7 @@ module BrainzLab
|
|
|
53
49
|
def around_invoke(job, &block)
|
|
54
50
|
started_at = Time.now.utc
|
|
55
51
|
job_name = extract_job_name(job)
|
|
56
|
-
queue = job.queue ||
|
|
52
|
+
queue = job.queue || 'default'
|
|
57
53
|
|
|
58
54
|
# Calculate queue wait time
|
|
59
55
|
queue_wait_ms = job.created_at ? ((started_at - job.created_at) * 1000).round(2) : nil
|
|
@@ -64,7 +60,7 @@ module BrainzLab
|
|
|
64
60
|
# Add breadcrumb
|
|
65
61
|
BrainzLab::Reflex.add_breadcrumb(
|
|
66
62
|
"DelayedJob #{job_name}",
|
|
67
|
-
category:
|
|
63
|
+
category: 'job.delayed_job',
|
|
68
64
|
level: :info,
|
|
69
65
|
data: { job_id: job.id, queue: queue, attempts: job.attempts }
|
|
70
66
|
)
|
|
@@ -133,7 +129,7 @@ module BrainzLab
|
|
|
133
129
|
payload = {
|
|
134
130
|
trace_id: SecureRandom.uuid,
|
|
135
131
|
name: job_name,
|
|
136
|
-
kind:
|
|
132
|
+
kind: 'job',
|
|
137
133
|
started_at: started_at.utc.iso8601(3),
|
|
138
134
|
ended_at: ended_at.utc.iso8601(3),
|
|
139
135
|
duration_ms: duration_ms,
|
|
@@ -162,7 +158,7 @@ module BrainzLab
|
|
|
162
158
|
|
|
163
159
|
BrainzLab::Reflex.add_breadcrumb(
|
|
164
160
|
"DelayedJob error: #{extract_job_name(job)}",
|
|
165
|
-
category:
|
|
161
|
+
category: 'job.delayed_job.error',
|
|
166
162
|
level: :error,
|
|
167
163
|
data: {
|
|
168
164
|
job_id: job.id,
|
|
@@ -177,7 +173,7 @@ module BrainzLab
|
|
|
177
173
|
def record_failure(job)
|
|
178
174
|
BrainzLab::Reflex.add_breadcrumb(
|
|
179
175
|
"DelayedJob failed permanently: #{extract_job_name(job)}",
|
|
180
|
-
category:
|
|
176
|
+
category: 'job.delayed_job.failure',
|
|
181
177
|
level: :error,
|
|
182
178
|
data: {
|
|
183
179
|
job_id: job.id,
|
|
@@ -200,7 +196,7 @@ module BrainzLab
|
|
|
200
196
|
payload.class.name
|
|
201
197
|
end
|
|
202
198
|
rescue StandardError
|
|
203
|
-
job.name ||
|
|
199
|
+
job.name || 'Unknown'
|
|
204
200
|
end
|
|
205
201
|
|
|
206
202
|
def format_timestamp(ts)
|
|
@@ -216,21 +212,23 @@ module BrainzLab
|
|
|
216
212
|
end
|
|
217
213
|
|
|
218
214
|
# Delayed::Job Plugin (alternative installation method)
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
215
|
+
if defined?(::Delayed::Plugin)
|
|
216
|
+
class Plugin < ::Delayed::Plugin
|
|
217
|
+
callbacks do |lifecycle|
|
|
218
|
+
lifecycle.around(:invoke_job) do |job, *_args, &block|
|
|
219
|
+
DelayedJobInstrumentation.send(:around_invoke, job, &block)
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
lifecycle.after(:error) do |_worker, job|
|
|
223
|
+
DelayedJobInstrumentation.send(:record_error, job)
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
lifecycle.after(:failure) do |_worker, job|
|
|
227
|
+
DelayedJobInstrumentation.send(:record_failure, job)
|
|
228
|
+
end
|
|
231
229
|
end
|
|
232
230
|
end
|
|
233
|
-
end
|
|
231
|
+
end
|
|
234
232
|
end
|
|
235
233
|
end
|
|
236
234
|
end
|
|
@@ -32,7 +32,7 @@ module BrainzLab
|
|
|
32
32
|
return unless installed_any
|
|
33
33
|
|
|
34
34
|
@installed = true
|
|
35
|
-
BrainzLab.debug_log(
|
|
35
|
+
BrainzLab.debug_log('Elasticsearch instrumentation installed')
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
def installed?
|
|
@@ -64,14 +64,12 @@ module BrainzLab
|
|
|
64
64
|
return super unless should_track?
|
|
65
65
|
|
|
66
66
|
started_at = Time.now.utc
|
|
67
|
-
error_info = nil
|
|
68
67
|
|
|
69
68
|
begin
|
|
70
69
|
response = super
|
|
71
70
|
record_request(method, path, params, started_at, response.status)
|
|
72
71
|
response
|
|
73
72
|
rescue StandardError => e
|
|
74
|
-
error_info = e
|
|
75
73
|
record_request(method, path, params, started_at, nil, e)
|
|
76
74
|
raise
|
|
77
75
|
end
|
|
@@ -83,7 +81,7 @@ module BrainzLab
|
|
|
83
81
|
BrainzLab.configuration.instrument_elasticsearch
|
|
84
82
|
end
|
|
85
83
|
|
|
86
|
-
def record_request(method, path,
|
|
84
|
+
def record_request(method, path, _params, started_at, status, error = nil)
|
|
87
85
|
duration_ms = ((Time.now.utc - started_at) * 1000).round(2)
|
|
88
86
|
operation = extract_operation(method, path)
|
|
89
87
|
index = extract_index(path)
|
|
@@ -93,7 +91,7 @@ module BrainzLab
|
|
|
93
91
|
if BrainzLab.configuration.reflex_enabled
|
|
94
92
|
BrainzLab::Reflex.add_breadcrumb(
|
|
95
93
|
"ES #{operation}",
|
|
96
|
-
category:
|
|
94
|
+
category: 'elasticsearch',
|
|
97
95
|
level: level,
|
|
98
96
|
data: {
|
|
99
97
|
method: method.to_s.upcase,
|
|
@@ -143,7 +141,7 @@ module BrainzLab
|
|
|
143
141
|
span = {
|
|
144
142
|
span_id: SecureRandom.uuid,
|
|
145
143
|
name: "ES #{operation}",
|
|
146
|
-
kind:
|
|
144
|
+
kind: 'elasticsearch',
|
|
147
145
|
started_at: started_at,
|
|
148
146
|
ended_at: Time.now.utc,
|
|
149
147
|
duration_ms: duration_ms,
|
|
@@ -168,25 +166,25 @@ module BrainzLab
|
|
|
168
166
|
method_str = method.to_s.upcase
|
|
169
167
|
|
|
170
168
|
case path
|
|
171
|
-
when %r{/_search} then
|
|
172
|
-
when %r{/_bulk} then
|
|
173
|
-
when %r{/_count} then
|
|
174
|
-
when %r{/_mget} then
|
|
175
|
-
when %r{/_msearch} then
|
|
176
|
-
when %r{/_update_by_query} then
|
|
177
|
-
when %r{/_delete_by_query} then
|
|
178
|
-
when %r{/_refresh} then
|
|
179
|
-
when %r{/_mapping} then
|
|
180
|
-
when %r{/_settings} then
|
|
181
|
-
when %r{/_alias} then
|
|
182
|
-
when %r{/_analyze} then
|
|
169
|
+
when %r{/_search} then 'search'
|
|
170
|
+
when %r{/_bulk} then 'bulk'
|
|
171
|
+
when %r{/_count} then 'count'
|
|
172
|
+
when %r{/_mget} then 'mget'
|
|
173
|
+
when %r{/_msearch} then 'msearch'
|
|
174
|
+
when %r{/_update_by_query} then 'update_by_query'
|
|
175
|
+
when %r{/_delete_by_query} then 'delete_by_query'
|
|
176
|
+
when %r{/_refresh} then 'refresh'
|
|
177
|
+
when %r{/_mapping} then 'mapping'
|
|
178
|
+
when %r{/_settings} then 'settings'
|
|
179
|
+
when %r{/_alias} then 'alias'
|
|
180
|
+
when %r{/_analyze} then 'analyze'
|
|
183
181
|
else
|
|
184
182
|
case method_str
|
|
185
|
-
when
|
|
186
|
-
when
|
|
187
|
-
when
|
|
188
|
-
when
|
|
189
|
-
when
|
|
183
|
+
when 'GET' then 'get'
|
|
184
|
+
when 'POST' then 'index'
|
|
185
|
+
when 'PUT' then 'update'
|
|
186
|
+
when 'DELETE' then 'delete'
|
|
187
|
+
when 'HEAD' then 'exists'
|
|
190
188
|
else method_str.downcase
|
|
191
189
|
end
|
|
192
190
|
end
|
|
@@ -195,13 +193,14 @@ module BrainzLab
|
|
|
195
193
|
def extract_index(path)
|
|
196
194
|
# Extract index name from path like /my-index/_search
|
|
197
195
|
match = path.match(%r{^/([^/_]+)})
|
|
198
|
-
match[1] if match && !match[1].start_with?(
|
|
196
|
+
match[1] if match && !match[1].start_with?('_')
|
|
199
197
|
rescue StandardError
|
|
200
198
|
nil
|
|
201
199
|
end
|
|
202
200
|
|
|
203
201
|
def truncate_path(path)
|
|
204
202
|
return nil unless path
|
|
203
|
+
|
|
205
204
|
path.to_s[0, 200]
|
|
206
205
|
end
|
|
207
206
|
end
|
|
@@ -9,7 +9,7 @@ module BrainzLab
|
|
|
9
9
|
|
|
10
10
|
install_middleware!
|
|
11
11
|
|
|
12
|
-
BrainzLab.debug_log(
|
|
12
|
+
BrainzLab.debug_log('[Instrumentation] Excon instrumentation installed')
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
private
|
|
@@ -19,15 +19,15 @@ module BrainzLab
|
|
|
19
19
|
::Excon.defaults[:instrumentor] = BrainzLabInstrumentor
|
|
20
20
|
|
|
21
21
|
# Also set up middleware
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
return unless ::Excon.defaults[:middlewares]
|
|
23
|
+
|
|
24
|
+
::Excon.defaults[:middlewares] = [Middleware] + ::Excon.defaults[:middlewares]
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
# Excon Instrumentor for ActiveSupport-style notifications
|
|
29
29
|
module BrainzLabInstrumentor
|
|
30
|
-
def self.instrument(name, params = {}
|
|
30
|
+
def self.instrument(name, params = {})
|
|
31
31
|
started_at = Time.now
|
|
32
32
|
|
|
33
33
|
begin
|
|
@@ -40,19 +40,19 @@ module BrainzLab
|
|
|
40
40
|
end
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
-
def self.track_request(
|
|
43
|
+
def self.track_request(_name, params, started_at, error)
|
|
44
44
|
return if skip_tracking?(params)
|
|
45
45
|
|
|
46
46
|
duration_ms = ((Time.now - started_at) * 1000).round(2)
|
|
47
|
-
host = params[:host] ||
|
|
48
|
-
method = (params[:method] ||
|
|
49
|
-
path = params[:path] ||
|
|
47
|
+
host = params[:host] || 'unknown'
|
|
48
|
+
method = (params[:method] || 'GET').to_s.upcase
|
|
49
|
+
path = params[:path] || '/'
|
|
50
50
|
status = params[:status]
|
|
51
51
|
|
|
52
52
|
# Add breadcrumb
|
|
53
53
|
BrainzLab::Reflex.add_breadcrumb(
|
|
54
54
|
"HTTP #{method} #{host}#{path}",
|
|
55
|
-
category:
|
|
55
|
+
category: 'http',
|
|
56
56
|
level: error ? :error : :info,
|
|
57
57
|
data: {
|
|
58
58
|
method: method,
|
|
@@ -65,21 +65,21 @@ module BrainzLab
|
|
|
65
65
|
|
|
66
66
|
# Track with Pulse
|
|
67
67
|
if BrainzLab.configuration.pulse_effectively_enabled?
|
|
68
|
-
BrainzLab::Pulse.span(
|
|
68
|
+
BrainzLab::Pulse.span('http.excon', kind: 'http') do
|
|
69
69
|
# Already completed, just recording
|
|
70
70
|
end
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
# Track with Flux
|
|
74
|
-
|
|
75
|
-
tags = { host: host, method: method, status: status.to_s }
|
|
76
|
-
BrainzLab::Flux.distribution("http.excon.duration_ms", duration_ms, tags: tags)
|
|
77
|
-
BrainzLab::Flux.increment("http.excon.requests", tags: tags)
|
|
74
|
+
return unless BrainzLab.configuration.flux_effectively_enabled?
|
|
78
75
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
76
|
+
tags = { host: host, method: method, status: status.to_s }
|
|
77
|
+
BrainzLab::Flux.distribution('http.excon.duration_ms', duration_ms, tags: tags)
|
|
78
|
+
BrainzLab::Flux.increment('http.excon.requests', tags: tags)
|
|
79
|
+
|
|
80
|
+
return unless error || (status && status >= 400)
|
|
81
|
+
|
|
82
|
+
BrainzLab::Flux.increment('http.excon.errors', tags: tags)
|
|
83
83
|
end
|
|
84
84
|
|
|
85
85
|
def self.skip_tracking?(params)
|
|
@@ -122,22 +122,22 @@ module BrainzLab
|
|
|
122
122
|
return if skip_host?(host)
|
|
123
123
|
|
|
124
124
|
duration_ms = ((Time.now - started_at) * 1000).round(2)
|
|
125
|
-
method = (datum[:method] ||
|
|
126
|
-
path = datum[:path] ||
|
|
125
|
+
method = (datum[:method] || 'GET').to_s.upcase
|
|
126
|
+
path = datum[:path] || '/'
|
|
127
127
|
status = datum[:response]&.dig(:status)
|
|
128
128
|
|
|
129
129
|
BrainzLab::Reflex.add_breadcrumb(
|
|
130
130
|
"HTTP #{method} #{host}#{path} -> #{status || 'error'}",
|
|
131
|
-
category:
|
|
131
|
+
category: 'http',
|
|
132
132
|
level: error ? :error : :info,
|
|
133
133
|
data: { method: method, host: host, status: status, duration_ms: duration_ms }
|
|
134
134
|
)
|
|
135
135
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
136
|
+
return unless BrainzLab.configuration.flux_effectively_enabled?
|
|
137
|
+
|
|
138
|
+
tags = { host: host, method: method }
|
|
139
|
+
tags[:status] = status.to_s if status
|
|
140
|
+
BrainzLab::Flux.distribution('http.excon.duration_ms', duration_ms, tags: tags)
|
|
141
141
|
end
|
|
142
142
|
|
|
143
143
|
def skip_host?(host)
|
|
@@ -14,7 +14,7 @@ module BrainzLab
|
|
|
14
14
|
::Faraday::Middleware.register_middleware(brainzlab: Middleware)
|
|
15
15
|
|
|
16
16
|
@installed = true
|
|
17
|
-
BrainzLab.debug_log(
|
|
17
|
+
BrainzLab.debug_log('Faraday instrumentation installed')
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def installed?
|
|
@@ -46,7 +46,6 @@ module BrainzLab
|
|
|
46
46
|
inject_trace_context(env)
|
|
47
47
|
|
|
48
48
|
started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
49
|
-
error_info = nil
|
|
50
49
|
|
|
51
50
|
begin
|
|
52
51
|
response = @app.call(env)
|
|
@@ -98,7 +97,7 @@ module BrainzLab
|
|
|
98
97
|
if BrainzLab.configuration.reflex_enabled
|
|
99
98
|
BrainzLab::Reflex.add_breadcrumb(
|
|
100
99
|
"#{method} #{url}",
|
|
101
|
-
category:
|
|
100
|
+
category: 'http.faraday',
|
|
102
101
|
level: level,
|
|
103
102
|
data: {
|
|
104
103
|
method: method,
|
|
@@ -138,7 +137,7 @@ module BrainzLab
|
|
|
138
137
|
span = {
|
|
139
138
|
span_id: SecureRandom.uuid,
|
|
140
139
|
name: "HTTP #{method} #{host}",
|
|
141
|
-
kind:
|
|
140
|
+
kind: 'http',
|
|
142
141
|
started_at: Time.now.utc - (duration_ms / 1000.0),
|
|
143
142
|
ended_at: Time.now.utc,
|
|
144
143
|
duration_ms: duration_ms,
|
|
@@ -10,7 +10,7 @@ module BrainzLab
|
|
|
10
10
|
install_notifier!
|
|
11
11
|
install_middleware!
|
|
12
12
|
|
|
13
|
-
BrainzLab.debug_log(
|
|
13
|
+
BrainzLab.debug_log('[Instrumentation] GoodJob instrumentation installed')
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
private
|
|
@@ -19,12 +19,12 @@ module BrainzLab
|
|
|
19
19
|
return unless defined?(::ActiveSupport::Notifications)
|
|
20
20
|
|
|
21
21
|
# GoodJob emits ActiveSupport notifications
|
|
22
|
-
::ActiveSupport::Notifications.subscribe(
|
|
22
|
+
::ActiveSupport::Notifications.subscribe('perform_job.good_job') do |*args|
|
|
23
23
|
event = ::ActiveSupport::Notifications::Event.new(*args)
|
|
24
24
|
handle_perform(event)
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
-
::ActiveSupport::Notifications.subscribe(
|
|
27
|
+
::ActiveSupport::Notifications.subscribe('finished_job_task.good_job') do |*args|
|
|
28
28
|
event = ::ActiveSupport::Notifications::Event.new(*args)
|
|
29
29
|
handle_finished(event)
|
|
30
30
|
end
|
|
@@ -34,25 +34,28 @@ module BrainzLab
|
|
|
34
34
|
return unless defined?(::GoodJob::Adapter)
|
|
35
35
|
|
|
36
36
|
# Add our callback to GoodJob
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
return unless ::GoodJob.respond_to?(:on_thread_error)
|
|
38
|
+
|
|
39
|
+
::GoodJob.on_thread_error = lambda { |error|
|
|
40
|
+
if BrainzLab.configuration.reflex_effectively_enabled?
|
|
41
|
+
BrainzLab::Reflex.capture(error,
|
|
42
|
+
tags: { source: 'good_job' })
|
|
40
43
|
end
|
|
41
|
-
|
|
44
|
+
}
|
|
42
45
|
end
|
|
43
46
|
|
|
44
47
|
def handle_perform(event)
|
|
45
48
|
payload = event.payload
|
|
46
49
|
job = payload[:job]
|
|
47
|
-
job_class = job&.class&.name || payload[:job_class] ||
|
|
48
|
-
queue = job&.queue_name || payload[:queue_name] ||
|
|
50
|
+
job_class = job&.class&.name || payload[:job_class] || 'Unknown'
|
|
51
|
+
queue = job&.queue_name || payload[:queue_name] || 'default'
|
|
49
52
|
duration_ms = event.duration.round(2)
|
|
50
53
|
|
|
51
54
|
# Track with Pulse
|
|
52
55
|
if BrainzLab.configuration.pulse_effectively_enabled?
|
|
53
56
|
BrainzLab::Pulse.record_trace(
|
|
54
57
|
"job.#{job_class}",
|
|
55
|
-
kind:
|
|
58
|
+
kind: 'job',
|
|
56
59
|
started_at: event.time,
|
|
57
60
|
ended_at: event.end,
|
|
58
61
|
job_class: job_class,
|
|
@@ -67,33 +70,30 @@ module BrainzLab
|
|
|
67
70
|
# Track with Flux
|
|
68
71
|
if BrainzLab.configuration.flux_effectively_enabled?
|
|
69
72
|
tags = { job_class: job_class, queue: queue }
|
|
70
|
-
BrainzLab::Flux.distribution(
|
|
71
|
-
BrainzLab::Flux.increment(
|
|
73
|
+
BrainzLab::Flux.distribution('good_job.job.duration_ms', duration_ms, tags: tags)
|
|
74
|
+
BrainzLab::Flux.increment('good_job.job.processed', tags: tags)
|
|
72
75
|
|
|
73
|
-
if payload[:error]
|
|
74
|
-
BrainzLab::Flux.increment("good_job.job.failed", tags: tags)
|
|
75
|
-
end
|
|
76
|
+
BrainzLab::Flux.increment('good_job.job.failed', tags: tags) if payload[:error]
|
|
76
77
|
end
|
|
77
78
|
|
|
78
79
|
# Capture error with Reflex
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
end
|
|
80
|
+
return unless payload[:error] && BrainzLab.configuration.reflex_effectively_enabled?
|
|
81
|
+
|
|
82
|
+
BrainzLab::Reflex.capture(payload[:error],
|
|
83
|
+
tags: { job_class: job_class, queue: queue, source: 'good_job' },
|
|
84
|
+
extra: { job_id: job&.job_id, duration_ms: duration_ms })
|
|
85
85
|
end
|
|
86
86
|
|
|
87
87
|
def handle_finished(event)
|
|
88
88
|
payload = event.payload
|
|
89
89
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
90
|
+
return unless BrainzLab.configuration.flux_effectively_enabled?
|
|
91
|
+
|
|
92
|
+
result = payload[:result]
|
|
93
|
+
if result == :discarded
|
|
94
|
+
BrainzLab::Flux.increment('good_job.job.discarded')
|
|
95
|
+
elsif result == :retried
|
|
96
|
+
BrainzLab::Flux.increment('good_job.job.retried')
|
|
97
97
|
end
|
|
98
98
|
end
|
|
99
99
|
end
|
|
@@ -14,7 +14,7 @@ module BrainzLab
|
|
|
14
14
|
install_notifications!
|
|
15
15
|
|
|
16
16
|
@installed = true
|
|
17
|
-
BrainzLab.debug_log(
|
|
17
|
+
BrainzLab.debug_log('Grape instrumentation installed')
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def installed?
|
|
@@ -29,23 +29,23 @@ module BrainzLab
|
|
|
29
29
|
|
|
30
30
|
def install_notifications!
|
|
31
31
|
# Grape emits these notifications
|
|
32
|
-
ActiveSupport::Notifications.subscribe(
|
|
32
|
+
ActiveSupport::Notifications.subscribe('endpoint_run.grape') do |*args|
|
|
33
33
|
event = ActiveSupport::Notifications::Event.new(*args)
|
|
34
34
|
record_endpoint(event)
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
-
ActiveSupport::Notifications.subscribe(
|
|
37
|
+
ActiveSupport::Notifications.subscribe('endpoint_render.grape') do |*args|
|
|
38
38
|
event = ActiveSupport::Notifications::Event.new(*args)
|
|
39
39
|
record_render(event)
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
-
ActiveSupport::Notifications.subscribe(
|
|
42
|
+
ActiveSupport::Notifications.subscribe('endpoint_run_filters.grape') do |*args|
|
|
43
43
|
event = ActiveSupport::Notifications::Event.new(*args)
|
|
44
44
|
record_filters(event)
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
# Format validation
|
|
48
|
-
ActiveSupport::Notifications.subscribe(
|
|
48
|
+
ActiveSupport::Notifications.subscribe('format_response.grape') do |*args|
|
|
49
49
|
event = ActiveSupport::Notifications::Event.new(*args)
|
|
50
50
|
record_format(event)
|
|
51
51
|
end
|
|
@@ -58,19 +58,19 @@ module BrainzLab
|
|
|
58
58
|
endpoint = payload[:endpoint]
|
|
59
59
|
env = payload[:env] || {}
|
|
60
60
|
|
|
61
|
-
method = env[
|
|
62
|
-
path = endpoint&.options&.dig(:path)&.first || env[
|
|
61
|
+
method = env['REQUEST_METHOD'] || 'GET'
|
|
62
|
+
path = endpoint&.options&.dig(:path)&.first || env['PATH_INFO'] || '/'
|
|
63
63
|
route_pattern = extract_route_pattern(endpoint)
|
|
64
64
|
duration_ms = event.duration.round(2)
|
|
65
65
|
|
|
66
|
-
status = env[
|
|
66
|
+
status = env['api.endpoint']&.status || 200
|
|
67
67
|
level = status >= 400 ? :error : :info
|
|
68
68
|
|
|
69
69
|
# Add breadcrumb for Reflex
|
|
70
70
|
if BrainzLab.configuration.reflex_enabled
|
|
71
71
|
BrainzLab::Reflex.add_breadcrumb(
|
|
72
72
|
"Grape #{method} #{route_pattern}",
|
|
73
|
-
category:
|
|
73
|
+
category: 'grape.endpoint',
|
|
74
74
|
level: level,
|
|
75
75
|
data: {
|
|
76
76
|
method: method,
|
|
@@ -85,7 +85,7 @@ module BrainzLab
|
|
|
85
85
|
# Record span for Pulse
|
|
86
86
|
record_span(
|
|
87
87
|
name: "Grape #{method} #{route_pattern}",
|
|
88
|
-
kind:
|
|
88
|
+
kind: 'grape',
|
|
89
89
|
started_at: event.time,
|
|
90
90
|
ended_at: event.end,
|
|
91
91
|
duration_ms: duration_ms,
|
|
@@ -117,12 +117,12 @@ module BrainzLab
|
|
|
117
117
|
duration_ms = event.duration.round(2)
|
|
118
118
|
|
|
119
119
|
record_span(
|
|
120
|
-
name:
|
|
121
|
-
kind:
|
|
120
|
+
name: 'Grape render',
|
|
121
|
+
kind: 'grape.render',
|
|
122
122
|
started_at: event.time,
|
|
123
123
|
ended_at: event.end,
|
|
124
124
|
duration_ms: duration_ms,
|
|
125
|
-
data: { phase:
|
|
125
|
+
data: { phase: 'render' }
|
|
126
126
|
)
|
|
127
127
|
rescue StandardError => e
|
|
128
128
|
BrainzLab.debug_log("Grape render recording failed: #{e.message}")
|
|
@@ -131,11 +131,11 @@ module BrainzLab
|
|
|
131
131
|
def record_filters(event)
|
|
132
132
|
payload = event.payload
|
|
133
133
|
duration_ms = event.duration.round(2)
|
|
134
|
-
filter_type = payload[:type] ||
|
|
134
|
+
filter_type = payload[:type] || 'filter'
|
|
135
135
|
|
|
136
136
|
record_span(
|
|
137
137
|
name: "Grape #{filter_type} filters",
|
|
138
|
-
kind:
|
|
138
|
+
kind: 'grape.filter',
|
|
139
139
|
started_at: event.time,
|
|
140
140
|
ended_at: event.end,
|
|
141
141
|
duration_ms: duration_ms,
|
|
@@ -149,12 +149,12 @@ module BrainzLab
|
|
|
149
149
|
duration_ms = event.duration.round(2)
|
|
150
150
|
|
|
151
151
|
record_span(
|
|
152
|
-
name:
|
|
153
|
-
kind:
|
|
152
|
+
name: 'Grape format response',
|
|
153
|
+
kind: 'grape.format',
|
|
154
154
|
started_at: event.time,
|
|
155
155
|
ended_at: event.end,
|
|
156
156
|
duration_ms: duration_ms,
|
|
157
|
-
data: { phase:
|
|
157
|
+
data: { phase: 'format' }
|
|
158
158
|
)
|
|
159
159
|
rescue StandardError => e
|
|
160
160
|
BrainzLab.debug_log("Grape format recording failed: #{e.message}")
|
|
@@ -177,14 +177,14 @@ module BrainzLab
|
|
|
177
177
|
end
|
|
178
178
|
|
|
179
179
|
def extract_route_pattern(endpoint)
|
|
180
|
-
return
|
|
180
|
+
return '/' unless endpoint
|
|
181
181
|
|
|
182
182
|
route = endpoint.route
|
|
183
|
-
return
|
|
183
|
+
return '/' unless route
|
|
184
184
|
|
|
185
|
-
route.pattern&.path || route.path ||
|
|
185
|
+
route.pattern&.path || route.path || '/'
|
|
186
186
|
rescue StandardError
|
|
187
|
-
|
|
187
|
+
'/'
|
|
188
188
|
end
|
|
189
189
|
end
|
|
190
190
|
|
|
@@ -243,14 +243,14 @@ module BrainzLab
|
|
|
243
243
|
path = request.path
|
|
244
244
|
|
|
245
245
|
# Get route pattern from Grape if available
|
|
246
|
-
route_pattern = env[
|
|
246
|
+
route_pattern = env['grape.routing_args']&.dig(:route_info)&.pattern&.path || path
|
|
247
247
|
|
|
248
248
|
spans = Thread.current[:brainzlab_pulse_spans] || []
|
|
249
249
|
|
|
250
250
|
payload = {
|
|
251
251
|
trace_id: SecureRandom.uuid,
|
|
252
252
|
name: "#{method} #{route_pattern}",
|
|
253
|
-
kind:
|
|
253
|
+
kind: 'request',
|
|
254
254
|
started_at: started_at.utc.iso8601(3),
|
|
255
255
|
ended_at: ended_at.utc.iso8601(3),
|
|
256
256
|
duration_ms: duration_ms,
|