brainzlab 0.1.1 → 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 +24 -2
- data/lib/brainzlab/beacon/client.rb +207 -0
- data/lib/brainzlab/beacon/provisioner.rb +44 -0
- data/lib/brainzlab/beacon.rb +215 -0
- data/lib/brainzlab/configuration.rb +372 -32
- data/lib/brainzlab/context.rb +2 -3
- data/lib/brainzlab/cortex/cache.rb +59 -0
- data/lib/brainzlab/cortex/client.rb +139 -0
- data/lib/brainzlab/cortex/provisioner.rb +49 -0
- data/lib/brainzlab/cortex.rb +223 -0
- data/lib/brainzlab/dendrite/client.rb +230 -0
- data/lib/brainzlab/dendrite/provisioner.rb +44 -0
- data/lib/brainzlab/dendrite.rb +195 -0
- data/lib/brainzlab/devtools/assets/devtools.css +1106 -0
- data/lib/brainzlab/devtools/assets/devtools.js +322 -0
- data/lib/brainzlab/devtools/assets/logo.svg +6 -0
- data/lib/brainzlab/devtools/assets/templates/debug_panel.html.erb +500 -0
- data/lib/brainzlab/devtools/assets/templates/error_page.html.erb +1086 -0
- data/lib/brainzlab/devtools/data/collector.rb +248 -0
- data/lib/brainzlab/devtools/middleware/asset_server.rb +63 -0
- data/lib/brainzlab/devtools/middleware/database_handler.rb +177 -0
- data/lib/brainzlab/devtools/middleware/debug_panel.rb +126 -0
- data/lib/brainzlab/devtools/middleware/error_page.rb +377 -0
- data/lib/brainzlab/devtools/renderers/debug_panel_renderer.rb +159 -0
- data/lib/brainzlab/devtools/renderers/error_page_renderer.rb +98 -0
- data/lib/brainzlab/devtools.rb +75 -0
- data/lib/brainzlab/flux/buffer.rb +96 -0
- data/lib/brainzlab/flux/client.rb +68 -0
- data/lib/brainzlab/flux/provisioner.rb +57 -0
- data/lib/brainzlab/flux.rb +174 -0
- data/lib/brainzlab/instrumentation/action_mailer.rb +14 -13
- data/lib/brainzlab/instrumentation/active_record.rb +28 -13
- data/lib/brainzlab/instrumentation/aws.rb +183 -0
- data/lib/brainzlab/instrumentation/dalli.rb +108 -0
- data/lib/brainzlab/instrumentation/delayed_job.rb +27 -29
- data/lib/brainzlab/instrumentation/elasticsearch.rb +23 -24
- data/lib/brainzlab/instrumentation/excon.rb +152 -0
- data/lib/brainzlab/instrumentation/faraday.rb +3 -4
- data/lib/brainzlab/instrumentation/good_job.rb +102 -0
- 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 +114 -0
- data/lib/brainzlab/instrumentation/sidekiq.rb +29 -28
- data/lib/brainzlab/instrumentation/solid_queue.rb +194 -0
- data/lib/brainzlab/instrumentation/stripe.rb +163 -0
- data/lib/brainzlab/instrumentation/typhoeus.rb +106 -0
- data/lib/brainzlab/instrumentation.rb +84 -12
- data/lib/brainzlab/nerve/client.rb +215 -0
- data/lib/brainzlab/nerve/provisioner.rb +44 -0
- data/lib/brainzlab/nerve.rb +219 -0
- data/lib/brainzlab/pulse/client.rb +15 -11
- data/lib/brainzlab/pulse/instrumentation.rb +90 -53
- data/lib/brainzlab/pulse/propagation.rb +29 -29
- data/lib/brainzlab/pulse/provisioner.rb +12 -12
- data/lib/brainzlab/pulse/tracer.rb +4 -4
- data/lib/brainzlab/pulse.rb +14 -14
- data/lib/brainzlab/rails/log_formatter.rb +127 -121
- data/lib/brainzlab/rails/log_subscriber.rb +70 -77
- data/lib/brainzlab/rails/railtie.rb +96 -86
- 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 +29 -12
- data/lib/brainzlab/recall.rb +14 -11
- 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 +31 -31
- data/lib/brainzlab/sentinel/client.rb +216 -0
- data/lib/brainzlab/sentinel/provisioner.rb +44 -0
- data/lib/brainzlab/sentinel.rb +165 -0
- data/lib/brainzlab/signal/client.rb +60 -0
- data/lib/brainzlab/signal/provisioner.rb +55 -0
- data/lib/brainzlab/signal.rb +136 -0
- data/lib/brainzlab/synapse/client.rb +288 -0
- data/lib/brainzlab/synapse/provisioner.rb +44 -0
- data/lib/brainzlab/synapse.rb +270 -0
- data/lib/brainzlab/utilities/circuit_breaker.rb +261 -0
- data/lib/brainzlab/utilities/health_check.rb +294 -0
- data/lib/brainzlab/utilities/log_formatter.rb +254 -0
- data/lib/brainzlab/utilities/rate_limiter.rb +230 -0
- data/lib/brainzlab/utilities.rb +17 -0
- data/lib/brainzlab/vault/cache.rb +80 -0
- data/lib/brainzlab/vault/client.rb +196 -0
- data/lib/brainzlab/vault/provisioner.rb +49 -0
- data/lib/brainzlab/vault.rb +262 -0
- data/lib/brainzlab/version.rb +1 -1
- data/lib/brainzlab/vision/client.rb +128 -0
- data/lib/brainzlab/vision/provisioner.rb +136 -0
- data/lib/brainzlab/vision.rb +155 -0
- data/lib/brainzlab-sdk.rb +1 -1
- data/lib/brainzlab.rb +112 -13
- data/lib/generators/brainzlab/install/install_generator.rb +29 -27
- metadata +60 -1
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'nerve/client'
|
|
4
|
+
require_relative 'nerve/provisioner'
|
|
5
|
+
|
|
6
|
+
module BrainzLab
|
|
7
|
+
module Nerve
|
|
8
|
+
class << self
|
|
9
|
+
# Report a completed job
|
|
10
|
+
# @param job_class [String] Job class name
|
|
11
|
+
# @param job_id [String] Job ID
|
|
12
|
+
# @param queue [String] Queue name
|
|
13
|
+
# @param started_at [Time] When job started
|
|
14
|
+
# @param ended_at [Time] When job ended (defaults to now)
|
|
15
|
+
# @param attributes [Hash] Additional attributes
|
|
16
|
+
#
|
|
17
|
+
# @example
|
|
18
|
+
# BrainzLab::Nerve.report_success(
|
|
19
|
+
# job_class: "ProcessOrderJob",
|
|
20
|
+
# job_id: "abc-123",
|
|
21
|
+
# queue: "default",
|
|
22
|
+
# started_at: 1.minute.ago
|
|
23
|
+
# )
|
|
24
|
+
#
|
|
25
|
+
def report_success(job_class:, job_id:, queue:, started_at:, ended_at: Time.now, **attributes)
|
|
26
|
+
return false unless enabled?
|
|
27
|
+
|
|
28
|
+
ensure_provisioned!
|
|
29
|
+
return false unless BrainzLab.configuration.nerve_valid?
|
|
30
|
+
|
|
31
|
+
client.report_job(
|
|
32
|
+
job_class: job_class,
|
|
33
|
+
job_id: job_id,
|
|
34
|
+
queue: queue,
|
|
35
|
+
status: 'completed',
|
|
36
|
+
started_at: started_at,
|
|
37
|
+
ended_at: ended_at,
|
|
38
|
+
**attributes
|
|
39
|
+
)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Report a failed job
|
|
43
|
+
def report_failure(job_class:, job_id:, queue:, error:, started_at: nil, **attributes)
|
|
44
|
+
return false unless enabled?
|
|
45
|
+
|
|
46
|
+
ensure_provisioned!
|
|
47
|
+
return false unless BrainzLab.configuration.nerve_valid?
|
|
48
|
+
|
|
49
|
+
client.report_failure(
|
|
50
|
+
job_class: job_class,
|
|
51
|
+
job_id: job_id,
|
|
52
|
+
queue: queue,
|
|
53
|
+
error_class: error.class.name,
|
|
54
|
+
error_message: error.message,
|
|
55
|
+
backtrace: error.backtrace,
|
|
56
|
+
started_at: started_at,
|
|
57
|
+
**attributes
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Report a job that's currently running
|
|
62
|
+
def report_started(job_class:, job_id:, queue:, **attributes)
|
|
63
|
+
return false unless enabled?
|
|
64
|
+
|
|
65
|
+
ensure_provisioned!
|
|
66
|
+
return false unless BrainzLab.configuration.nerve_valid?
|
|
67
|
+
|
|
68
|
+
client.report_job(
|
|
69
|
+
job_class: job_class,
|
|
70
|
+
job_id: job_id,
|
|
71
|
+
queue: queue,
|
|
72
|
+
status: 'running',
|
|
73
|
+
started_at: Time.now,
|
|
74
|
+
ended_at: Time.now,
|
|
75
|
+
**attributes
|
|
76
|
+
)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Get job statistics
|
|
80
|
+
# @param queue [String] Filter by queue (optional)
|
|
81
|
+
# @param job_class [String] Filter by job class (optional)
|
|
82
|
+
# @param period [String] Time period: "1h", "24h", "7d", "30d"
|
|
83
|
+
def stats(queue: nil, job_class: nil, period: '1h')
|
|
84
|
+
return nil unless enabled?
|
|
85
|
+
|
|
86
|
+
ensure_provisioned!
|
|
87
|
+
return nil unless BrainzLab.configuration.nerve_valid?
|
|
88
|
+
|
|
89
|
+
client.stats(queue: queue, job_class: job_class, period: period)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# List recent jobs
|
|
93
|
+
def jobs(queue: nil, status: nil, limit: 100)
|
|
94
|
+
return [] unless enabled?
|
|
95
|
+
|
|
96
|
+
ensure_provisioned!
|
|
97
|
+
return [] unless BrainzLab.configuration.nerve_valid?
|
|
98
|
+
|
|
99
|
+
client.list_jobs(queue: queue, status: status, limit: limit)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# List all queues
|
|
103
|
+
def queues
|
|
104
|
+
return [] unless enabled?
|
|
105
|
+
|
|
106
|
+
ensure_provisioned!
|
|
107
|
+
return [] unless BrainzLab.configuration.nerve_valid?
|
|
108
|
+
|
|
109
|
+
client.list_queues
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Get queue details
|
|
113
|
+
def queue(name)
|
|
114
|
+
return nil unless enabled?
|
|
115
|
+
|
|
116
|
+
ensure_provisioned!
|
|
117
|
+
return nil unless BrainzLab.configuration.nerve_valid?
|
|
118
|
+
|
|
119
|
+
client.get_queue(name)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Retry a failed job
|
|
123
|
+
def retry(job_id)
|
|
124
|
+
return false unless enabled?
|
|
125
|
+
|
|
126
|
+
ensure_provisioned!
|
|
127
|
+
return false unless BrainzLab.configuration.nerve_valid?
|
|
128
|
+
|
|
129
|
+
client.retry_job(job_id)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Delete a job
|
|
133
|
+
def delete(job_id)
|
|
134
|
+
return false unless enabled?
|
|
135
|
+
|
|
136
|
+
ensure_provisioned!
|
|
137
|
+
return false unless BrainzLab.configuration.nerve_valid?
|
|
138
|
+
|
|
139
|
+
client.delete_job(job_id)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Report queue metrics (for custom job backends)
|
|
143
|
+
def report_metrics(queue:, size:, latency_ms: nil, workers: nil)
|
|
144
|
+
return false unless enabled?
|
|
145
|
+
|
|
146
|
+
ensure_provisioned!
|
|
147
|
+
return false unless BrainzLab.configuration.nerve_valid?
|
|
148
|
+
|
|
149
|
+
client.report_metrics(
|
|
150
|
+
queue: queue,
|
|
151
|
+
size: size,
|
|
152
|
+
latency_ms: latency_ms,
|
|
153
|
+
workers: workers
|
|
154
|
+
)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Track a job execution (block helper)
|
|
158
|
+
# @example
|
|
159
|
+
# BrainzLab::Nerve.track(job_class: "MyJob", job_id: "123", queue: "default") do
|
|
160
|
+
# # job work
|
|
161
|
+
# end
|
|
162
|
+
#
|
|
163
|
+
def track(job_class:, job_id:, queue: 'default', **attributes)
|
|
164
|
+
started_at = Time.now
|
|
165
|
+
|
|
166
|
+
begin
|
|
167
|
+
result = yield
|
|
168
|
+
report_success(
|
|
169
|
+
job_class: job_class,
|
|
170
|
+
job_id: job_id,
|
|
171
|
+
queue: queue,
|
|
172
|
+
started_at: started_at,
|
|
173
|
+
**attributes
|
|
174
|
+
)
|
|
175
|
+
result
|
|
176
|
+
rescue StandardError => e
|
|
177
|
+
report_failure(
|
|
178
|
+
job_class: job_class,
|
|
179
|
+
job_id: job_id,
|
|
180
|
+
queue: queue,
|
|
181
|
+
error: e,
|
|
182
|
+
started_at: started_at,
|
|
183
|
+
**attributes
|
|
184
|
+
)
|
|
185
|
+
raise
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# === INTERNAL ===
|
|
190
|
+
|
|
191
|
+
def ensure_provisioned!
|
|
192
|
+
return if @provisioned
|
|
193
|
+
|
|
194
|
+
@provisioned = true
|
|
195
|
+
provisioner.ensure_project!
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def provisioner
|
|
199
|
+
@provisioner ||= Provisioner.new(BrainzLab.configuration)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def client
|
|
203
|
+
@client ||= Client.new(BrainzLab.configuration)
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def reset!
|
|
207
|
+
@client = nil
|
|
208
|
+
@provisioner = nil
|
|
209
|
+
@provisioned = false
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
private
|
|
213
|
+
|
|
214
|
+
def enabled?
|
|
215
|
+
BrainzLab.configuration.nerve_enabled
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
end
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require
|
|
3
|
+
require 'net/http'
|
|
4
|
+
require 'uri'
|
|
5
|
+
require 'json'
|
|
6
6
|
|
|
7
7
|
module BrainzLab
|
|
8
8
|
module Pulse
|
|
@@ -23,7 +23,7 @@ module BrainzLab
|
|
|
23
23
|
if @config.pulse_buffer_size > 1
|
|
24
24
|
buffer_trace(payload)
|
|
25
25
|
else
|
|
26
|
-
post(
|
|
26
|
+
post('/api/v1/traces', payload)
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
|
|
@@ -31,13 +31,13 @@ module BrainzLab
|
|
|
31
31
|
return unless @config.pulse_enabled && @config.pulse_valid?
|
|
32
32
|
return if payloads.empty?
|
|
33
33
|
|
|
34
|
-
post(
|
|
34
|
+
post('/api/v1/traces/batch', { traces: payloads })
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
def send_metric(payload)
|
|
38
38
|
return unless @config.pulse_enabled && @config.pulse_valid?
|
|
39
39
|
|
|
40
|
-
post(
|
|
40
|
+
post('/api/v1/metrics', payload)
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
def flush
|
|
@@ -79,9 +79,9 @@ module BrainzLab
|
|
|
79
79
|
def post(path, body)
|
|
80
80
|
uri = URI.join(@config.pulse_url, path)
|
|
81
81
|
request = Net::HTTP::Post.new(uri)
|
|
82
|
-
request[
|
|
83
|
-
request[
|
|
84
|
-
request[
|
|
82
|
+
request['Content-Type'] = 'application/json'
|
|
83
|
+
request['Authorization'] = "Bearer #{@config.pulse_auth_key}"
|
|
84
|
+
request['User-Agent'] = "brainzlab-sdk-ruby/#{BrainzLab::VERSION}"
|
|
85
85
|
request.body = JSON.generate(body)
|
|
86
86
|
|
|
87
87
|
execute_with_retry(uri, request)
|
|
@@ -94,7 +94,7 @@ module BrainzLab
|
|
|
94
94
|
retries = 0
|
|
95
95
|
begin
|
|
96
96
|
http = Net::HTTP.new(uri.host, uri.port)
|
|
97
|
-
http.use_ssl = uri.scheme ==
|
|
97
|
+
http.use_ssl = uri.scheme == 'https'
|
|
98
98
|
http.open_timeout = 5
|
|
99
99
|
http.read_timeout = 10
|
|
100
100
|
|
|
@@ -102,7 +102,11 @@ module BrainzLab
|
|
|
102
102
|
|
|
103
103
|
case response.code.to_i
|
|
104
104
|
when 200..299
|
|
105
|
-
|
|
105
|
+
begin
|
|
106
|
+
JSON.parse(response.body)
|
|
107
|
+
rescue StandardError
|
|
108
|
+
{}
|
|
109
|
+
end
|
|
106
110
|
when 429, 500..599
|
|
107
111
|
raise RetryableError, "Server error: #{response.code}"
|
|
108
112
|
else
|
|
@@ -22,20 +22,23 @@ module BrainzLab
|
|
|
22
22
|
def install_active_record!
|
|
23
23
|
return unless defined?(ActiveRecord)
|
|
24
24
|
|
|
25
|
-
ActiveSupport::Notifications.subscribe(
|
|
25
|
+
ActiveSupport::Notifications.subscribe('sql.active_record') do |*args|
|
|
26
26
|
event = ActiveSupport::Notifications::Event.new(*args)
|
|
27
27
|
next if skip_query?(event.payload)
|
|
28
28
|
|
|
29
|
+
sql = event.payload[:sql]
|
|
29
30
|
record_span(
|
|
30
|
-
name: event.payload[:name] ||
|
|
31
|
-
kind:
|
|
31
|
+
name: event.payload[:name] || 'SQL',
|
|
32
|
+
kind: 'db',
|
|
32
33
|
started_at: event.time,
|
|
33
34
|
ended_at: event.end,
|
|
34
35
|
duration_ms: event.duration,
|
|
35
36
|
data: {
|
|
36
|
-
sql: truncate_sql(
|
|
37
|
+
sql: truncate_sql(sql),
|
|
37
38
|
name: event.payload[:name],
|
|
38
|
-
cached: event.payload[:cached] || false
|
|
39
|
+
cached: event.payload[:cached] || false,
|
|
40
|
+
table: extract_table(sql),
|
|
41
|
+
operation: extract_operation(sql)
|
|
39
42
|
}
|
|
40
43
|
)
|
|
41
44
|
end
|
|
@@ -45,12 +48,12 @@ module BrainzLab
|
|
|
45
48
|
def install_action_view!
|
|
46
49
|
return unless defined?(ActionView)
|
|
47
50
|
|
|
48
|
-
ActiveSupport::Notifications.subscribe(
|
|
51
|
+
ActiveSupport::Notifications.subscribe('render_template.action_view') do |*args|
|
|
49
52
|
event = ActiveSupport::Notifications::Event.new(*args)
|
|
50
53
|
|
|
51
54
|
record_span(
|
|
52
55
|
name: short_path(event.payload[:identifier]),
|
|
53
|
-
kind:
|
|
56
|
+
kind: 'render',
|
|
54
57
|
started_at: event.time,
|
|
55
58
|
ended_at: event.end,
|
|
56
59
|
duration_ms: event.duration,
|
|
@@ -61,12 +64,12 @@ module BrainzLab
|
|
|
61
64
|
)
|
|
62
65
|
end
|
|
63
66
|
|
|
64
|
-
ActiveSupport::Notifications.subscribe(
|
|
67
|
+
ActiveSupport::Notifications.subscribe('render_partial.action_view') do |*args|
|
|
65
68
|
event = ActiveSupport::Notifications::Event.new(*args)
|
|
66
69
|
|
|
67
70
|
record_span(
|
|
68
71
|
name: short_path(event.payload[:identifier]),
|
|
69
|
-
kind:
|
|
72
|
+
kind: 'render',
|
|
70
73
|
started_at: event.time,
|
|
71
74
|
ended_at: event.end,
|
|
72
75
|
duration_ms: event.duration,
|
|
@@ -77,12 +80,12 @@ module BrainzLab
|
|
|
77
80
|
)
|
|
78
81
|
end
|
|
79
82
|
|
|
80
|
-
ActiveSupport::Notifications.subscribe(
|
|
83
|
+
ActiveSupport::Notifications.subscribe('render_collection.action_view') do |*args|
|
|
81
84
|
event = ActiveSupport::Notifications::Event.new(*args)
|
|
82
85
|
|
|
83
86
|
record_span(
|
|
84
87
|
name: short_path(event.payload[:identifier]),
|
|
85
|
-
kind:
|
|
88
|
+
kind: 'render',
|
|
86
89
|
started_at: event.time,
|
|
87
90
|
ended_at: event.end,
|
|
88
91
|
duration_ms: event.duration,
|
|
@@ -100,11 +103,11 @@ module BrainzLab
|
|
|
100
103
|
%w[cache_read.active_support cache_write.active_support cache_delete.active_support].each do |event_name|
|
|
101
104
|
ActiveSupport::Notifications.subscribe(event_name) do |*args|
|
|
102
105
|
event = ActiveSupport::Notifications::Event.new(*args)
|
|
103
|
-
operation = event_name.split(
|
|
106
|
+
operation = event_name.split('.').first.sub('cache_', '')
|
|
104
107
|
|
|
105
108
|
record_span(
|
|
106
109
|
name: "Cache #{operation}",
|
|
107
|
-
kind:
|
|
110
|
+
kind: 'cache',
|
|
108
111
|
started_at: event.time,
|
|
109
112
|
ended_at: event.end,
|
|
110
113
|
duration_ms: event.duration,
|
|
@@ -122,7 +125,7 @@ module BrainzLab
|
|
|
122
125
|
def install_action_controller!
|
|
123
126
|
return unless defined?(ActionController)
|
|
124
127
|
|
|
125
|
-
ActiveSupport::Notifications.subscribe(
|
|
128
|
+
ActiveSupport::Notifications.subscribe('process_action.action_controller') do |*args|
|
|
126
129
|
event = ActiveSupport::Notifications::Event.new(*args)
|
|
127
130
|
payload = event.payload
|
|
128
131
|
|
|
@@ -138,12 +141,12 @@ module BrainzLab
|
|
|
138
141
|
def install_http_clients!
|
|
139
142
|
# Net::HTTP instrumentation
|
|
140
143
|
if defined?(Net::HTTP)
|
|
141
|
-
ActiveSupport::Notifications.subscribe(
|
|
144
|
+
ActiveSupport::Notifications.subscribe('request.net_http') do |*args|
|
|
142
145
|
event = ActiveSupport::Notifications::Event.new(*args)
|
|
143
146
|
|
|
144
147
|
record_span(
|
|
145
148
|
name: "HTTP #{event.payload[:method]} #{event.payload[:host]}",
|
|
146
|
-
kind:
|
|
149
|
+
kind: 'http',
|
|
147
150
|
started_at: event.time,
|
|
148
151
|
ended_at: event.end,
|
|
149
152
|
duration_ms: event.duration,
|
|
@@ -158,26 +161,26 @@ module BrainzLab
|
|
|
158
161
|
end
|
|
159
162
|
|
|
160
163
|
# Faraday instrumentation
|
|
161
|
-
|
|
162
|
-
ActiveSupport::Notifications.subscribe("request.faraday") do |*args|
|
|
163
|
-
event = ActiveSupport::Notifications::Event.new(*args)
|
|
164
|
-
env = event.payload[:env]
|
|
165
|
-
next unless env
|
|
164
|
+
return unless defined?(Faraday)
|
|
166
165
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
166
|
+
ActiveSupport::Notifications.subscribe('request.faraday') do |*args|
|
|
167
|
+
event = ActiveSupport::Notifications::Event.new(*args)
|
|
168
|
+
env = event.payload[:env]
|
|
169
|
+
next unless env
|
|
170
|
+
|
|
171
|
+
record_span(
|
|
172
|
+
name: "HTTP #{env.method.to_s.upcase} #{env.url.host}",
|
|
173
|
+
kind: 'http',
|
|
174
|
+
started_at: event.time,
|
|
175
|
+
ended_at: event.end,
|
|
176
|
+
duration_ms: event.duration,
|
|
177
|
+
data: {
|
|
178
|
+
method: env.method.to_s.upcase,
|
|
179
|
+
host: env.url.host,
|
|
180
|
+
path: env.url.path,
|
|
181
|
+
status: env.status
|
|
182
|
+
}
|
|
183
|
+
)
|
|
181
184
|
end
|
|
182
185
|
end
|
|
183
186
|
|
|
@@ -186,13 +189,13 @@ module BrainzLab
|
|
|
186
189
|
return unless defined?(ActiveJob)
|
|
187
190
|
|
|
188
191
|
# Track job enqueuing
|
|
189
|
-
ActiveSupport::Notifications.subscribe(
|
|
192
|
+
ActiveSupport::Notifications.subscribe('enqueue.active_job') do |*args|
|
|
190
193
|
event = ActiveSupport::Notifications::Event.new(*args)
|
|
191
194
|
job = event.payload[:job]
|
|
192
195
|
|
|
193
196
|
record_span(
|
|
194
197
|
name: "Enqueue #{job.class.name}",
|
|
195
|
-
kind:
|
|
198
|
+
kind: 'job',
|
|
196
199
|
started_at: event.time,
|
|
197
200
|
ended_at: event.end,
|
|
198
201
|
duration_ms: event.duration,
|
|
@@ -205,14 +208,14 @@ module BrainzLab
|
|
|
205
208
|
end
|
|
206
209
|
|
|
207
210
|
# Track job retry
|
|
208
|
-
ActiveSupport::Notifications.subscribe(
|
|
211
|
+
ActiveSupport::Notifications.subscribe('retry_stopped.active_job') do |*args|
|
|
209
212
|
event = ActiveSupport::Notifications::Event.new(*args)
|
|
210
213
|
job = event.payload[:job]
|
|
211
214
|
error = event.payload[:error]
|
|
212
215
|
|
|
213
216
|
record_span(
|
|
214
217
|
name: "Retry stopped #{job.class.name}",
|
|
215
|
-
kind:
|
|
218
|
+
kind: 'job',
|
|
216
219
|
started_at: event.time,
|
|
217
220
|
ended_at: event.end,
|
|
218
221
|
duration_ms: event.duration,
|
|
@@ -229,14 +232,14 @@ module BrainzLab
|
|
|
229
232
|
end
|
|
230
233
|
|
|
231
234
|
# Track job discard
|
|
232
|
-
ActiveSupport::Notifications.subscribe(
|
|
235
|
+
ActiveSupport::Notifications.subscribe('discard.active_job') do |*args|
|
|
233
236
|
event = ActiveSupport::Notifications::Event.new(*args)
|
|
234
237
|
job = event.payload[:job]
|
|
235
238
|
error = event.payload[:error]
|
|
236
239
|
|
|
237
240
|
record_span(
|
|
238
241
|
name: "Discarded #{job.class.name}",
|
|
239
|
-
kind:
|
|
242
|
+
kind: 'job',
|
|
240
243
|
started_at: event.time,
|
|
241
244
|
ended_at: event.end,
|
|
242
245
|
duration_ms: event.duration,
|
|
@@ -257,12 +260,12 @@ module BrainzLab
|
|
|
257
260
|
def install_action_cable!
|
|
258
261
|
return unless defined?(ActionCable)
|
|
259
262
|
|
|
260
|
-
ActiveSupport::Notifications.subscribe(
|
|
263
|
+
ActiveSupport::Notifications.subscribe('perform_action.action_cable') do |*args|
|
|
261
264
|
event = ActiveSupport::Notifications::Event.new(*args)
|
|
262
265
|
|
|
263
266
|
record_span(
|
|
264
267
|
name: "Cable #{event.payload[:channel_class]}##{event.payload[:action]}",
|
|
265
|
-
kind:
|
|
268
|
+
kind: 'cable',
|
|
266
269
|
started_at: event.time,
|
|
267
270
|
ended_at: event.end,
|
|
268
271
|
duration_ms: event.duration,
|
|
@@ -273,12 +276,12 @@ module BrainzLab
|
|
|
273
276
|
)
|
|
274
277
|
end
|
|
275
278
|
|
|
276
|
-
ActiveSupport::Notifications.subscribe(
|
|
279
|
+
ActiveSupport::Notifications.subscribe('transmit.action_cable') do |*args|
|
|
277
280
|
event = ActiveSupport::Notifications::Event.new(*args)
|
|
278
281
|
|
|
279
282
|
record_span(
|
|
280
283
|
name: "Cable transmit #{event.payload[:channel_class]}",
|
|
281
|
-
kind:
|
|
284
|
+
kind: 'cable',
|
|
282
285
|
started_at: event.time,
|
|
283
286
|
ended_at: event.end,
|
|
284
287
|
duration_ms: event.duration,
|
|
@@ -289,12 +292,12 @@ module BrainzLab
|
|
|
289
292
|
)
|
|
290
293
|
end
|
|
291
294
|
|
|
292
|
-
ActiveSupport::Notifications.subscribe(
|
|
295
|
+
ActiveSupport::Notifications.subscribe('broadcast.action_cable') do |*args|
|
|
293
296
|
event = ActiveSupport::Notifications::Event.new(*args)
|
|
294
297
|
|
|
295
298
|
record_span(
|
|
296
299
|
name: "Cable broadcast #{event.payload[:broadcasting]}",
|
|
297
|
-
kind:
|
|
300
|
+
kind: 'cable',
|
|
298
301
|
started_at: event.time,
|
|
299
302
|
ended_at: event.end,
|
|
300
303
|
duration_ms: event.duration,
|
|
@@ -306,7 +309,8 @@ module BrainzLab
|
|
|
306
309
|
end
|
|
307
310
|
end
|
|
308
311
|
|
|
309
|
-
def record_span(name:, kind:, started_at:, ended_at:, duration_ms:, error: false, error_class: nil,
|
|
312
|
+
def record_span(name:, kind:, started_at:, ended_at:, duration_ms:, error: false, error_class: nil,
|
|
313
|
+
error_message: nil, data: {})
|
|
310
314
|
spans = Thread.current[:brainzlab_pulse_spans]
|
|
311
315
|
return unless spans
|
|
312
316
|
|
|
@@ -331,10 +335,10 @@ module BrainzLab
|
|
|
331
335
|
|
|
332
336
|
def skip_query?(payload)
|
|
333
337
|
# Skip SCHEMA queries and internal Rails queries
|
|
334
|
-
return true if payload[:name] ==
|
|
335
|
-
return true if payload[:name]&.start_with?(
|
|
336
|
-
return true if payload[:sql]&.include?(
|
|
337
|
-
return true if payload[:sql]&.include?(
|
|
338
|
+
return true if payload[:name] == 'SCHEMA'
|
|
339
|
+
return true if payload[:name]&.start_with?('EXPLAIN')
|
|
340
|
+
return true if payload[:sql]&.include?('pg_')
|
|
341
|
+
return true if payload[:sql]&.include?('information_schema')
|
|
338
342
|
return true if payload[:cached] && !include_cached_queries?
|
|
339
343
|
|
|
340
344
|
false
|
|
@@ -346,17 +350,50 @@ module BrainzLab
|
|
|
346
350
|
|
|
347
351
|
def truncate_sql(sql)
|
|
348
352
|
return nil unless sql
|
|
353
|
+
|
|
349
354
|
sql.to_s[0, 1000]
|
|
350
355
|
end
|
|
351
356
|
|
|
352
357
|
def truncate_key(key)
|
|
353
358
|
return nil unless key
|
|
359
|
+
|
|
354
360
|
key.to_s[0, 200]
|
|
355
361
|
end
|
|
356
362
|
|
|
357
363
|
def short_path(path)
|
|
358
364
|
return nil unless path
|
|
359
|
-
|
|
365
|
+
|
|
366
|
+
path.to_s.split('/').last(2).join('/')
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
def extract_table(sql)
|
|
370
|
+
return nil unless sql
|
|
371
|
+
|
|
372
|
+
# Match FROM "table" or FROM table patterns
|
|
373
|
+
# Also handles INSERT INTO, UPDATE, DELETE FROM
|
|
374
|
+
case sql.to_s
|
|
375
|
+
when /\bFROM\s+["'`]?(\w+)["'`]?/i
|
|
376
|
+
Regexp.last_match(1)
|
|
377
|
+
when /\bINTO\s+["'`]?(\w+)["'`]?/i
|
|
378
|
+
Regexp.last_match(1)
|
|
379
|
+
when /\bUPDATE\s+["'`]?(\w+)["'`]?/i
|
|
380
|
+
Regexp.last_match(1)
|
|
381
|
+
when /\bJOIN\s+["'`]?(\w+)["'`]?/i
|
|
382
|
+
Regexp.last_match(1)
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
def extract_operation(sql)
|
|
387
|
+
return nil unless sql
|
|
388
|
+
|
|
389
|
+
case sql.to_s.strip.upcase
|
|
390
|
+
when /\ASELECT/i then 'SELECT'
|
|
391
|
+
when /\AINSERT/i then 'INSERT'
|
|
392
|
+
when /\AUPDATE/i then 'UPDATE'
|
|
393
|
+
when /\ADELETE/i then 'DELETE'
|
|
394
|
+
when /\ABEGIN/i, /\ACOMMIT/i, /\AROLLBACK/i then 'TRANSACTION'
|
|
395
|
+
else 'QUERY'
|
|
396
|
+
end
|
|
360
397
|
end
|
|
361
398
|
end
|
|
362
399
|
end
|