dead_bro 0.2.12 → 0.2.14
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/lib/dead_bro/client.rb +11 -3
- data/lib/dead_bro/configuration.rb +14 -0
- data/lib/dead_bro/db_connection_subscriber.rb +49 -0
- data/lib/dead_bro/job_sql_tracking_middleware.rb +7 -0
- data/lib/dead_bro/job_subscriber.rb +34 -1
- data/lib/dead_bro/railtie.rb +4 -0
- data/lib/dead_bro/sql_tracking_middleware.rb +47 -4
- data/lib/dead_bro/subscriber.rb +19 -0
- data/lib/dead_bro/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3f7618eda689dd41bbb5c71cdff40619e5857a71b31a182f234064d89197d79c
|
|
4
|
+
data.tar.gz: fbcac3f8c189834690a5a75e013f07cec20044f4e74285139aa22f66ae0cf65d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 68864135e9fd51e65293ee369f1002e6f37341627fd674d570781fa163dd5b2345a4e7421356f49bc2bc00c1b8f37946b7fe9d31ff0370a6781f892392c7ec5d
|
|
7
|
+
data.tar.gz: 5e72422ba6297af9ef9a521e675d832dd94a0f81783ae964be53ecdd16eaa96dd4bc55448baceb697ea1b0b4bfd024090009d43dd87a3893f197df607cc08fd4
|
data/lib/dead_bro/client.rb
CHANGED
|
@@ -15,11 +15,12 @@ module DeadBro
|
|
|
15
15
|
def post_metric(event_name:, payload:, force: false)
|
|
16
16
|
return if @configuration.api_key.nil?
|
|
17
17
|
return unless @configuration.enabled
|
|
18
|
+
return if @configuration.skip_tracking?
|
|
18
19
|
return if !force && !@configuration.should_sample?
|
|
19
20
|
return if circuit_open?
|
|
20
21
|
|
|
21
22
|
payload = truncate_payload_for_request(payload)
|
|
22
|
-
body = {event: event_name, payload: payload, sent_at: Time.now.utc.iso8601, revision: @configuration.resolve_deploy_id}
|
|
23
|
+
body = {event: event_name, payload: payload, sent_at: Time.now.utc.iso8601, revision: @configuration.resolve_deploy_id, gem_version: DeadBro::VERSION}
|
|
23
24
|
|
|
24
25
|
dispatch_request(
|
|
25
26
|
url: metrics_endpoint_url,
|
|
@@ -35,7 +36,7 @@ module DeadBro
|
|
|
35
36
|
return if @configuration.api_key.nil?
|
|
36
37
|
|
|
37
38
|
@configuration.last_heartbeat_attempt_at = Time.now.utc
|
|
38
|
-
body = {event: "heartbeat", payload: {}, sent_at: Time.now.utc.iso8601, revision: @configuration.resolve_deploy_id}
|
|
39
|
+
body = {event: "heartbeat", payload: {}, sent_at: Time.now.utc.iso8601, revision: @configuration.resolve_deploy_id, gem_version: DeadBro::VERSION}
|
|
39
40
|
|
|
40
41
|
dispatch_request(
|
|
41
42
|
url: metrics_endpoint_url,
|
|
@@ -50,10 +51,11 @@ module DeadBro
|
|
|
50
51
|
def post_monitor_stats(payload)
|
|
51
52
|
return if @configuration.api_key.nil?
|
|
52
53
|
return unless @configuration.enabled
|
|
54
|
+
return if @configuration.skip_tracking?
|
|
53
55
|
return unless @configuration.job_queue_monitoring_enabled
|
|
54
56
|
return if circuit_open?
|
|
55
57
|
|
|
56
|
-
body = {payload: payload, sent_at: Time.now.utc.iso8601, revision: @configuration.resolve_deploy_id}
|
|
58
|
+
body = {payload: payload, sent_at: Time.now.utc.iso8601, revision: @configuration.resolve_deploy_id, gem_version: DeadBro::VERSION}
|
|
57
59
|
|
|
58
60
|
dispatch_request(
|
|
59
61
|
url: monitor_endpoint_url,
|
|
@@ -140,6 +142,12 @@ module DeadBro
|
|
|
140
142
|
@configuration.last_heartbeat_at = Time.now.utc
|
|
141
143
|
end
|
|
142
144
|
end
|
|
145
|
+
|
|
146
|
+
if response.is_a?(Net::HTTPSuccess)
|
|
147
|
+
@configuration.skip_until = nil
|
|
148
|
+
elsif response.is_a?(Net::HTTPInsufficientStorage)
|
|
149
|
+
@configuration.skip_until = Time.now.utc + DeadBro::Configuration::METRICS_BACKEND_SKIP_AFTER_507_SECONDS
|
|
150
|
+
end
|
|
143
151
|
elsif @circuit_breaker && @configuration.circuit_breaker_enabled
|
|
144
152
|
@circuit_breaker.record_failure
|
|
145
153
|
end
|
|
@@ -22,6 +22,10 @@ module DeadBro
|
|
|
22
22
|
# Tracks when we last received settings from the backend (in-memory only)
|
|
23
23
|
attr_accessor :settings_received_at
|
|
24
24
|
|
|
25
|
+
# After HTTP 507 Insufficient Storage from the API, skip all tracking until this
|
|
26
|
+
# UTC time (in-memory only). Cleared on the next successful API response.
|
|
27
|
+
attr_accessor :skip_until
|
|
28
|
+
|
|
25
29
|
# Last successful heartbeat HTTP response time while disabled (in-memory only)
|
|
26
30
|
attr_accessor :last_heartbeat_at
|
|
27
31
|
|
|
@@ -30,6 +34,8 @@ module DeadBro
|
|
|
30
34
|
|
|
31
35
|
HEARTBEAT_INTERVAL = 60 # seconds
|
|
32
36
|
|
|
37
|
+
METRICS_BACKEND_SKIP_AFTER_507_SECONDS = 600 # 10 minutes
|
|
38
|
+
|
|
33
39
|
# First non-empty ENV value wins for release/revision payloads and deploy grouping on the server.
|
|
34
40
|
# Order is roughly: DeadBro-native → common CI/hosting → observability tooling.
|
|
35
41
|
DEPLOY_REVISION_ENV_KEYS = %w[
|
|
@@ -87,6 +93,7 @@ module DeadBro
|
|
|
87
93
|
@enable_system_stats = false
|
|
88
94
|
|
|
89
95
|
@settings_received_at = nil
|
|
96
|
+
@skip_until = nil
|
|
90
97
|
@last_heartbeat_at = nil
|
|
91
98
|
@last_heartbeat_attempt_at = nil
|
|
92
99
|
@settings_mutex = Mutex.new
|
|
@@ -152,6 +159,13 @@ module DeadBro
|
|
|
152
159
|
last_heartbeat_attempt_at.nil? || (Time.now.utc - last_heartbeat_attempt_at) >= HEARTBEAT_INTERVAL
|
|
153
160
|
end
|
|
154
161
|
|
|
162
|
+
def skip_tracking?
|
|
163
|
+
t = skip_until
|
|
164
|
+
return false unless t
|
|
165
|
+
|
|
166
|
+
Time.now.utc < t
|
|
167
|
+
end
|
|
168
|
+
|
|
155
169
|
def resolve_deploy_id
|
|
156
170
|
explicit = @explicit_deploy_revision&.to_s&.strip
|
|
157
171
|
return explicit unless explicit.nil? || explicit.empty?
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DeadBro
|
|
4
|
+
module DbConnectionSubscriber
|
|
5
|
+
WAIT_KEY = :dead_bro_db_connection_wait_ms
|
|
6
|
+
COUNT_KEY = :dead_bro_db_connection_checkouts
|
|
7
|
+
|
|
8
|
+
# Prepended onto ConnectionPool so every checkout is timed.
|
|
9
|
+
# Only accumulates when a request is being tracked (thread-local is a Numeric).
|
|
10
|
+
module CheckoutInstrumentation
|
|
11
|
+
def checkout(*args)
|
|
12
|
+
return super unless Thread.current[DbConnectionSubscriber::WAIT_KEY].is_a?(Numeric)
|
|
13
|
+
|
|
14
|
+
# Initialize conn before calling super so the rescue block can tell whether
|
|
15
|
+
# checkout succeeded before timing code raised (avoids double-checkout).
|
|
16
|
+
conn = nil
|
|
17
|
+
t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
18
|
+
conn = super
|
|
19
|
+
Thread.current[DbConnectionSubscriber::WAIT_KEY] += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0) * 1000.0
|
|
20
|
+
Thread.current[DbConnectionSubscriber::COUNT_KEY] += 1
|
|
21
|
+
conn
|
|
22
|
+
rescue
|
|
23
|
+
conn || super
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.install!
|
|
28
|
+
return unless defined?(ActiveRecord::ConnectionAdapters::ConnectionPool)
|
|
29
|
+
return if ActiveRecord::ConnectionAdapters::ConnectionPool.ancestors.include?(CheckoutInstrumentation)
|
|
30
|
+
|
|
31
|
+
ActiveRecord::ConnectionAdapters::ConnectionPool.prepend(CheckoutInstrumentation)
|
|
32
|
+
rescue StandardError => e
|
|
33
|
+
warn "[DeadBro] DbConnectionSubscriber install failed: #{e.class}: #{e.message}"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.start_request_tracking
|
|
37
|
+
Thread.current[WAIT_KEY] = 0.0
|
|
38
|
+
Thread.current[COUNT_KEY] = 0
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.stop_request_tracking
|
|
42
|
+
wait_ms = Thread.current[WAIT_KEY]
|
|
43
|
+
checkouts = Thread.current[COUNT_KEY]
|
|
44
|
+
Thread.current[WAIT_KEY] = nil
|
|
45
|
+
Thread.current[COUNT_KEY] = nil
|
|
46
|
+
{ wait_ms: wait_ms&.round(2), checkouts: checkouts }
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -5,6 +5,8 @@ module DeadBro
|
|
|
5
5
|
def self.subscribe!
|
|
6
6
|
# Start SQL tracking when a job begins - use the start event, not the complete event
|
|
7
7
|
ActiveSupport::Notifications.subscribe("perform_start.active_job") do |name, started, finished, _unique_id, data|
|
|
8
|
+
next if DeadBro.configuration.skip_tracking?
|
|
9
|
+
|
|
8
10
|
# Clear logs for this job
|
|
9
11
|
DeadBro.logger.clear
|
|
10
12
|
|
|
@@ -22,6 +24,11 @@ module DeadBro
|
|
|
22
24
|
if DeadBro.configuration.allocation_tracking_enabled && defined?(DeadBro::MemoryTrackingSubscriber)
|
|
23
25
|
DeadBro::MemoryTrackingSubscriber.start_request_tracking
|
|
24
26
|
end
|
|
27
|
+
|
|
28
|
+
# Start DB connection pool wait tracking
|
|
29
|
+
if defined?(DeadBro::DbConnectionSubscriber)
|
|
30
|
+
DeadBro::DbConnectionSubscriber.start_request_tracking
|
|
31
|
+
end
|
|
25
32
|
end
|
|
26
33
|
rescue
|
|
27
34
|
# Never raise from instrumentation install
|
|
@@ -15,6 +15,11 @@ module DeadBro
|
|
|
15
15
|
# Track job execution
|
|
16
16
|
ActiveSupport::Notifications.subscribe(JOB_EVENT_NAME) do |name, started, finished, _unique_id, data|
|
|
17
17
|
begin
|
|
18
|
+
if DeadBro.configuration.skip_tracking?
|
|
19
|
+
drain_job_tracking
|
|
20
|
+
next
|
|
21
|
+
end
|
|
22
|
+
|
|
18
23
|
job_class_name = data[:job].class.name
|
|
19
24
|
if DeadBro.configuration.excluded_job?(job_class_name)
|
|
20
25
|
drain_job_tracking
|
|
@@ -38,6 +43,7 @@ module DeadBro
|
|
|
38
43
|
end
|
|
39
44
|
|
|
40
45
|
duration_ms = ((finished - started) * 1000.0).round(2)
|
|
46
|
+
queue_duration_ms = job_queue_duration_ms(data[:job], started)
|
|
41
47
|
|
|
42
48
|
# Ensure tracking was started (fallback if perform_start.active_job didn't fire)
|
|
43
49
|
# This handles job backends that don't emit perform_start events
|
|
@@ -45,6 +51,7 @@ module DeadBro
|
|
|
45
51
|
DeadBro.logger.clear
|
|
46
52
|
Thread.current[DeadBro::TRACKING_START_TIME_KEY] = Time.now
|
|
47
53
|
DeadBro::SqlSubscriber.start_request_tracking
|
|
54
|
+
DeadBro::DbConnectionSubscriber.start_request_tracking if defined?(DeadBro::DbConnectionSubscriber)
|
|
48
55
|
if DeadBro.configuration.allocation_tracking_enabled && defined?(DeadBro::MemoryTrackingSubscriber)
|
|
49
56
|
DeadBro::MemoryTrackingSubscriber.start_request_tracking
|
|
50
57
|
else
|
|
@@ -54,6 +61,7 @@ module DeadBro
|
|
|
54
61
|
|
|
55
62
|
# Get SQL queries executed during this job
|
|
56
63
|
sql_queries = DeadBro::SqlSubscriber.stop_request_tracking
|
|
64
|
+
db_connection_stats = defined?(DeadBro::DbConnectionSubscriber) ? DeadBro::DbConnectionSubscriber.stop_request_tracking : {}
|
|
57
65
|
|
|
58
66
|
# Stop memory tracking and get collected memory data
|
|
59
67
|
if DeadBro.configuration.allocation_tracking_enabled && defined?(DeadBro::MemoryTrackingSubscriber)
|
|
@@ -89,6 +97,9 @@ module DeadBro
|
|
|
89
97
|
queue_name: data[:job].queue_name,
|
|
90
98
|
arguments: safe_arguments(data[:job].arguments),
|
|
91
99
|
duration_ms: duration_ms,
|
|
100
|
+
queue_duration_ms: queue_duration_ms,
|
|
101
|
+
db_connection_wait_ms: db_connection_stats[:wait_ms],
|
|
102
|
+
db_connection_checkouts: db_connection_stats[:checkouts],
|
|
92
103
|
status: "completed",
|
|
93
104
|
sql_queries: sql_queries,
|
|
94
105
|
rails_env: DeadBro.env,
|
|
@@ -106,6 +117,11 @@ module DeadBro
|
|
|
106
117
|
# Track job exceptions
|
|
107
118
|
ActiveSupport::Notifications.subscribe(JOB_EXCEPTION_EVENT_NAME) do |name, started, finished, _unique_id, data|
|
|
108
119
|
begin
|
|
120
|
+
if DeadBro.configuration.skip_tracking?
|
|
121
|
+
drain_job_tracking
|
|
122
|
+
next
|
|
123
|
+
end
|
|
124
|
+
|
|
109
125
|
job_class_name = data[:job].class.name
|
|
110
126
|
if DeadBro.configuration.excluded_job?(job_class_name)
|
|
111
127
|
next
|
|
@@ -119,13 +135,14 @@ module DeadBro
|
|
|
119
135
|
|
|
120
136
|
duration_ms = ((finished - started) * 1000.0).round(2)
|
|
121
137
|
exception = data[:exception_object]
|
|
122
|
-
data[:job]
|
|
138
|
+
queue_duration_ms = job_queue_duration_ms(data[:job], started)
|
|
123
139
|
|
|
124
140
|
# Ensure tracking was started (fallback if perform_start.active_job didn't fire)
|
|
125
141
|
unless DeadBro::SqlSubscriber.tracking_active?
|
|
126
142
|
DeadBro.logger.clear
|
|
127
143
|
Thread.current[DeadBro::TRACKING_START_TIME_KEY] = Time.now
|
|
128
144
|
DeadBro::SqlSubscriber.start_request_tracking
|
|
145
|
+
DeadBro::DbConnectionSubscriber.start_request_tracking if defined?(DeadBro::DbConnectionSubscriber)
|
|
129
146
|
if DeadBro.configuration.allocation_tracking_enabled && defined?(DeadBro::MemoryTrackingSubscriber)
|
|
130
147
|
DeadBro::MemoryTrackingSubscriber.start_request_tracking
|
|
131
148
|
else
|
|
@@ -135,6 +152,7 @@ module DeadBro
|
|
|
135
152
|
|
|
136
153
|
# Get SQL queries executed during this job
|
|
137
154
|
sql_queries = DeadBro::SqlSubscriber.stop_request_tracking
|
|
155
|
+
db_connection_stats = defined?(DeadBro::DbConnectionSubscriber) ? DeadBro::DbConnectionSubscriber.stop_request_tracking : {}
|
|
138
156
|
|
|
139
157
|
# Stop memory tracking and get collected memory data
|
|
140
158
|
if DeadBro.configuration.allocation_tracking_enabled && defined?(DeadBro::MemoryTrackingSubscriber)
|
|
@@ -170,6 +188,9 @@ module DeadBro
|
|
|
170
188
|
queue_name: data[:job].queue_name,
|
|
171
189
|
arguments: safe_arguments(data[:job].arguments),
|
|
172
190
|
duration_ms: duration_ms,
|
|
191
|
+
queue_duration_ms: queue_duration_ms,
|
|
192
|
+
db_connection_wait_ms: db_connection_stats[:wait_ms],
|
|
193
|
+
db_connection_checkouts: db_connection_stats[:checkouts],
|
|
173
194
|
status: "failed",
|
|
174
195
|
sql_queries: sql_queries,
|
|
175
196
|
exception_class: exception&.class&.name,
|
|
@@ -195,6 +216,7 @@ module DeadBro
|
|
|
195
216
|
# build a payload (excluded job / sampled out). Matches Subscriber.drain_request_tracking.
|
|
196
217
|
def self.drain_job_tracking
|
|
197
218
|
DeadBro::SqlSubscriber.stop_request_tracking if defined?(DeadBro::SqlSubscriber)
|
|
219
|
+
DeadBro::DbConnectionSubscriber.stop_request_tracking if defined?(DeadBro::DbConnectionSubscriber)
|
|
198
220
|
DeadBro::LightweightMemoryTracker.stop_request_tracking if defined?(DeadBro::LightweightMemoryTracker)
|
|
199
221
|
if DeadBro.configuration.allocation_tracking_enabled && defined?(DeadBro::MemoryTrackingSubscriber)
|
|
200
222
|
DeadBro::MemoryTrackingSubscriber.stop_request_tracking
|
|
@@ -205,6 +227,17 @@ module DeadBro
|
|
|
205
227
|
|
|
206
228
|
private
|
|
207
229
|
|
|
230
|
+
def self.job_queue_duration_ms(job, perform_started)
|
|
231
|
+
enqueued_at = job.enqueued_at
|
|
232
|
+
return nil if enqueued_at.nil?
|
|
233
|
+
|
|
234
|
+
enqueued_time = enqueued_at.is_a?(Time) ? enqueued_at : Time.parse(enqueued_at.to_s)
|
|
235
|
+
diff_ms = ((perform_started - enqueued_time) * 1000.0).round(2)
|
|
236
|
+
diff_ms >= 0 ? diff_ms : nil
|
|
237
|
+
rescue
|
|
238
|
+
nil
|
|
239
|
+
end
|
|
240
|
+
|
|
208
241
|
def self.safe_arguments(arguments)
|
|
209
242
|
return [] unless arguments.is_a?(Array)
|
|
210
243
|
|
data/lib/dead_bro/railtie.rb
CHANGED
|
@@ -36,6 +36,10 @@ if defined?(Rails) && defined?(Rails::Railtie)
|
|
|
36
36
|
require "dead_bro/elasticsearch_subscriber"
|
|
37
37
|
DeadBro::ElasticsearchSubscriber.subscribe!
|
|
38
38
|
|
|
39
|
+
# Install DB connection pool wait tracking
|
|
40
|
+
require "dead_bro/db_connection_subscriber"
|
|
41
|
+
DeadBro::DbConnectionSubscriber.install!
|
|
42
|
+
|
|
39
43
|
# Install view rendering tracking
|
|
40
44
|
require "dead_bro/view_rendering_subscriber"
|
|
41
45
|
DeadBro::ViewRenderingSubscriber.subscribe!(client: shared_client)
|
|
@@ -7,6 +7,17 @@ module DeadBro
|
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
def call(env)
|
|
10
|
+
return @app.call(env) if DeadBro.configuration.skip_tracking?
|
|
11
|
+
|
|
12
|
+
# Capture rack entry time before any setup so middleware overhead is accurately measured.
|
|
13
|
+
rack_entry = Time.now
|
|
14
|
+
Thread.current[DeadBro::TRACKING_START_TIME_KEY] = rack_entry
|
|
15
|
+
|
|
16
|
+
# Queue time: gap between when the upstream proxy accepted the connection and when a Rack
|
|
17
|
+
# worker picked it up. Heroku sets X-Request-Start as "t=<microseconds>"; nginx typically
|
|
18
|
+
# uses "t=<seconds.ms>". Both are parsed below.
|
|
19
|
+
Thread.current[:dead_bro_queue_duration_ms] = parse_queue_start(env, rack_entry)
|
|
20
|
+
|
|
10
21
|
# Clear logs for this request
|
|
11
22
|
DeadBro.logger.clear
|
|
12
23
|
|
|
@@ -45,12 +56,14 @@ module DeadBro
|
|
|
45
56
|
DeadBro::ElasticsearchSubscriber.start_request_tracking
|
|
46
57
|
end
|
|
47
58
|
|
|
59
|
+
# Start DB connection pool wait tracking
|
|
60
|
+
if defined?(DeadBro::DbConnectionSubscriber)
|
|
61
|
+
DeadBro::DbConnectionSubscriber.start_request_tracking
|
|
62
|
+
end
|
|
63
|
+
|
|
48
64
|
# Start outgoing HTTP accumulation for this request
|
|
49
65
|
Thread.current[:dead_bro_http_events] = []
|
|
50
66
|
|
|
51
|
-
# Set tracking start time once for all subscribers (before starting any tracking)
|
|
52
|
-
Thread.current[DeadBro::TRACKING_START_TIME_KEY] = Time.now
|
|
53
|
-
|
|
54
67
|
@app.call(env)
|
|
55
68
|
ensure
|
|
56
69
|
# Clean up thread-local storage
|
|
@@ -79,10 +92,40 @@ module DeadBro
|
|
|
79
92
|
Thread.current[:dead_bro_lightweight_memory] = nil
|
|
80
93
|
end
|
|
81
94
|
|
|
82
|
-
# Clean up HTTP events, ES events, and tracking start time
|
|
95
|
+
# Clean up HTTP events, ES events, DB connection tracking, and tracking start time
|
|
83
96
|
Thread.current[:dead_bro_elasticsearch_events] = nil
|
|
84
97
|
Thread.current[:dead_bro_http_events] = nil
|
|
98
|
+
Thread.current[:dead_bro_queue_duration_ms] = nil
|
|
99
|
+
DeadBro::DbConnectionSubscriber.stop_request_tracking if defined?(DeadBro::DbConnectionSubscriber)
|
|
85
100
|
Thread.current[DeadBro::TRACKING_START_TIME_KEY] = nil
|
|
86
101
|
end
|
|
102
|
+
|
|
103
|
+
private
|
|
104
|
+
|
|
105
|
+
def parse_queue_start(env, rack_entry)
|
|
106
|
+
raw = env["HTTP_X_REQUEST_START"] || env["HTTP_X_QUEUE_START"]
|
|
107
|
+
return nil if raw.nil? || raw.empty?
|
|
108
|
+
|
|
109
|
+
# Strip "t=" prefix used by Heroku and nginx
|
|
110
|
+
raw = raw.sub(/\At=/, "")
|
|
111
|
+
num = raw.to_f
|
|
112
|
+
return nil if num <= 0
|
|
113
|
+
|
|
114
|
+
request_start =
|
|
115
|
+
if num > 1_000_000_000_000_000 # microseconds (Heroku)
|
|
116
|
+
Time.at(num / 1_000_000.0)
|
|
117
|
+
elsif num > 1_000_000_000_000 # milliseconds
|
|
118
|
+
Time.at(num / 1_000.0)
|
|
119
|
+
else # seconds (nginx)
|
|
120
|
+
Time.at(num)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Guard against clocks being out of sync or wildly misconfigured proxy timestamps.
|
|
124
|
+
# Cap at 60 s — anything larger almost certainly means the header value is wrong.
|
|
125
|
+
diff_ms = ((rack_entry - request_start) * 1000.0).round(2)
|
|
126
|
+
diff_ms >= 0 && diff_ms <= 60_000 ? diff_ms : nil
|
|
127
|
+
rescue
|
|
128
|
+
nil
|
|
129
|
+
end
|
|
87
130
|
end
|
|
88
131
|
end
|
data/lib/dead_bro/subscriber.rb
CHANGED
|
@@ -16,6 +16,12 @@ module DeadBro
|
|
|
16
16
|
next
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
+
if DeadBro.configuration.skip_tracking?
|
|
20
|
+
client.post_heartbeat if DeadBro.configuration.heartbeat_due?
|
|
21
|
+
drain_request_tracking
|
|
22
|
+
next
|
|
23
|
+
end
|
|
24
|
+
|
|
19
25
|
# Skip excluded controllers or controller#action pairs
|
|
20
26
|
# Also check exclusive_controller_actions - if defined, only track those
|
|
21
27
|
notification = data.is_a?(Hash) ? data : {}
|
|
@@ -43,6 +49,11 @@ module DeadBro
|
|
|
43
49
|
end
|
|
44
50
|
|
|
45
51
|
duration_ms = ((finished - started) * 1000.0).round(2)
|
|
52
|
+
|
|
53
|
+
# Time spent in Rack middleware before ActionController took over (routing, session, auth, etc.)
|
|
54
|
+
rack_start = Thread.current[DeadBro::TRACKING_START_TIME_KEY]
|
|
55
|
+
rack_duration_ms = rack_start ? ([((started - rack_start) * 1000.0), 0].max).round(2) : nil
|
|
56
|
+
|
|
46
57
|
# Stop SQL tracking and get collected queries (this was started by the request)
|
|
47
58
|
sql_queries = DeadBro::SqlSubscriber.stop_request_tracking
|
|
48
59
|
|
|
@@ -51,6 +62,9 @@ module DeadBro
|
|
|
51
62
|
redis_events = defined?(DeadBro::RedisSubscriber) ? DeadBro::RedisSubscriber.stop_request_tracking : []
|
|
52
63
|
elasticsearch_events = defined?(DeadBro::ElasticsearchSubscriber) ? DeadBro::ElasticsearchSubscriber.stop_request_tracking : []
|
|
53
64
|
|
|
65
|
+
# Stop DB connection pool wait tracking
|
|
66
|
+
db_connection_stats = defined?(DeadBro::DbConnectionSubscriber) ? DeadBro::DbConnectionSubscriber.stop_request_tracking : {}
|
|
67
|
+
|
|
54
68
|
# Stop view rendering tracking and get collected view events
|
|
55
69
|
view_events = DeadBro::ViewRenderingSubscriber.stop_request_tracking
|
|
56
70
|
view_performance = DeadBro::ViewRenderingSubscriber.analyze_view_performance(view_events)
|
|
@@ -160,6 +174,10 @@ module DeadBro
|
|
|
160
174
|
view_performance: view_performance,
|
|
161
175
|
memory_events: memory_events,
|
|
162
176
|
memory_performance: memory_performance,
|
|
177
|
+
rack_duration_ms: rack_duration_ms,
|
|
178
|
+
queue_duration_ms: Thread.current[:dead_bro_queue_duration_ms],
|
|
179
|
+
db_connection_wait_ms: db_connection_stats[:wait_ms],
|
|
180
|
+
db_connection_checkouts: db_connection_stats[:checkouts],
|
|
163
181
|
logs: DeadBro.logger.logs
|
|
164
182
|
}
|
|
165
183
|
client.post_metric(event_name: name, payload: payload)
|
|
@@ -180,6 +198,7 @@ module DeadBro
|
|
|
180
198
|
DeadBro::MemoryTrackingSubscriber.stop_request_tracking
|
|
181
199
|
end
|
|
182
200
|
Thread.current[:dead_bro_http_events] = nil
|
|
201
|
+
DeadBro::DbConnectionSubscriber.stop_request_tracking if defined?(DeadBro::DbConnectionSubscriber)
|
|
183
202
|
rescue
|
|
184
203
|
# Best effort — draining must never raise from the notifications callback.
|
|
185
204
|
end
|
data/lib/dead_bro/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dead_bro
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.14
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Emanuel Comsa
|
|
@@ -33,6 +33,7 @@ files:
|
|
|
33
33
|
- lib/dead_bro/collectors/sample_store.rb
|
|
34
34
|
- lib/dead_bro/collectors/system.rb
|
|
35
35
|
- lib/dead_bro/configuration.rb
|
|
36
|
+
- lib/dead_bro/db_connection_subscriber.rb
|
|
36
37
|
- lib/dead_bro/dispatcher.rb
|
|
37
38
|
- lib/dead_bro/elasticsearch_subscriber.rb
|
|
38
39
|
- lib/dead_bro/error_middleware.rb
|