errorgap 0.7.0 → 0.9.0
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/CHANGELOG.md +61 -0
- data/README.md +79 -1
- data/exe/errorgap +17 -1
- data/lib/errorgap/configuration.rb +55 -2
- data/lib/errorgap/delivery.rb +248 -0
- data/lib/errorgap/integrations/active_job.rb +58 -0
- data/lib/errorgap/integrations/net_http.rb +50 -0
- data/lib/errorgap/integrations/sidekiq.rb +56 -0
- data/lib/errorgap/log_delivery.rb +2 -25
- data/lib/errorgap/notice.rb +10 -21
- data/lib/errorgap/notifier.rb +27 -21
- data/lib/errorgap/rack_middleware.rb +48 -5
- data/lib/errorgap/rails/railtie.rb +13 -0
- data/lib/errorgap/release_detector.rb +69 -0
- data/lib/errorgap/sanitizer.rb +91 -0
- data/lib/errorgap/sign_ins.rb +68 -0
- data/lib/errorgap/transacter.rb +2 -24
- data/lib/errorgap/version.rb +1 -1
- data/lib/errorgap/warden_hooks.rb +88 -0
- data/lib/errorgap.rb +124 -6
- metadata +10 -2
data/lib/errorgap.rb
CHANGED
|
@@ -3,24 +3,34 @@
|
|
|
3
3
|
require "securerandom"
|
|
4
4
|
|
|
5
5
|
require_relative "errorgap/configuration"
|
|
6
|
+
require_relative "errorgap/sanitizer"
|
|
7
|
+
require_relative "errorgap/release_detector"
|
|
8
|
+
require_relative "errorgap/delivery"
|
|
6
9
|
require_relative "errorgap/breadcrumbs"
|
|
7
10
|
require_relative "errorgap/notifier"
|
|
8
11
|
require_relative "errorgap/notice"
|
|
9
12
|
require_relative "errorgap/log_delivery"
|
|
13
|
+
require_relative "errorgap/sign_ins"
|
|
14
|
+
require_relative "errorgap/warden_hooks"
|
|
10
15
|
require_relative "errorgap/transaction"
|
|
11
16
|
require_relative "errorgap/span_collector"
|
|
12
17
|
require_relative "errorgap/span_recorder"
|
|
13
18
|
require_relative "errorgap/transacter"
|
|
14
19
|
require_relative "errorgap/rack_middleware"
|
|
20
|
+
require_relative "errorgap/integrations/sidekiq"
|
|
21
|
+
require_relative "errorgap/integrations/active_job"
|
|
22
|
+
require_relative "errorgap/integrations/net_http"
|
|
15
23
|
require_relative "errorgap/version"
|
|
16
24
|
|
|
17
25
|
module Errorgap
|
|
18
26
|
class << self
|
|
19
27
|
def configure
|
|
20
28
|
yield(configuration)
|
|
29
|
+
delivery.configure(configuration)
|
|
21
30
|
notifier.configure(configuration)
|
|
22
31
|
transacter.configure(configuration)
|
|
23
32
|
log_delivery.configure(configuration)
|
|
33
|
+
sign_ins.configure(configuration)
|
|
24
34
|
@breadcrumbs = Breadcrumbs.new(configuration.max_breadcrumbs)
|
|
25
35
|
end
|
|
26
36
|
|
|
@@ -32,6 +42,11 @@ module Errorgap
|
|
|
32
42
|
@notifier ||= Notifier.new(configuration)
|
|
33
43
|
end
|
|
34
44
|
|
|
45
|
+
# The shared sender behind notices, transactions, logs and sign-ins.
|
|
46
|
+
def delivery
|
|
47
|
+
@delivery ||= Delivery.new(configuration)
|
|
48
|
+
end
|
|
49
|
+
|
|
35
50
|
def transacter
|
|
36
51
|
@transacter ||= Transacter.new(configuration)
|
|
37
52
|
end
|
|
@@ -40,6 +55,19 @@ module Errorgap
|
|
|
40
55
|
@log_delivery ||= LogDelivery.new(configuration)
|
|
41
56
|
end
|
|
42
57
|
|
|
58
|
+
def sign_ins
|
|
59
|
+
@sign_ins ||= SignIns.new(configuration)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Report a sign-in to this app: "success", "failure", "password_reset",
|
|
63
|
+
# "mfa_failure" or "locked". Pass the request for its IP, user agent and
|
|
64
|
+
# path. Needs `config.auth_events = true`; Devise apps get this
|
|
65
|
+
# automatically from the Warden hooks.
|
|
66
|
+
def sign_in(outcome, user: nil, request: nil, ip: nil, user_agent: nil, path: nil, method: nil, sync: false)
|
|
67
|
+
sign_ins.record(outcome, user: user, request: request, ip: ip, user_agent: user_agent,
|
|
68
|
+
path: path, method: method, sync: sync)
|
|
69
|
+
end
|
|
70
|
+
|
|
43
71
|
def breadcrumbs
|
|
44
72
|
@breadcrumbs ||= Breadcrumbs.new(configuration.max_breadcrumbs)
|
|
45
73
|
end
|
|
@@ -49,6 +77,7 @@ module Errorgap
|
|
|
49
77
|
if (transaction_id = current_transaction_id) && !context.key?(:transaction_id) && !context.key?("transaction_id")
|
|
50
78
|
context = context.merge(transaction_id: transaction_id)
|
|
51
79
|
end
|
|
80
|
+
session = user_session.merge(session || {}) if current_user
|
|
52
81
|
notifier.notify(
|
|
53
82
|
error,
|
|
54
83
|
context: context,
|
|
@@ -60,6 +89,82 @@ module Errorgap
|
|
|
60
89
|
)
|
|
61
90
|
end
|
|
62
91
|
|
|
92
|
+
REPORTED_IVAR = :@__errorgap_reported
|
|
93
|
+
USER_KEY = :errorgap_user
|
|
94
|
+
|
|
95
|
+
# `notify`, unless this exception object was already reported: lets the
|
|
96
|
+
# Rack middleware, a job integration and the app's own rescue all see the
|
|
97
|
+
# same error without sending it more than once.
|
|
98
|
+
def notify_once(error, **options)
|
|
99
|
+
return nil if reported?(error)
|
|
100
|
+
|
|
101
|
+
mark_reported(error)
|
|
102
|
+
notify(error, **options)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def reported?(error)
|
|
106
|
+
error.instance_variable_defined?(REPORTED_IVAR)
|
|
107
|
+
rescue StandardError
|
|
108
|
+
false
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def mark_reported(error)
|
|
112
|
+
error.instance_variable_set(REPORTED_IVAR, true) unless error.frozen?
|
|
113
|
+
rescue StandardError
|
|
114
|
+
nil
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Name the user the current request or job is acting for. Errors reported
|
|
118
|
+
# on this thread until `clear_user` carry it as `session.user_id` /
|
|
119
|
+
# `session.user_email`, which errorgap's user filters read.
|
|
120
|
+
def set_user(id: nil, email: nil)
|
|
121
|
+
user = {}
|
|
122
|
+
user[:id] = id.to_s unless id.nil? || id.to_s.empty?
|
|
123
|
+
user[:email] = email.to_s unless email.nil? || email.to_s.empty?
|
|
124
|
+
Thread.current[USER_KEY] = user.empty? ? nil : user
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def clear_user
|
|
128
|
+
Thread.current[USER_KEY] = nil
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def current_user
|
|
132
|
+
Thread.current[USER_KEY]
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Record a release with errorgap (Deploys): errors are then attributed to
|
|
136
|
+
# the deploy that shipped them. Defaults come from the configuration.
|
|
137
|
+
def track_release(version: nil, sha: nil, branch: nil, environment: nil, sync: true)
|
|
138
|
+
configuration.validate!
|
|
139
|
+
return if configuration.ignored_environment?
|
|
140
|
+
|
|
141
|
+
payload = {
|
|
142
|
+
version: version || configuration.release,
|
|
143
|
+
sha: sha || configuration.release_sha,
|
|
144
|
+
branch: branch || configuration.release_branch,
|
|
145
|
+
environment: environment || configuration.environment
|
|
146
|
+
}.compact
|
|
147
|
+
return unless payload[:version] || payload[:sha]
|
|
148
|
+
|
|
149
|
+
if sync
|
|
150
|
+
delivery.post("releases", payload)
|
|
151
|
+
else
|
|
152
|
+
delivery.enqueue("releases", payload)
|
|
153
|
+
end
|
|
154
|
+
rescue StandardError => exception
|
|
155
|
+
configuration.logger&.warn("[errorgap] release not recorded: #{exception.class}: #{exception.message}")
|
|
156
|
+
nil
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# `config.track_release`: the first notice of a process records the
|
|
160
|
+
# release, so an app that never errors never calls errorgap.
|
|
161
|
+
def record_release_once
|
|
162
|
+
return if @release_recorded
|
|
163
|
+
|
|
164
|
+
@release_recorded = true
|
|
165
|
+
track_release(sync: false)
|
|
166
|
+
end
|
|
167
|
+
|
|
63
168
|
# Record a diagnostic breadcrumb attached to subsequent notices.
|
|
64
169
|
def add_breadcrumb(message, category: nil, metadata: nil)
|
|
65
170
|
breadcrumbs.add(message, category: category, metadata: metadata)
|
|
@@ -110,7 +215,7 @@ module Errorgap
|
|
|
110
215
|
if sync || !configuration.async
|
|
111
216
|
transacter.deliver(transaction)
|
|
112
217
|
else
|
|
113
|
-
|
|
218
|
+
delivery.enqueue("transactions", transaction.to_h)
|
|
114
219
|
end
|
|
115
220
|
end
|
|
116
221
|
|
|
@@ -160,25 +265,38 @@ module Errorgap
|
|
|
160
265
|
end
|
|
161
266
|
end
|
|
162
267
|
|
|
163
|
-
#
|
|
164
|
-
#
|
|
165
|
-
def flush
|
|
268
|
+
# Wait for queued notices, transactions and logs to be sent. Call before
|
|
269
|
+
# process exit; queued payloads are also flushed from an `at_exit` hook.
|
|
270
|
+
def flush(timeout = Delivery::FLUSH_TIMEOUT)
|
|
271
|
+
delivery.flush(timeout)
|
|
166
272
|
threads = thread_mutex.synchronize do
|
|
167
273
|
pending = delivery_threads.dup
|
|
168
274
|
delivery_threads.clear
|
|
169
275
|
pending
|
|
170
276
|
end
|
|
171
|
-
threads.each { |thread| thread.join(
|
|
277
|
+
threads.each { |thread| thread.join(timeout) }
|
|
172
278
|
nil
|
|
173
279
|
end
|
|
174
280
|
|
|
281
|
+
# Kept for callers that run their own delivery threads.
|
|
175
282
|
def register_thread(thread)
|
|
176
|
-
thread_mutex.synchronize
|
|
283
|
+
thread_mutex.synchronize do
|
|
284
|
+
delivery_threads.select!(&:alive?)
|
|
285
|
+
delivery_threads << thread
|
|
286
|
+
end
|
|
177
287
|
thread
|
|
178
288
|
end
|
|
179
289
|
|
|
180
290
|
private
|
|
181
291
|
|
|
292
|
+
def user_session
|
|
293
|
+
user = current_user || {}
|
|
294
|
+
session = {}
|
|
295
|
+
session["user_id"] = user[:id] if user[:id]
|
|
296
|
+
session["user_email"] = user[:email] if user[:email]
|
|
297
|
+
session
|
|
298
|
+
end
|
|
299
|
+
|
|
182
300
|
def sample_apm?
|
|
183
301
|
rate = configuration.apm_sample_rate.to_f
|
|
184
302
|
return true if rate >= 1.0
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: errorgap
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Errorgap
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rake
|
|
@@ -67,16 +67,24 @@ files:
|
|
|
67
67
|
- lib/errorgap.rb
|
|
68
68
|
- lib/errorgap/breadcrumbs.rb
|
|
69
69
|
- lib/errorgap/configuration.rb
|
|
70
|
+
- lib/errorgap/delivery.rb
|
|
71
|
+
- lib/errorgap/integrations/active_job.rb
|
|
72
|
+
- lib/errorgap/integrations/net_http.rb
|
|
73
|
+
- lib/errorgap/integrations/sidekiq.rb
|
|
70
74
|
- lib/errorgap/log_delivery.rb
|
|
71
75
|
- lib/errorgap/notice.rb
|
|
72
76
|
- lib/errorgap/notifier.rb
|
|
73
77
|
- lib/errorgap/rack_middleware.rb
|
|
74
78
|
- lib/errorgap/rails/railtie.rb
|
|
79
|
+
- lib/errorgap/release_detector.rb
|
|
80
|
+
- lib/errorgap/sanitizer.rb
|
|
81
|
+
- lib/errorgap/sign_ins.rb
|
|
75
82
|
- lib/errorgap/span_collector.rb
|
|
76
83
|
- lib/errorgap/span_recorder.rb
|
|
77
84
|
- lib/errorgap/transacter.rb
|
|
78
85
|
- lib/errorgap/transaction.rb
|
|
79
86
|
- lib/errorgap/version.rb
|
|
87
|
+
- lib/errorgap/warden_hooks.rb
|
|
80
88
|
- lib/generators/errorgap/install_generator.rb
|
|
81
89
|
homepage: https://github.com/errorgaphq/errorgap-ruby
|
|
82
90
|
licenses:
|