Class: ErrorRadar::Configuration

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

Overview

Holds every host-app-specific decision so the engine stays decoupled. Configure from an initializer (see the install generator's template).

Constant Summary collapse

DEFAULT_CATEGORIES =

Built-in categories (name => stored integer). Hosts can override the whole map (config.categories = {...}) or add their own (register_category).

{
  application:    0, # generic Ruby/Rails runtime error
  external_api:   1, # any 3rd-party API error
  background_job: 2, # uncategorised background-job failure
  syntax:         3, # SyntaxError / NameError / NoMethodError / ArgumentError / TypeError
  database:       4, # ActiveRecord / DB level
  network:        5  # timeouts, connection resets, DNS, ...
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeConfiguration

Returns a new instance of Configuration.



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/error_radar/configuration.rb', line 151

def initialize
  @enabled            = true
  @backtrace_lines    = 30
  @max_message_length = 4_000
  @ignored_exceptions = %w[
    ActionController::RoutingError
    ActiveRecord::RecordNotFound
    ActionController::ParameterMissing
    ActionController::UnknownFormat
    ActionController::BadRequest
    ActionController::InvalidAuthenticityToken
    ActionDispatch::Http::Parameters::ParseError
  ]
  @sensitive_params   = %w[password password_confirmation token access_token authorization secret]
  @install_middleware  = true
  @install_sidekiq     = true
  @install_rails_admin = true
  @install_active_job  = true
  @install_rake        = true

  @notify_on            = [:new_error]
  @slack_webhook_url    = nil
  @slack_channel        = nil
  @discord_webhook_url  = nil
  @email_recipients     = []
  @email_from           = nil
  @webhook_urls         = []
  @chatwork_api_token      = nil
  @chatwork_room_id        = nil
  @chatwork_notify_sources = []
  @app_name             = nil
  @app_host             = nil
  @error_callbacks      = []

  @digest_enabled    = false
  @digest_recipients = []

  @spike_threshold      = 10
  @spike_window_minutes = 5

  @track_occurrences        = false
  @max_occurrences_per_error = 200

  @async_capture     = false
  @capture_job_queue = :default
  @retention_days    = nil
  @max_records       = nil

  @api_token    = nil
  @github_token = nil
  @github_repo  = nil
  @categorizers       = []
  @detail_extractors  = []
  @expected_servers   = []
  @authenticate       = nil
  @current_user       = nil
  @categories         = DEFAULT_CATEGORIES.dup
end

Instance Attribute Details

#api_tokenObject

REST API ──────────────────────────────────────────────────────────────── Bearer token for /api/* endpoints. nil = unauthenticated (not for prod).



118
119
120
# File 'lib/error_radar/configuration.rb', line 118

def api_token
  @api_token
end

#app_hostObject

Base URL used to build deep-links (e.g. "https://myapp.com").



73
74
75
# File 'lib/error_radar/configuration.rb', line 73

def app_host
  @app_host
end

#app_nameObject

App name shown in notification subject/title. Defaults to Rails app name.



71
72
73
# File 'lib/error_radar/configuration.rb', line 71

def app_name
  @app_name
end

#async_captureObject

Performance ───────────────────────────────────────────────────────────── When true, ErrorLog.record is enqueued via ActiveJob (non-blocking). Requires ActiveJob to be configured. Falls back to sync if ActiveJob is absent.



106
107
108
# File 'lib/error_radar/configuration.rb', line 106

def async_capture
  @async_capture
end

#authenticateObject

Dashboard auth: ->(controller) { ... } run as a before_action. Raise / redirect inside it to deny access. nil => no auth (NOT recommended in prod).



141
142
143
# File 'lib/error_radar/configuration.rb', line 141

def authenticate
  @authenticate
end

#backtrace_linesObject

How many backtrace lines to persist.



22
23
24
# File 'lib/error_radar/configuration.rb', line 22

def backtrace_lines
  @backtrace_lines
end

#capture_job_queueObject

Queue name for CaptureJob when async_capture is enabled.



108
109
110
# File 'lib/error_radar/configuration.rb', line 108

def capture_job_queue
  @capture_job_queue
end

#categoriesObject

The category name => integer map backing ErrorLog's category enum. Read-only accessor; mutate through categories= or register_category so the built-in defaults are always preserved.



149
150
151
# File 'lib/error_radar/configuration.rb', line 149

def categories
  @categories
end

#categorizersObject

Custom classification rules. Each is a callable ->(exception) { :category | nil }. The first rule that returns a non-nil category wins; built-in rules run after.



128
129
130
# File 'lib/error_radar/configuration.rb', line 128

def categorizers
  @categorizers
end

#chatwork_api_tokenObject

ChatWork ──────────────────────────────────────────────────────────────── API token from https://www.chatwork.com/service/packages/chatwork/subpackages/api/apply_token.php



62
63
64
# File 'lib/error_radar/configuration.rb', line 62

def chatwork_api_token
  @chatwork_api_token
end

#chatwork_notify_sourcesObject

Filter by source: array of strings/regexps. Only errors whose source matches at least one entry are sent to ChatWork. nil or [] = notify all. Example: ['Maintain::CheckSidekiqServ', /FetchInsights/]



68
69
70
# File 'lib/error_radar/configuration.rb', line 68

def chatwork_notify_sources
  @chatwork_notify_sources
end

#chatwork_room_idObject

Room ID to post messages into (numeric string).



64
65
66
# File 'lib/error_radar/configuration.rb', line 64

def chatwork_room_id
  @chatwork_room_id
end

#current_userObject

->(controller) { "who@acted" } — stamped onto resolved errors.



144
145
146
# File 'lib/error_radar/configuration.rb', line 144

def current_user
  @current_user
end

#detail_extractorsObject

Extract extra structured columns from custom exception types. Each is a callable ->(exception) { { http_status:, request_url:, api_code:, api_subcode: } | nil }.



132
133
134
# File 'lib/error_radar/configuration.rb', line 132

def detail_extractors
  @detail_extractors
end

#digest_enabledObject

Digest email ──────────────────────────────────────────────────────────── Set to true to enable digest delivery (rake error_radar:digest).



84
85
86
# File 'lib/error_radar/configuration.rb', line 84

def digest_enabled
  @digest_enabled
end

#digest_recipientsObject

Separate recipient list for digests. Falls back to email_recipients if empty.



86
87
88
# File 'lib/error_radar/configuration.rb', line 86

def digest_recipients
  @digest_recipients
end

#discord_webhook_urlObject

Discord incoming-webhook URL



50
51
52
# File 'lib/error_radar/configuration.rb', line 50

def discord_webhook_url
  @discord_webhook_url
end

#email_fromObject

From address for notification emails.



55
56
57
# File 'lib/error_radar/configuration.rb', line 55

def email_from
  @email_from
end

#email_recipientsObject

ActionMailer recipients. Requires ActionMailer to be configured in host app.



53
54
55
# File 'lib/error_radar/configuration.rb', line 53

def email_recipients
  @email_recipients
end

#enabledObject

Master switch — set false (e.g. in test env) to make capture a no-op.



19
20
21
# File 'lib/error_radar/configuration.rb', line 19

def enabled
  @enabled
end

#error_callbacksObject (readonly)

Custom callbacks: ->(error_log) { ... }. Called after built-in channels.



76
77
78
# File 'lib/error_radar/configuration.rb', line 76

def error_callbacks
  @error_callbacks
end

#expected_serversObject

Optional Sidekiq process expectations for the dashboard's server panel. Each entry: { key:, name:, tag:, host:, queue_hint: }. Empty => the panel simply lists whatever live processes exist.



137
138
139
# File 'lib/error_radar/configuration.rb', line 137

def expected_servers
  @expected_servers
end

#github_repoObject

"owner/repo" string, e.g. "myorg/myapp".



124
125
126
# File 'lib/error_radar/configuration.rb', line 124

def github_repo
  @github_repo
end

#github_tokenObject

GitHub integration ────────────────────────────────────────────────────── Personal access token with repo scope.



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

def github_token
  @github_token
end

#ignored_exceptionsObject

Exception class names the Rack middleware must NOT log (expected client outcomes: routing errors, 404s, bad requests, ...).



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

def ignored_exceptions
  @ignored_exceptions
end

#install_active_jobObject

Integration toggles.



35
36
37
# File 'lib/error_radar/configuration.rb', line 35

def install_active_job
  @install_active_job
end

#install_middlewareObject

Integration toggles.



35
36
37
# File 'lib/error_radar/configuration.rb', line 35

def install_middleware
  @install_middleware
end

#install_rails_adminObject

Integration toggles.



35
36
37
# File 'lib/error_radar/configuration.rb', line 35

def install_rails_admin
  @install_rails_admin
end

#install_rakeObject

Integration toggles.



35
36
37
# File 'lib/error_radar/configuration.rb', line 35

def install_rake
  @install_rake
end

#install_sidekiqObject

Integration toggles.



35
36
37
# File 'lib/error_radar/configuration.rb', line 35

def install_sidekiq
  @install_sidekiq
end

#max_message_lengthObject

Truncate stored messages to this many chars.



25
26
27
# File 'lib/error_radar/configuration.rb', line 25

def max_message_length
  @max_message_length
end

#max_occurrences_per_errorObject

Maximum occurrences to keep per ErrorLog. Oldest are pruned on each new hit. nil = keep all (not recommended for high-volume apps).



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

def max_occurrences_per_error
  @max_occurrences_per_error
end

#max_recordsObject

Keep at most this many total records; deletes oldest resolved/ignored first (nil = unlimited).



114
115
116
# File 'lib/error_radar/configuration.rb', line 114

def max_records
  @max_records
end

#notify_onObject

Notifications ───────────────────────────────────────────────────────── When to fire: :new_error (first time a fingerprint is seen), :critical (any critical-severity occurrence, throttled), :all (every occurrence, throttled to 1/hour/fingerprint)



42
43
44
# File 'lib/error_radar/configuration.rb', line 42

def notify_on
  @notify_on
end

#retention_daysObject

Retention ─────────────────────────────────────────────────────────────── Auto-delete resolved/ignored records older than this many days (nil = keep forever).



112
113
114
# File 'lib/error_radar/configuration.rb', line 112

def retention_days
  @retention_days
end

#sensitive_paramsObject

Request param keys to scrub before persisting them in context.



32
33
34
# File 'lib/error_radar/configuration.rb', line 32

def sensitive_params
  @sensitive_params
end

#slack_channelObject

Override target channel. Leave nil to use webhook's default channel.



47
48
49
# File 'lib/error_radar/configuration.rb', line 47

def slack_channel
  @slack_channel
end

#slack_webhook_urlObject

Slack incoming-webhook URL (https://hooks.slack.com/services/...)



45
46
47
# File 'lib/error_radar/configuration.rb', line 45

def slack_webhook_url
  @slack_webhook_url
end

#spike_thresholdObject

Spike detection ───────────────────────────────────────────────────────── Number of occurrences within spike_window_minutes that triggers a spike alert. Add :spike to notify_on to enable: config.notify_on = [:new_error, :spike]



91
92
93
# File 'lib/error_radar/configuration.rb', line 91

def spike_threshold
  @spike_threshold
end

#spike_window_minutesObject

Rolling time window in minutes for counting occurrences.



93
94
95
# File 'lib/error_radar/configuration.rb', line 93

def spike_window_minutes
  @spike_window_minutes
end

#track_occurrencesObject

Occurrences ───────────────────────────────────────────────────────────── When true, each individual error hit is stored in error_radar_occurrences. Requires running: bin/rails generate error_radar:upgrade_v060 && bin/rails db:migrate



98
99
100
# File 'lib/error_radar/configuration.rb', line 98

def track_occurrences
  @track_occurrences
end

#webhook_urlsObject

One or more plain HTTPS URLs that receive a POST with JSON body on each alert.



58
59
60
# File 'lib/error_radar/configuration.rb', line 58

def webhook_urls
  @webhook_urls
end

Instance Method Details

#categorize(&block) ⇒ Object

Convenience DSL inside configure:

c.categorize { |e| :external_api if e.is_a?(MyApi::Error) }


237
238
239
# File 'lib/error_radar/configuration.rb', line 237

def categorize(&block)
  @categorizers << block
end

#extract_details(&block) ⇒ Object

c.extract_details { |e| { http_status: e.status } if e.is_a?(MyApi::Error) }



242
243
244
# File 'lib/error_radar/configuration.rb', line 242

def extract_details(&block)
  @detail_extractors << block
end

#on_error(&block) ⇒ Object



78
79
80
# File 'lib/error_radar/configuration.rb', line 78

def on_error(&block)
  @error_callbacks << block
end

#register_category(name, value) ⇒ Object

Add a single custom category without disturbing the rest:

config.register_category(:instagram_api, 6)


222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/error_radar/configuration.rb', line 222

def register_category(name, value)
  name = name.to_sym
  value = Integer(value)
  if @categories[name] && @categories[name] != value
    raise ArgumentError, "category #{name.inspect} already mapped to #{@categories[name]}"
  end
  existing = @categories.key(value)
  if existing && existing != name
    raise ArgumentError, "category value #{value} already used by #{existing.inspect}"
  end
  @categories = @categories.merge(name => value)
end