Class: DeadBro::Configuration

Inherits:
Object
  • Object
show all
Defined in:
lib/dead_bro/configuration.rb

Constant Summary collapse

HEARTBEAT_INTERVAL =

seconds

60
DEPLOY_REVISION_ENV_KEYS =

First non-empty ENV value wins for release/revision payloads and deploy grouping on the server. Order is roughly: DeadBro-native → common CI/hosting → observability tooling.

%w[
  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
].freeze
REMOTE_SETTING_KEYS =
%w[
  enabled sample_rate memory_tracking_enabled allocation_tracking_enabled
  explain_analyze_enabled slow_query_threshold_ms max_sql_queries_to_send max_logs_to_send
  excluded_controllers excluded_jobs exclusive_controllers exclusive_jobs
  job_queue_monitoring_enabled enable_db_stats enable_process_stats enable_system_stats
].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeConfiguration

Returns a new instance of Configuration.



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/dead_bro/configuration.rb', line 58

def initialize
  @api_key = nil
  @open_timeout = 1.0
  @read_timeout = 1.0
  @enabled = true
  @ruby_dev = false
  @circuit_breaker_enabled = true
  @circuit_breaker_failure_threshold = 3
  @circuit_breaker_recovery_timeout = 60
  @circuit_breaker_retry_timeout = 300
  @explicit_deploy_revision = nil
  @disk_paths = ["/"]
  @interfaces_ignore = %w[lo lo0 docker0]

  # Remote-managed defaults (used until backend sends real values)
  @sample_rate = 100
  @memory_tracking_enabled = true
  @allocation_tracking_enabled = false
  @explain_analyze_enabled = false
  @slow_query_threshold_ms = 500
  @max_sql_queries_to_send = 500
  @max_logs_to_send = 100
  self.excluded_controllers = []
  self.excluded_jobs = []
  self.exclusive_controllers = []
  self.exclusive_jobs = []
  @job_queue_monitoring_enabled = false
  @enable_db_stats = false
  @enable_process_stats = false
  @enable_system_stats = false

  @settings_received_at = nil
  @last_heartbeat_at = nil
  @last_heartbeat_attempt_at = nil
  @settings_mutex = Mutex.new
end

Instance Attribute Details

#allocation_tracking_enabledObject

Remote-managed settings (overwritten by backend JSON ‘settings` on successful API responses)



13
14
15
# File 'lib/dead_bro/configuration.rb', line 13

def allocation_tracking_enabled
  @allocation_tracking_enabled
end

#api_keyObject

Local-only settings (not overwritten by API ‘settings` payloads). Note: `enabled` may still be updated remotely via apply_remote_settings when the backend returns it in a response; local configure() values apply until the next remote update.



8
9
10
# File 'lib/dead_bro/configuration.rb', line 8

def api_key
  @api_key
end

#circuit_breaker_enabledObject

Local-only settings (not overwritten by API ‘settings` payloads). Note: `enabled` may still be updated remotely via apply_remote_settings when the backend returns it in a response; local configure() values apply until the next remote update.



8
9
10
# File 'lib/dead_bro/configuration.rb', line 8

def circuit_breaker_enabled
  @circuit_breaker_enabled
end

#circuit_breaker_failure_thresholdObject

Local-only settings (not overwritten by API ‘settings` payloads). Note: `enabled` may still be updated remotely via apply_remote_settings when the backend returns it in a response; local configure() values apply until the next remote update.



8
9
10
# File 'lib/dead_bro/configuration.rb', line 8

def circuit_breaker_failure_threshold
  @circuit_breaker_failure_threshold
end

#circuit_breaker_recovery_timeoutObject

Local-only settings (not overwritten by API ‘settings` payloads). Note: `enabled` may still be updated remotely via apply_remote_settings when the backend returns it in a response; local configure() values apply until the next remote update.



8
9
10
# File 'lib/dead_bro/configuration.rb', line 8

def circuit_breaker_recovery_timeout
  @circuit_breaker_recovery_timeout
end

#circuit_breaker_retry_timeoutObject

Local-only settings (not overwritten by API ‘settings` payloads). Note: `enabled` may still be updated remotely via apply_remote_settings when the backend returns it in a response; local configure() values apply until the next remote update.



8
9
10
# File 'lib/dead_bro/configuration.rb', line 8

def circuit_breaker_retry_timeout
  @circuit_breaker_retry_timeout
end

#disk_pathsObject

Local-only settings (not overwritten by API ‘settings` payloads). Note: `enabled` may still be updated remotely via apply_remote_settings when the backend returns it in a response; local configure() values apply until the next remote update.



8
9
10
# File 'lib/dead_bro/configuration.rb', line 8

def disk_paths
  @disk_paths
end

#enable_db_statsObject

Remote-managed settings (overwritten by backend JSON ‘settings` on successful API responses)



13
14
15
# File 'lib/dead_bro/configuration.rb', line 13

def enable_db_stats
  @enable_db_stats
end

#enable_process_statsObject

Remote-managed settings (overwritten by backend JSON ‘settings` on successful API responses)



13
14
15
# File 'lib/dead_bro/configuration.rb', line 13

def enable_process_stats
  @enable_process_stats
end

#enable_system_statsObject

Remote-managed settings (overwritten by backend JSON ‘settings` on successful API responses)



13
14
15
# File 'lib/dead_bro/configuration.rb', line 13

def enable_system_stats
  @enable_system_stats
end

#enabledObject

Local-only settings (not overwritten by API ‘settings` payloads). Note: `enabled` may still be updated remotely via apply_remote_settings when the backend returns it in a response; local configure() values apply until the next remote update.



8
9
10
# File 'lib/dead_bro/configuration.rb', line 8

def enabled
  @enabled
end

#excluded_controllersObject

Readers for exclusion lists. Writers are defined below so we can compile and cache the regex form once, instead of rebuilding it per request.



20
21
22
# File 'lib/dead_bro/configuration.rb', line 20

def excluded_controllers
  @excluded_controllers
end

#excluded_jobsObject

Readers for exclusion lists. Writers are defined below so we can compile and cache the regex form once, instead of rebuilding it per request.



20
21
22
# File 'lib/dead_bro/configuration.rb', line 20

def excluded_jobs
  @excluded_jobs
end

#exclusive_controllersObject

Readers for exclusion lists. Writers are defined below so we can compile and cache the regex form once, instead of rebuilding it per request.



20
21
22
# File 'lib/dead_bro/configuration.rb', line 20

def exclusive_controllers
  @exclusive_controllers
end

#exclusive_jobsObject

Readers for exclusion lists. Writers are defined below so we can compile and cache the regex form once, instead of rebuilding it per request.



20
21
22
# File 'lib/dead_bro/configuration.rb', line 20

def exclusive_jobs
  @exclusive_jobs
end

#explain_analyze_enabledObject

Remote-managed settings (overwritten by backend JSON ‘settings` on successful API responses)



13
14
15
# File 'lib/dead_bro/configuration.rb', line 13

def explain_analyze_enabled
  @explain_analyze_enabled
end

#interfaces_ignoreObject

Local-only settings (not overwritten by API ‘settings` payloads). Note: `enabled` may still be updated remotely via apply_remote_settings when the backend returns it in a response; local configure() values apply until the next remote update.



8
9
10
# File 'lib/dead_bro/configuration.rb', line 8

def interfaces_ignore
  @interfaces_ignore
end

#job_queue_monitoring_enabledObject

Remote-managed settings (overwritten by backend JSON ‘settings` on successful API responses)



13
14
15
# File 'lib/dead_bro/configuration.rb', line 13

def job_queue_monitoring_enabled
  @job_queue_monitoring_enabled
end

#last_heartbeat_atObject

Last successful heartbeat HTTP response time while disabled (in-memory only)



26
27
28
# File 'lib/dead_bro/configuration.rb', line 26

def last_heartbeat_at
  @last_heartbeat_at
end

#last_heartbeat_attempt_atObject

Throttles heartbeat attempts to HEARTBEAT_INTERVAL (set when a heartbeat request is started)



29
30
31
# File 'lib/dead_bro/configuration.rb', line 29

def last_heartbeat_attempt_at
  @last_heartbeat_attempt_at
end

#max_logs_to_sendObject

Remote-managed settings (overwritten by backend JSON ‘settings` on successful API responses)



13
14
15
# File 'lib/dead_bro/configuration.rb', line 13

def max_logs_to_send
  @max_logs_to_send
end

#max_sql_queries_to_sendObject

Remote-managed settings (overwritten by backend JSON ‘settings` on successful API responses)



13
14
15
# File 'lib/dead_bro/configuration.rb', line 13

def max_sql_queries_to_send
  @max_sql_queries_to_send
end

#memory_tracking_enabledObject

Remote-managed settings (overwritten by backend JSON ‘settings` on successful API responses)



13
14
15
# File 'lib/dead_bro/configuration.rb', line 13

def memory_tracking_enabled
  @memory_tracking_enabled
end

#open_timeoutObject

Local-only settings (not overwritten by API ‘settings` payloads). Note: `enabled` may still be updated remotely via apply_remote_settings when the backend returns it in a response; local configure() values apply until the next remote update.



8
9
10
# File 'lib/dead_bro/configuration.rb', line 8

def open_timeout
  @open_timeout
end

#read_timeoutObject

Local-only settings (not overwritten by API ‘settings` payloads). Note: `enabled` may still be updated remotely via apply_remote_settings when the backend returns it in a response; local configure() values apply until the next remote update.



8
9
10
# File 'lib/dead_bro/configuration.rb', line 8

def read_timeout
  @read_timeout
end

#ruby_devObject

Local-only settings (not overwritten by API ‘settings` payloads). Note: `enabled` may still be updated remotely via apply_remote_settings when the backend returns it in a response; local configure() values apply until the next remote update.



8
9
10
# File 'lib/dead_bro/configuration.rb', line 8

def ruby_dev
  @ruby_dev
end

#sample_rateObject

Remote-managed settings (overwritten by backend JSON ‘settings` on successful API responses)



13
14
15
# File 'lib/dead_bro/configuration.rb', line 13

def sample_rate
  @sample_rate
end

#settings_received_atObject

Tracks when we last received settings from the backend (in-memory only)



23
24
25
# File 'lib/dead_bro/configuration.rb', line 23

def settings_received_at
  @settings_received_at
end

#slow_query_threshold_msObject

Remote-managed settings (overwritten by backend JSON ‘settings` on successful API responses)



13
14
15
# File 'lib/dead_bro/configuration.rb', line 13

def slow_query_threshold_ms
  @slow_query_threshold_ms
end

Instance Method Details

#apply_remote_settings(hash) ⇒ Object

Apply a settings hash received from the backend response. Only known keys are applied; unknown keys are silently ignored. Serialized so concurrent HTTP threads do not interleave writes with request-thread reads.



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/dead_bro/configuration.rb', line 129

def apply_remote_settings(hash)
  return unless hash.is_a?(Hash)

  @settings_mutex.synchronize do
    hash.each do |key, value|
      k = key.to_s
      next unless REMOTE_SETTING_KEYS.include?(k)

      case k
      when "sample_rate", "slow_query_threshold_ms", "max_sql_queries_to_send", "max_logs_to_send"
        send(:"#{k}=", value.to_i)
      when "enabled", "memory_tracking_enabled", "allocation_tracking_enabled", "explain_analyze_enabled",
           "job_queue_monitoring_enabled", "enable_db_stats", "enable_process_stats", "enable_system_stats"
        send(:"#{k}=", !!value)
      when "excluded_controllers", "excluded_jobs", "exclusive_controllers", "exclusive_jobs"
        send(:"#{k}=", Array(value).map(&:to_s))
      end
    end
  end
end

#deploy_idObject

Current release revision sent as ‘revision` on all API payloads — same semantics as `#resolve_deploy_id`.



96
97
98
# File 'lib/dead_bro/configuration.rb', line 96

def deploy_id
  resolve_deploy_id
end

#deploy_id=(value) ⇒ Object

Overrides ENV-based resolution when set to a non-empty string (or clears override when nil/blank).



101
102
103
104
# File 'lib/dead_bro/configuration.rb', line 101

def deploy_id=(value)
  s = value&.respond_to?(:to_s) ? value.to_s.strip : ""
  @explicit_deploy_revision = s.empty? ? nil : s
end

#excluded_controller?(controller_name, action_name = nil) ⇒ Boolean

Returns:

  • (Boolean)


172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/dead_bro/configuration.rb', line 172

def excluded_controller?(controller_name, action_name = nil)
  compiled = @compiled_excluded_controllers
  return false if compiled.nil? || compiled.empty?

  if action_name
    target = "#{controller_name}##{action_name}"
    compiled.each do |entry|
      if entry[:has_hash]
        return true if match_compiled?(target, entry)
      elsif match_compiled?(controller_name, entry)
        return true
      end
    end
    return false
  end

  compiled.each do |entry|
    next if entry[:has_hash]
    return true if match_compiled?(controller_name, entry)
  end
  false
end

#excluded_job?(job_class_name) ⇒ Boolean

Returns:

  • (Boolean)


195
196
197
198
199
# File 'lib/dead_bro/configuration.rb', line 195

def excluded_job?(job_class_name)
  compiled = @compiled_excluded_jobs
  return false if compiled.nil? || compiled.empty?
  compiled.any? { |entry| match_compiled?(job_class_name, entry) }
end

#exclusive_controller?(controller_name, action_name) ⇒ Boolean

Returns:

  • (Boolean)


207
208
209
210
211
212
# File 'lib/dead_bro/configuration.rb', line 207

def exclusive_controller?(controller_name, action_name)
  compiled = @compiled_exclusive_controllers
  return true if compiled.nil? || compiled.empty?
  target = "#{controller_name}##{action_name}"
  compiled.any? { |entry| match_compiled?(target, entry) }
end

#exclusive_job?(job_class_name) ⇒ Boolean

Returns:

  • (Boolean)


201
202
203
204
205
# File 'lib/dead_bro/configuration.rb', line 201

def exclusive_job?(job_class_name)
  compiled = @compiled_exclusive_jobs
  return true if compiled.nil? || compiled.empty?
  compiled.any? { |entry| match_compiled?(job_class_name, entry) }
end

#heartbeat_due?Boolean

Returns:

  • (Boolean)


150
151
152
153
# File 'lib/dead_bro/configuration.rb', line 150

def heartbeat_due?
  return false if api_key.nil?
  last_heartbeat_attempt_at.nil? || (Time.now.utc - last_heartbeat_attempt_at) >= HEARTBEAT_INTERVAL
end

#resolve_api_keyObject



230
231
232
233
234
# File 'lib/dead_bro/configuration.rb', line 230

def resolve_api_key
  return @api_key unless @api_key.nil?

  ENV["DEAD_BRO_API_KEY"]
end

#resolve_deploy_idObject



155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/dead_bro/configuration.rb', line 155

def resolve_deploy_id
  explicit = @explicit_deploy_revision&.to_s&.strip
  return explicit unless explicit.nil? || explicit.empty?

  DEPLOY_REVISION_ENV_KEYS.each do |key|
    v = ENV[key]
    next unless v.respond_to?(:to_s)

    stripped = v.to_s.strip
    next if stripped.empty?

    return stripped
  end

  DeadBro.process_deploy_id
end

#resolve_sample_rateObject

Returns the configured sample_rate only (no ENV fallback). Use DeadBro.configure or remote settings.



226
227
228
# File 'lib/dead_bro/configuration.rb', line 226

def resolve_sample_rate
  @sample_rate
end

#should_sample?Boolean

Returns:

  • (Boolean)


214
215
216
217
218
219
220
221
222
223
# File 'lib/dead_bro/configuration.rb', line 214

def should_sample?
  sample_rate = resolve_sample_rate
  sample_rate = 100 if sample_rate.nil?

  return true if sample_rate >= 100
  return false if sample_rate <= 0

  # Generate random number 1-100 and check if it's within sample rate
  rand(1..100) <= sample_rate
end