dead_bro 0.2.10 → 0.2.13

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1ac04c555f3f82572e94327d09b90672869eb17c129deb87c78f746625cb5afd
4
- data.tar.gz: 4639f701e7bd5dff8b36933e85b405dbbe43a2ccc664c94f16b6e2ea98987fda
3
+ metadata.gz: 2c308968cd84cfa8df47974178b741ab2847809754e86dc49cbe716d07a7a0bb
4
+ data.tar.gz: 6cdfb10f1ac9b2ecd9994bf6f35d8468022dc024e16e9ab31c1664fa91db7041
5
5
  SHA512:
6
- metadata.gz: fee0d59a0362226babd057547b8138078d5ce3da4a75a3c5a2bbd175ee21b3043485e9f6c8e0b0a27a18c2373f10827fc7804f64c96888a41eea8d3c8eb8ea74
7
- data.tar.gz: 1e044e7a275a5e52843119e00488a8a458e6d6f95420543014edd1074985bcdeebe1cbeef579e436a4eb31836eb6f9e24961c039851c4c82b2b0a76184cf23d2
6
+ metadata.gz: 2a8f31655b9512739fa991ee94675c1f948c5ae2229dbb9de62a4e3c6ea0b5a8883ea880f986d911044e200d0c8ae6e696f6d8a58e5c338da6c8c3756c08e543
7
+ data.tar.gz: ddf1ed72e8310eb1f42db17f5124b704c5214447706ed68c1f9bae9f47f669fbf56006733f430a064af0fc8965be161dbb85bcaca2aee6b6c14a68b4865216f9
data/FEATURES.md CHANGED
@@ -284,12 +284,7 @@ A comprehensive feature list for comparing ApmBro with other APM (Application Pe
284
284
  ## Deployment & Environment
285
285
 
286
286
  ### Deploy Tracking
287
- - **Deploy ID Resolution**: Multiple sources for deploy identification
288
- - Explicit configuration
289
- - Rails settings/credentials
290
- - Environment variables (APM_BRO_DEPLOY_ID, GIT_REV)
291
- - Heroku (HEROKU_SLUG_COMMIT)
292
- - Process-stable UUID fallback
287
+ - **Deploy ID Resolution**: Multiple sources for deploy identification (`Configuration#deploy_id=` wins when set, then ENV in `Configuration::DEPLOY_REVISION_ENV_KEYS` order—including `DEAD_BRO_DEPLOY_ID`, git/CI vars, `DD_VERSION`, etc.), otherwise a **per-process UUID** (fine for single dyno/process; unusable alone for fleets like ECS replicas)
293
288
  - **Revision Tracking**: Includes deploy/revision ID in all metric payloads
294
289
 
295
290
  ### Environment Support
data/README.md CHANGED
@@ -30,6 +30,25 @@ end
30
30
 
31
31
  That is enough to start shipping metrics. Create or copy the key from your DeadBro account, then wire it into `DEAD_BRO_API_KEY` (or assign `config.api_key` directly).
32
32
 
33
+ ### Deploy / release tracking (ECS, Kubernetes, autoscaling groups)
34
+
35
+ DeadBro sends a **`revision`** string on every payload so charts and deploys group metrics by release. If you do **not** configure a stable value, the gem generates a UUID **once per Ruby process**. With multiple containers or EC2 instances, each replica then looks like a separate deployment.
36
+
37
+ **Use one shared identifier for every task in the same rollout**, for example:
38
+
39
+ - Set `DEAD_BRO_DEPLOY_ID` (or `dead_bro_DEPLOY_ID`) in the task definition / pod spec to your **git SHA**, **image digest**, or CD **release id** injected at build or deploy time.
40
+ - Or set it in Ruby (this wins over environment variables when non-blank):
41
+
42
+ ```ruby
43
+ DeadBro.configure do |config|
44
+ config.deploy_id = ENV.fetch("GIT_SHA") { raise "Set GIT_SHA in the task definition" }
45
+ end
46
+ ```
47
+
48
+ The gem also checks these environment variables in order (first non-empty wins): `DEAD_BRO_DEPLOY_ID`, `dead_bro_DEPLOY_ID`, `GIT_REV`, `GIT_COMMIT`, `GIT_COMMIT_SHA`, `GIT_SHA`, `CODEBUILD_RESOLVED_SOURCE_REVISION`, `HEROKU_SLUG_COMMIT`, `RENDER_GIT_COMMIT`, `DD_VERSION`, `APP_REVISION`, `RELEASE_VERSION`, `SOURCE_VERSION`.
49
+
50
+ For **Amazon ECS**, add one of these variables in your task definition from CodeBuild, GitHub Actions, or your pipeline so all tasks in the service share the same value for that image version.
51
+
33
52
  ### Dashboard configuration
34
53
 
35
54
  Use the DeadBro UI to turn features on or off, set sample rates, define controller/job inclusions and exclusions, tune slow-query EXPLAIN, enable queue and system metrics, and adjust related limits. After you deploy the initializer above, those choices take effect when the gem receives them from the API (typically on the next successful metric or heartbeat response).
@@ -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
@@ -7,7 +7,7 @@ module DeadBro
7
7
  # returns it in a response; local configure() values apply until the next remote update.
8
8
  attr_accessor :api_key, :open_timeout, :read_timeout, :enabled, :ruby_dev,
9
9
  :circuit_breaker_enabled, :circuit_breaker_failure_threshold, :circuit_breaker_recovery_timeout,
10
- :circuit_breaker_retry_timeout, :deploy_id, :disk_paths, :interfaces_ignore
10
+ :circuit_breaker_retry_timeout, :disk_paths, :interfaces_ignore
11
11
 
12
12
  # Remote-managed settings (overwritten by backend JSON `settings` on successful API responses)
13
13
  attr_accessor :memory_tracking_enabled, :allocation_tracking_enabled,
@@ -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,26 @@ module DeadBro
30
34
 
31
35
  HEARTBEAT_INTERVAL = 60 # seconds
32
36
 
37
+ METRICS_BACKEND_SKIP_AFTER_507_SECONDS = 600 # 10 minutes
38
+
39
+ # First non-empty ENV value wins for release/revision payloads and deploy grouping on the server.
40
+ # Order is roughly: DeadBro-native → common CI/hosting → observability tooling.
41
+ DEPLOY_REVISION_ENV_KEYS = %w[
42
+ DEAD_BRO_DEPLOY_ID
43
+ dead_bro_DEPLOY_ID
44
+ GIT_REV
45
+ GIT_COMMIT
46
+ GIT_COMMIT_SHA
47
+ GIT_SHA
48
+ CODEBUILD_RESOLVED_SOURCE_REVISION
49
+ HEROKU_SLUG_COMMIT
50
+ RENDER_GIT_COMMIT
51
+ DD_VERSION
52
+ APP_REVISION
53
+ RELEASE_VERSION
54
+ SOURCE_VERSION
55
+ ].freeze
56
+
33
57
  REMOTE_SETTING_KEYS = %w[
34
58
  enabled sample_rate memory_tracking_enabled allocation_tracking_enabled
35
59
  explain_analyze_enabled slow_query_threshold_ms max_sql_queries_to_send max_logs_to_send
@@ -47,7 +71,7 @@ module DeadBro
47
71
  @circuit_breaker_failure_threshold = 3
48
72
  @circuit_breaker_recovery_timeout = 60
49
73
  @circuit_breaker_retry_timeout = 300
50
- @deploy_id = resolve_deploy_id
74
+ @explicit_deploy_revision = nil
51
75
  @disk_paths = ["/"]
52
76
  @interfaces_ignore = %w[lo lo0 docker0]
53
77
 
@@ -69,11 +93,23 @@ module DeadBro
69
93
  @enable_system_stats = false
70
94
 
71
95
  @settings_received_at = nil
96
+ @skip_until = nil
72
97
  @last_heartbeat_at = nil
73
98
  @last_heartbeat_attempt_at = nil
74
99
  @settings_mutex = Mutex.new
75
100
  end
76
101
 
102
+ # Current release revision sent as `revision` on all API payloads — same semantics as `#resolve_deploy_id`.
103
+ def deploy_id
104
+ resolve_deploy_id
105
+ end
106
+
107
+ # Overrides ENV-based resolution when set to a non-empty string (or clears override when nil/blank).
108
+ def deploy_id=(value)
109
+ s = value&.respond_to?(:to_s) ? value.to_s.strip : ""
110
+ @explicit_deploy_revision = s.empty? ? nil : s
111
+ end
112
+
77
113
  def excluded_controllers=(value)
78
114
  @excluded_controllers = Array(value).map(&:to_s)
79
115
  @compiled_excluded_controllers = compile_patterns(@excluded_controllers)
@@ -123,8 +159,28 @@ module DeadBro
123
159
  last_heartbeat_attempt_at.nil? || (Time.now.utc - last_heartbeat_attempt_at) >= HEARTBEAT_INTERVAL
124
160
  end
125
161
 
162
+ def skip_tracking?
163
+ t = skip_until
164
+ return false unless t
165
+
166
+ Time.now.utc < t
167
+ end
168
+
126
169
  def resolve_deploy_id
127
- ENV["dead_bro_DEPLOY_ID"] || ENV["GIT_REV"] || ENV["HEROKU_SLUG_COMMIT"] || DeadBro.process_deploy_id
170
+ explicit = @explicit_deploy_revision&.to_s&.strip
171
+ return explicit unless explicit.nil? || explicit.empty?
172
+
173
+ DEPLOY_REVISION_ENV_KEYS.each do |key|
174
+ v = ENV[key]
175
+ next unless v.respond_to?(:to_s)
176
+
177
+ stripped = v.to_s.strip
178
+ next if stripped.empty?
179
+
180
+ return stripped
181
+ end
182
+
183
+ DeadBro.process_deploy_id
128
184
  end
129
185
 
130
186
  def excluded_controller?(controller_name, action_name = nil)
@@ -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
 
@@ -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
@@ -106,6 +111,11 @@ module DeadBro
106
111
  # Track job exceptions
107
112
  ActiveSupport::Notifications.subscribe(JOB_EXCEPTION_EVENT_NAME) do |name, started, finished, _unique_id, data|
108
113
  begin
114
+ if DeadBro.configuration.skip_tracking?
115
+ drain_job_tracking
116
+ next
117
+ end
118
+
109
119
  job_class_name = data[:job].class.name
110
120
  if DeadBro.configuration.excluded_job?(job_class_name)
111
121
  next
@@ -215,7 +225,7 @@ module DeadBro
215
225
  (arg.length > 200) ? arg[0, 200] + "..." : arg
216
226
  when Hash
217
227
  # Filter sensitive keys and limit size
218
- filtered = arg.except(*%w[password token secret key])
228
+ filtered = arg.reject { |k, _| %w[password token secret key].include?(k.to_s) }
219
229
  (filtered.keys.size > 20) ? filtered.first(20).to_h : filtered
220
230
  when Array
221
231
  arg.first(5)
@@ -7,6 +7,8 @@ module DeadBro
7
7
  end
8
8
 
9
9
  def call(env)
10
+ return @app.call(env) if DeadBro.configuration.skip_tracking?
11
+
10
12
  # Clear logs for this request
11
13
  DeadBro.logger.clear
12
14
 
@@ -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 : {}
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DeadBro
4
- VERSION = "0.2.10"
4
+ VERSION = "0.2.13"
5
5
  end
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.10
4
+ version: 0.2.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Emanuel Comsa
@@ -65,7 +65,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: 3.0.0
68
+ version: 2.7.0
69
69
  required_rubygems_version: !ruby/object:Gem::Requirement
70
70
  requirements:
71
71
  - - ">="