Class: DeadBro::Configuration

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

Constant Summary collapse

HEARTBEAT_INTERVAL =

seconds

60
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.



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/dead_bro/configuration.rb', line 40

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
  @deploy_id = resolve_deploy_id
  @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

#deploy_idObject

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 deploy_id
  @deploy_id
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.



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/dead_bro/configuration.rb', line 100

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

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

Returns:

  • (Boolean)


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

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)


153
154
155
156
157
# File 'lib/dead_bro/configuration.rb', line 153

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)


165
166
167
168
169
170
# File 'lib/dead_bro/configuration.rb', line 165

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)


159
160
161
162
163
# File 'lib/dead_bro/configuration.rb', line 159

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)


121
122
123
124
# File 'lib/dead_bro/configuration.rb', line 121

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



188
189
190
191
192
# File 'lib/dead_bro/configuration.rb', line 188

def resolve_api_key
  return @api_key unless @api_key.nil?

  ENV["DEAD_BRO_API_KEY"]
end

#resolve_deploy_idObject



126
127
128
# File 'lib/dead_bro/configuration.rb', line 126

def resolve_deploy_id
  ENV["dead_bro_DEPLOY_ID"] || ENV["GIT_REV"] || ENV["HEROKU_SLUG_COMMIT"] || DeadBro.process_deploy_id
end

#resolve_sample_rateObject

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



184
185
186
# File 'lib/dead_bro/configuration.rb', line 184

def resolve_sample_rate
  @sample_rate
end

#should_sample?Boolean

Returns:

  • (Boolean)


172
173
174
175
176
177
178
179
180
181
# File 'lib/dead_bro/configuration.rb', line 172

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