appsignal 4.8.5 → 4.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 +2 -2
- data/SUPPORT.md +1 -1
- data/appsignal.gemspec +2 -2
- data/build_matrix.yml +35 -0
- data/ext/agent.rb +27 -27
- data/ext/base.rb +3 -7
- data/ext/extconf.rb +1 -1
- data/lib/appsignal/check_in/event.rb +5 -4
- data/lib/appsignal/cli/diagnose.rb +1 -1
- data/lib/appsignal/cli/helpers.rb +2 -2
- data/lib/appsignal/cli/install.rb +3 -3
- data/lib/appsignal/config.rb +44 -1
- data/lib/appsignal/environment.rb +1 -0
- data/lib/appsignal/extension/jruby.rb +6 -5
- data/lib/appsignal/extension.rb +1 -1
- data/lib/appsignal/helpers/instrumentation.rb +12 -12
- data/lib/appsignal/hooks/action_cable.rb +2 -2
- data/lib/appsignal/hooks/active_job.rb +42 -3
- data/lib/appsignal/hooks/delayed_job.rb +2 -1
- data/lib/appsignal/hooks/excon.rb +1 -1
- data/lib/appsignal/hooks/faraday.rb +21 -0
- data/lib/appsignal/hooks/http.rb +9 -0
- data/lib/appsignal/hooks/mongo_ruby_driver.rb +2 -1
- data/lib/appsignal/hooks/que.rb +7 -1
- data/lib/appsignal/hooks/resque.rb +5 -1
- data/lib/appsignal/hooks/shoryuken.rb +15 -1
- data/lib/appsignal/hooks/sidekiq.rb +14 -1
- data/lib/appsignal/hooks.rb +1 -0
- data/lib/appsignal/integrations/action_cable.rb +1 -1
- data/lib/appsignal/integrations/active_support_notifications.rb +19 -6
- data/lib/appsignal/integrations/delayed_job_plugin.rb +38 -1
- data/lib/appsignal/integrations/excon.rb +8 -0
- data/lib/appsignal/integrations/faraday.rb +51 -0
- data/lib/appsignal/integrations/http.rb +9 -0
- data/lib/appsignal/integrations/mongo_ruby_driver.rb +4 -2
- data/lib/appsignal/integrations/net_http.rb +7 -0
- data/lib/appsignal/integrations/object.rb +3 -3
- data/lib/appsignal/integrations/que.rb +68 -1
- data/lib/appsignal/integrations/rake.rb +1 -1
- data/lib/appsignal/integrations/resque.rb +20 -1
- data/lib/appsignal/integrations/shoryuken.rb +33 -1
- data/lib/appsignal/integrations/sidekiq.rb +73 -36
- data/lib/appsignal/integrations/webmachine.rb +1 -1
- data/lib/appsignal/logger.rb +4 -1
- data/lib/appsignal/rack/abstract_middleware.rb +1 -1
- data/lib/appsignal/rack/body_wrapper.rb +5 -5
- data/lib/appsignal/rack/hanami_middleware.rb +1 -0
- data/lib/appsignal/sample_data.rb +1 -0
- data/lib/appsignal/transaction.rb +59 -11
- data/lib/appsignal/utils/query_params_sanitizer.rb +2 -0
- data/lib/appsignal/version.rb +1 -1
- data/lib/appsignal.rb +2 -2
- data/lib/puma/plugin/appsignal.rb +1 -1
- data/sig/appsignal.rbi +41 -1
- data/sig/appsignal.rbs +30 -0
- metadata +7 -6
- data/lib/appsignal/event_formatter/faraday/request_formatter.rb +0 -24
|
@@ -10,7 +10,7 @@ module Appsignal
|
|
|
10
10
|
|
|
11
11
|
begin
|
|
12
12
|
Appsignal.instrument("perform_job.que") { super }
|
|
13
|
-
rescue Exception => error
|
|
13
|
+
rescue Exception => error
|
|
14
14
|
transaction.set_error(error)
|
|
15
15
|
raise error
|
|
16
16
|
ensure
|
|
@@ -34,5 +34,72 @@ module Appsignal
|
|
|
34
34
|
end
|
|
35
35
|
end
|
|
36
36
|
end
|
|
37
|
+
|
|
38
|
+
# @!visibility private
|
|
39
|
+
#
|
|
40
|
+
# Prepended to `Que::Job`'s singleton so it records each enqueue as an
|
|
41
|
+
# `enqueue.que` event under the active transaction. Like all AppSignal
|
|
42
|
+
# events, it only records when there's an active transaction (e.g. enqueuing
|
|
43
|
+
# from within a web request or another job); otherwise it's a transparent
|
|
44
|
+
# pass-through.
|
|
45
|
+
module QueClientPlugin
|
|
46
|
+
def enqueue(*_args, job_options: {}, **_rest)
|
|
47
|
+
# Inside a `bulk_enqueue` block the batch is recorded once by the
|
|
48
|
+
# `bulk_enqueue` wrapper, so each inner enqueue is a pass-through to
|
|
49
|
+
# avoid recording an event per job.
|
|
50
|
+
return super if Thread.current[:appsignal_que_bulk_enqueue]
|
|
51
|
+
|
|
52
|
+
# Under Active Job the enqueue is already recorded as an
|
|
53
|
+
# `enqueue.active_job` event, so skip recording it again here.
|
|
54
|
+
return super if Appsignal::Transaction.current? &&
|
|
55
|
+
Appsignal::Transaction.current.job_enqueue_events_suppressed?
|
|
56
|
+
|
|
57
|
+
# Resolve the job class the way Que does: an explicit `:job_class`, else
|
|
58
|
+
# the class `enqueue` was called on.
|
|
59
|
+
title = "enqueue #{job_options[:job_class] || name} job"
|
|
60
|
+
Appsignal.instrument("enqueue.que", title) { super }
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# @!visibility private
|
|
65
|
+
#
|
|
66
|
+
# `bulk_enqueue` exists only on Que 2+, so this lives in its own module that
|
|
67
|
+
# the hook prepends only when Que has the method -- otherwise we'd define a
|
|
68
|
+
# `bulk_enqueue` on Que versions that have none. The whole batch records a
|
|
69
|
+
# single `bulk_enqueue.que` event; the inner enqueues are pass-throughs.
|
|
70
|
+
module QueBulkClientPlugin
|
|
71
|
+
def bulk_enqueue(*_args, job_options: {}, **_rest)
|
|
72
|
+
# Under Active Job the enqueue is already recorded as an
|
|
73
|
+
# `enqueue.active_job` event, so skip recording it again here.
|
|
74
|
+
return super if Appsignal::Transaction.current? &&
|
|
75
|
+
Appsignal::Transaction.current.job_enqueue_events_suppressed?
|
|
76
|
+
|
|
77
|
+
Appsignal.instrument("bulk_enqueue.que", bulk_enqueue_title(job_options)) do
|
|
78
|
+
# Flag the batch so the enqueues this block triggers pass through
|
|
79
|
+
# without recording, without reading Que's internal bulk state.
|
|
80
|
+
was_bulk = Thread.current[:appsignal_que_bulk_enqueue]
|
|
81
|
+
Thread.current[:appsignal_que_bulk_enqueue] = true
|
|
82
|
+
begin
|
|
83
|
+
super
|
|
84
|
+
ensure
|
|
85
|
+
Thread.current[:appsignal_que_bulk_enqueue] = was_bulk
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
private
|
|
91
|
+
|
|
92
|
+
# The batch's job class is known up front only from an explicit
|
|
93
|
+
# `:job_class` or when `bulk_enqueue` is called on a concrete subclass;
|
|
94
|
+
# called on `Que::Job` itself the class isn't known until the inner
|
|
95
|
+
# enqueues run, so the title is left class-less.
|
|
96
|
+
def bulk_enqueue_title(job_options)
|
|
97
|
+
job_class = job_options[:job_class]
|
|
98
|
+
job_class ||= name unless equal?(::Que::Job)
|
|
99
|
+
return "bulk enqueue jobs" unless job_class
|
|
100
|
+
|
|
101
|
+
"bulk enqueue #{job_class} jobs"
|
|
102
|
+
end
|
|
103
|
+
end
|
|
37
104
|
end
|
|
38
105
|
end
|
|
@@ -25,7 +25,7 @@ module Appsignal
|
|
|
25
25
|
Appsignal.instrument "task.rake" do
|
|
26
26
|
super
|
|
27
27
|
end
|
|
28
|
-
rescue Exception => error
|
|
28
|
+
rescue Exception => error
|
|
29
29
|
Appsignal::Integrations::RakeIntegrationHelper.register_at_exit_hook
|
|
30
30
|
unless RakeIntegration.ignored_error?(error)
|
|
31
31
|
transaction ||= _appsignal_create_transaction
|
|
@@ -10,7 +10,7 @@ module Appsignal
|
|
|
10
10
|
Appsignal.instrument "perform.resque" do
|
|
11
11
|
super
|
|
12
12
|
end
|
|
13
|
-
rescue Exception => exception
|
|
13
|
+
rescue Exception => exception
|
|
14
14
|
transaction.set_error(exception)
|
|
15
15
|
raise exception
|
|
16
16
|
ensure
|
|
@@ -25,6 +25,25 @@ module Appsignal
|
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
+
# Wraps `Resque.push` to record an `enqueue.resque` event so the enqueue
|
|
29
|
+
# shows up under the active transaction.
|
|
30
|
+
#
|
|
31
|
+
# Like all AppSignal events, this only records when there's an active
|
|
32
|
+
# transaction (e.g. enqueuing from within a web request or another job).
|
|
33
|
+
# An enqueue with no transaction is a transparent pass-through.
|
|
34
|
+
#
|
|
35
|
+
# @!visibility private
|
|
36
|
+
module ResquePushIntegration
|
|
37
|
+
def push(_queue, item)
|
|
38
|
+
# Under Active Job the enqueue is already recorded as an
|
|
39
|
+
# `enqueue.active_job` event, so skip recording it again here.
|
|
40
|
+
return super if Appsignal::Transaction.current? &&
|
|
41
|
+
Appsignal::Transaction.current.job_enqueue_events_suppressed?
|
|
42
|
+
|
|
43
|
+
Appsignal.instrument("enqueue.resque", "enqueue #{item["class"]} job") { super }
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
28
47
|
# @!visibility private
|
|
29
48
|
class ResqueHelpers
|
|
30
49
|
def self.arguments(payload)
|
|
@@ -8,7 +8,7 @@ module Appsignal
|
|
|
8
8
|
transaction = Appsignal::Transaction.create(Appsignal::Transaction::BACKGROUND_JOB)
|
|
9
9
|
|
|
10
10
|
Appsignal.instrument("perform_job.shoryuken", &block)
|
|
11
|
-
rescue Exception => error
|
|
11
|
+
rescue Exception => error
|
|
12
12
|
transaction.set_error(error)
|
|
13
13
|
raise
|
|
14
14
|
ensure
|
|
@@ -71,5 +71,37 @@ module Appsignal
|
|
|
71
71
|
end
|
|
72
72
|
end
|
|
73
73
|
end
|
|
74
|
+
|
|
75
|
+
# Shoryuken client middleware that records an `enqueue.shoryuken` event so
|
|
76
|
+
# the enqueue shows up under the active transaction.
|
|
77
|
+
#
|
|
78
|
+
# Like all AppSignal events, this only records when there's an active
|
|
79
|
+
# transaction (e.g. enqueuing from within a web request or another job). An
|
|
80
|
+
# enqueue with no transaction is a transparent pass-through.
|
|
81
|
+
#
|
|
82
|
+
# @!visibility private
|
|
83
|
+
class ShoryukenClientMiddleware
|
|
84
|
+
def call(options, &block)
|
|
85
|
+
# Under Active Job the enqueue is already recorded as an
|
|
86
|
+
# `enqueue.active_job` event, so skip recording it again here.
|
|
87
|
+
return yield if Appsignal::Transaction.current? &&
|
|
88
|
+
Appsignal::Transaction.current.job_enqueue_events_suppressed?
|
|
89
|
+
|
|
90
|
+
Appsignal.instrument("enqueue.shoryuken", enqueue_title(options), &block)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
private
|
|
94
|
+
|
|
95
|
+
# Enqueues through a Shoryuken worker carry the worker class in the
|
|
96
|
+
# `shoryuken_class` message attribute. Raw `send_message` enqueues don't,
|
|
97
|
+
# so there's no worker class to name -- fall back to the queue instead.
|
|
98
|
+
def enqueue_title(options)
|
|
99
|
+
worker_class = options.dig(:message_attributes, "shoryuken_class", :string_value)
|
|
100
|
+
return "enqueue #{worker_class} job" if worker_class
|
|
101
|
+
|
|
102
|
+
queue = options[:queue_url].to_s.split("/").last
|
|
103
|
+
"enqueue on #{queue}"
|
|
104
|
+
end
|
|
105
|
+
end
|
|
74
106
|
end
|
|
75
107
|
end
|
|
@@ -49,6 +49,76 @@ module Appsignal
|
|
|
49
49
|
end
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
+
# Resolves the name of a Sidekiq job. That's normally the job class, but
|
|
53
|
+
# the Sidekiq delayed extensions encode the real target and method as YAML
|
|
54
|
+
# in the job's first argument, so those are decoded into a `Target.method`
|
|
55
|
+
# (class) or `Target#method` (instance) name.
|
|
56
|
+
#
|
|
57
|
+
# Shared between the client middleware, which titles the enqueue event with
|
|
58
|
+
# it, and the server middleware, which names the perform transaction with
|
|
59
|
+
# it. The same job then reads the same name on both sides.
|
|
60
|
+
#
|
|
61
|
+
# @!visibility private
|
|
62
|
+
module SidekiqActionName
|
|
63
|
+
module_function
|
|
64
|
+
|
|
65
|
+
# Based on: https://github.com/mperham/sidekiq/blob/63ee43353bd3b753beb0233f64865e658abeb1c3/lib/sidekiq/api.rb#L316-L334
|
|
66
|
+
def parse_action_name(job)
|
|
67
|
+
args = job.fetch("args", [])
|
|
68
|
+
job_class = job["class"]
|
|
69
|
+
case job_class
|
|
70
|
+
when "Sidekiq::Extensions::DelayedModel"
|
|
71
|
+
safe_load(args[0], job_class) do |target, method, _|
|
|
72
|
+
"#{target.class}##{method}"
|
|
73
|
+
end
|
|
74
|
+
when /\ASidekiq::Extensions::Delayed/
|
|
75
|
+
safe_load(args[0], job_class) do |target, method, _|
|
|
76
|
+
"#{target}.#{method}"
|
|
77
|
+
end
|
|
78
|
+
else
|
|
79
|
+
job_class
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Based on: https://github.com/mperham/sidekiq/blob/63ee43353bd3b753beb0233f64865e658abeb1c3/lib/sidekiq/api.rb#L403-L412
|
|
84
|
+
def safe_load(content, default)
|
|
85
|
+
if Gem::Version.new(YAML::VERSION) >= Gem::Version.new("4.0.0")
|
|
86
|
+
yield(*YAML.unsafe_load(content))
|
|
87
|
+
else
|
|
88
|
+
yield(*YAML.load(content)) # rubocop:disable Security/YAMLLoad
|
|
89
|
+
end
|
|
90
|
+
rescue => error
|
|
91
|
+
# Sidekiq issue #1761: in dev mode, it's possible to have jobs enqueued
|
|
92
|
+
# which haven't been loaded into memory yet so the YAML can't be
|
|
93
|
+
# loaded.
|
|
94
|
+
Appsignal.internal_logger.warn(
|
|
95
|
+
"Unable to load YAML from Sidekiq delayed extension job: #{error.message}"
|
|
96
|
+
)
|
|
97
|
+
default
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Sidekiq client middleware that runs on enqueue. Records an
|
|
102
|
+
# `enqueue.sidekiq` event so the enqueue shows up under the active
|
|
103
|
+
# transaction.
|
|
104
|
+
#
|
|
105
|
+
# Like all AppSignal events, this only records when there's an active
|
|
106
|
+
# transaction (e.g. enqueuing from within a web request or another job). An
|
|
107
|
+
# enqueue with no transaction is a transparent pass-through.
|
|
108
|
+
#
|
|
109
|
+
# @!visibility private
|
|
110
|
+
class SidekiqClientMiddleware
|
|
111
|
+
def call(_worker_class, job, _queue, _redis_pool, &block)
|
|
112
|
+
# Under Active Job the enqueue is already recorded as an
|
|
113
|
+
# `enqueue.active_job` event, so skip recording it again here.
|
|
114
|
+
return yield if Appsignal::Transaction.current? &&
|
|
115
|
+
Appsignal::Transaction.current.job_enqueue_events_suppressed?
|
|
116
|
+
|
|
117
|
+
title = "enqueue #{SidekiqActionName.parse_action_name(job)} job"
|
|
118
|
+
Appsignal.instrument("enqueue.sidekiq", title, &block)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
52
122
|
# @!visibility private
|
|
53
123
|
class SidekiqMiddleware
|
|
54
124
|
include Appsignal::Hooks::Helpers
|
|
@@ -77,7 +147,7 @@ module Appsignal
|
|
|
77
147
|
|
|
78
148
|
begin
|
|
79
149
|
Appsignal.instrument "perform_job.sidekiq", &block
|
|
80
|
-
rescue Exception => exception
|
|
150
|
+
rescue Exception => exception
|
|
81
151
|
job_status = :failed
|
|
82
152
|
raise exception
|
|
83
153
|
ensure
|
|
@@ -124,7 +194,7 @@ module Appsignal
|
|
|
124
194
|
end
|
|
125
195
|
|
|
126
196
|
def formatted_action_name(job)
|
|
127
|
-
sidekiq_action_name = parse_action_name(job)
|
|
197
|
+
sidekiq_action_name = SidekiqActionName.parse_action_name(job)
|
|
128
198
|
return unless sidekiq_action_name
|
|
129
199
|
|
|
130
200
|
complete_action = sidekiq_action_name =~ /\.|#/
|
|
@@ -143,30 +213,12 @@ module Appsignal
|
|
|
143
213
|
end
|
|
144
214
|
end
|
|
145
215
|
|
|
146
|
-
# Based on: https://github.com/mperham/sidekiq/blob/63ee43353bd3b753beb0233f64865e658abeb1c3/lib/sidekiq/api.rb#L316-L334
|
|
147
|
-
def parse_action_name(job)
|
|
148
|
-
args = job.fetch("args", [])
|
|
149
|
-
job_class = job["class"]
|
|
150
|
-
case job_class
|
|
151
|
-
when "Sidekiq::Extensions::DelayedModel"
|
|
152
|
-
safe_load(args[0], job_class) do |target, method, _|
|
|
153
|
-
"#{target.class}##{method}"
|
|
154
|
-
end
|
|
155
|
-
when /\ASidekiq::Extensions::Delayed/
|
|
156
|
-
safe_load(args[0], job_class) do |target, method, _|
|
|
157
|
-
"#{target}.#{method}"
|
|
158
|
-
end
|
|
159
|
-
else
|
|
160
|
-
job_class
|
|
161
|
-
end
|
|
162
|
-
end
|
|
163
|
-
|
|
164
216
|
# Based on: https://github.com/mperham/sidekiq/blob/63ee43353bd3b753beb0233f64865e658abeb1c3/lib/sidekiq/api.rb#L336-L358
|
|
165
217
|
def parse_arguments(job)
|
|
166
218
|
args = job.fetch("args", [])
|
|
167
219
|
case job["class"]
|
|
168
220
|
when /\ASidekiq::Extensions::Delayed/
|
|
169
|
-
safe_load(args[0], args) do |_, _, arg|
|
|
221
|
+
SidekiqActionName.safe_load(args[0], args) do |_, _, arg|
|
|
170
222
|
arg
|
|
171
223
|
end
|
|
172
224
|
else
|
|
@@ -179,21 +231,6 @@ module Appsignal
|
|
|
179
231
|
args
|
|
180
232
|
end
|
|
181
233
|
end
|
|
182
|
-
|
|
183
|
-
# Based on: https://github.com/mperham/sidekiq/blob/63ee43353bd3b753beb0233f64865e658abeb1c3/lib/sidekiq/api.rb#L403-L412
|
|
184
|
-
def safe_load(content, default)
|
|
185
|
-
if YAML::VERSION >= "4.0.0"
|
|
186
|
-
yield(*YAML.unsafe_load(content))
|
|
187
|
-
else
|
|
188
|
-
yield(*YAML.load(content))
|
|
189
|
-
end
|
|
190
|
-
rescue => error
|
|
191
|
-
# Sidekiq issue #1761: in dev mode, it's possible to have jobs enqueued
|
|
192
|
-
# which haven't been loaded into memory yet so the YAML can't be
|
|
193
|
-
# loaded.
|
|
194
|
-
Appsignal.internal_logger.warn "Unable to load YAML: #{error.message}"
|
|
195
|
-
default
|
|
196
|
-
end
|
|
197
234
|
end
|
|
198
235
|
end
|
|
199
236
|
end
|
data/lib/appsignal/logger.rb
CHANGED
|
@@ -67,6 +67,8 @@ module Appsignal
|
|
|
67
67
|
# @return [Integer]
|
|
68
68
|
attr_reader :level
|
|
69
69
|
|
|
70
|
+
# rubocop:disable Lint/MissingSuper
|
|
71
|
+
|
|
70
72
|
# Create a new logger instance
|
|
71
73
|
#
|
|
72
74
|
# @param group [String] Name of the group for this logger.
|
|
@@ -87,6 +89,7 @@ module Appsignal
|
|
|
87
89
|
@appsignal_attributes = attributes
|
|
88
90
|
@loggers = []
|
|
89
91
|
end
|
|
92
|
+
# rubocop:enable Lint/MissingSuper
|
|
90
93
|
|
|
91
94
|
# Sets the formatter for this logger and all broadcasted loggers.
|
|
92
95
|
# @param formatter [Proc] The formatter to use for log messages.
|
|
@@ -101,7 +104,7 @@ module Appsignal
|
|
|
101
104
|
# We support the various methods in the Ruby
|
|
102
105
|
# logger class by supplying this method.
|
|
103
106
|
# @!visibility private
|
|
104
|
-
def add(severity, message = nil, group = nil, &block)
|
|
107
|
+
def add(severity, message = nil, group = nil, &block)
|
|
105
108
|
# If we do not need to broadcast to any loggers and the severity is
|
|
106
109
|
# below the log level, we can return early.
|
|
107
110
|
severity ||= UNKNOWN
|
|
@@ -108,7 +108,7 @@ module Appsignal
|
|
|
108
108
|
# @see #instrument_app_call
|
|
109
109
|
def instrument_app_call_with_exception_handling(env, transaction, wrapped_instrumentation)
|
|
110
110
|
instrument_app_call(env, transaction)
|
|
111
|
-
rescue Exception => error
|
|
111
|
+
rescue Exception => error
|
|
112
112
|
report_errors =
|
|
113
113
|
if @report_errors == DEFAULT_ERROR_REPORTING
|
|
114
114
|
# If there's no parent transaction, report the error
|
|
@@ -53,7 +53,7 @@ module Appsignal
|
|
|
53
53
|
@body_already_closed = true
|
|
54
54
|
rescue *IGNORED_ERRORS # Do not report
|
|
55
55
|
raise
|
|
56
|
-
rescue Exception => error
|
|
56
|
+
rescue Exception => error
|
|
57
57
|
appsignal_report_error(error)
|
|
58
58
|
raise error
|
|
59
59
|
end
|
|
@@ -109,7 +109,7 @@ module Appsignal
|
|
|
109
109
|
end
|
|
110
110
|
rescue *IGNORED_ERRORS # Do not report
|
|
111
111
|
raise
|
|
112
|
-
rescue Exception => error
|
|
112
|
+
rescue Exception => error
|
|
113
113
|
appsignal_report_error(error)
|
|
114
114
|
raise error
|
|
115
115
|
end
|
|
@@ -130,7 +130,7 @@ module Appsignal
|
|
|
130
130
|
end
|
|
131
131
|
rescue *IGNORED_ERRORS # Do not report
|
|
132
132
|
raise
|
|
133
|
-
rescue Exception => error
|
|
133
|
+
rescue Exception => error
|
|
134
134
|
appsignal_report_error(error)
|
|
135
135
|
raise error
|
|
136
136
|
end
|
|
@@ -156,7 +156,7 @@ module Appsignal
|
|
|
156
156
|
end
|
|
157
157
|
rescue *IGNORED_ERRORS # Do not report
|
|
158
158
|
raise
|
|
159
|
-
rescue Exception => error
|
|
159
|
+
rescue Exception => error
|
|
160
160
|
appsignal_report_error(error)
|
|
161
161
|
raise error
|
|
162
162
|
end
|
|
@@ -174,7 +174,7 @@ module Appsignal
|
|
|
174
174
|
end
|
|
175
175
|
rescue *IGNORED_ERRORS # Do not report
|
|
176
176
|
raise
|
|
177
|
-
rescue Exception => error
|
|
177
|
+
rescue Exception => error
|
|
178
178
|
appsignal_report_error(error)
|
|
179
179
|
raise error
|
|
180
180
|
end
|
|
@@ -14,6 +14,7 @@ module Appsignal
|
|
|
14
14
|
|
|
15
15
|
HANAMI_ACTION_INSTANCE = "hanami.action_instance"
|
|
16
16
|
ROUTER_PARAMS = "router.params"
|
|
17
|
+
private_constant :HANAMI_ACTION_INSTANCE, :ROUTER_PARAMS
|
|
17
18
|
|
|
18
19
|
def add_transaction_metadata_after(transaction, request)
|
|
19
20
|
action_name = fetch_hanami_action(request.env)
|
|
@@ -290,6 +290,53 @@ module Appsignal
|
|
|
290
290
|
@store[key]
|
|
291
291
|
end
|
|
292
292
|
|
|
293
|
+
# @!visibility private
|
|
294
|
+
#
|
|
295
|
+
# Run a block during which downstream HTTP client integrations (Net::HTTP,
|
|
296
|
+
# ...) skip recording their own event. Used when an outer HTTP client
|
|
297
|
+
# integration (Faraday) already records the request, so the same request is
|
|
298
|
+
# not instrumented twice as nested client events.
|
|
299
|
+
def suppress_http_client_events
|
|
300
|
+
# Restore the previous value rather than forcing `false`, so nested calls
|
|
301
|
+
# don't unsuppress while an outer block is still active.
|
|
302
|
+
previously_suppressed = store("http_client")[:suppressed]
|
|
303
|
+
store("http_client")[:suppressed] = true
|
|
304
|
+
yield
|
|
305
|
+
ensure
|
|
306
|
+
store("http_client")[:suppressed] = previously_suppressed
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
# @!visibility private
|
|
310
|
+
def http_client_events_suppressed?
|
|
311
|
+
store("http_client")[:suppressed] == true
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
# @!visibility private
|
|
315
|
+
#
|
|
316
|
+
# Run a block during which nested job enqueue integrations (Sidekiq, Resque,
|
|
317
|
+
# ...) skip recording their own enqueue event. Used when an outer integration
|
|
318
|
+
# (Active Job) already records the enqueue, so the same enqueue is not
|
|
319
|
+
# instrumented twice as nested enqueue events.
|
|
320
|
+
def suppress_job_enqueue_events
|
|
321
|
+
# Restore the previous value rather than forcing `false`, so nested calls
|
|
322
|
+
# don't unsuppress while an outer block is still active.
|
|
323
|
+
previously_suppressed = store("job_enqueue")[:suppressed]
|
|
324
|
+
store("job_enqueue")[:suppressed] = true
|
|
325
|
+
yield
|
|
326
|
+
ensure
|
|
327
|
+
store("job_enqueue")[:suppressed] = previously_suppressed
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
# @!visibility private
|
|
331
|
+
def job_enqueue_events_suppressed?
|
|
332
|
+
# When enqueue instrumentation is disabled, every enqueue integration
|
|
333
|
+
# treats its event as suppressed. That is how the config option turns the
|
|
334
|
+
# enqueue events off across all integrations at once.
|
|
335
|
+
return true if Appsignal.config && !Appsignal.config[:enable_job_enqueue_instrumentation]
|
|
336
|
+
|
|
337
|
+
store("job_enqueue")[:suppressed] == true
|
|
338
|
+
end
|
|
339
|
+
|
|
293
340
|
# Add parameters to the transaction.
|
|
294
341
|
#
|
|
295
342
|
# When this method is called multiple times, it will merge the request parameters.
|
|
@@ -311,7 +358,7 @@ module Appsignal
|
|
|
311
358
|
def add_params(given_params = nil, &block)
|
|
312
359
|
@params.add(given_params, &block)
|
|
313
360
|
end
|
|
314
|
-
alias
|
|
361
|
+
alias set_params add_params
|
|
315
362
|
|
|
316
363
|
# @since 4.0.0
|
|
317
364
|
# @return [void]
|
|
@@ -337,7 +384,7 @@ module Appsignal
|
|
|
337
384
|
def add_params_if_nil(given_params = nil, &block)
|
|
338
385
|
add_params(given_params, &block) if !@params.value? && !@params.empty?
|
|
339
386
|
end
|
|
340
|
-
alias
|
|
387
|
+
alias set_params_if_nil add_params_if_nil
|
|
341
388
|
|
|
342
389
|
# Add tags to the transaction.
|
|
343
390
|
#
|
|
@@ -357,7 +404,7 @@ module Appsignal
|
|
|
357
404
|
def add_tags(given_tags = {})
|
|
358
405
|
@tags.merge!(given_tags)
|
|
359
406
|
end
|
|
360
|
-
alias
|
|
407
|
+
alias set_tags add_tags
|
|
361
408
|
|
|
362
409
|
# Add session data to the transaction.
|
|
363
410
|
#
|
|
@@ -379,7 +426,7 @@ module Appsignal
|
|
|
379
426
|
def add_session_data(given_session_data = nil, &block)
|
|
380
427
|
@session_data.add(given_session_data, &block)
|
|
381
428
|
end
|
|
382
|
-
alias
|
|
429
|
+
alias set_session_data add_session_data
|
|
383
430
|
|
|
384
431
|
# Set session data on the transaction if not already set.
|
|
385
432
|
#
|
|
@@ -401,7 +448,7 @@ module Appsignal
|
|
|
401
448
|
def add_session_data_if_nil(given_session_data = nil, &block)
|
|
402
449
|
add_session_data(given_session_data, &block) unless @session_data.value?
|
|
403
450
|
end
|
|
404
|
-
alias
|
|
451
|
+
alias set_session_data_if_nil add_session_data_if_nil
|
|
405
452
|
|
|
406
453
|
# Add headers to the transaction.
|
|
407
454
|
#
|
|
@@ -418,7 +465,7 @@ module Appsignal
|
|
|
418
465
|
def add_headers(given_headers = nil, &block)
|
|
419
466
|
@headers.add(given_headers, &block)
|
|
420
467
|
end
|
|
421
|
-
alias
|
|
468
|
+
alias set_headers add_headers
|
|
422
469
|
|
|
423
470
|
# Add headers to the transaction if not already set.
|
|
424
471
|
#
|
|
@@ -439,7 +486,7 @@ module Appsignal
|
|
|
439
486
|
def add_headers_if_nil(given_headers = nil, &block)
|
|
440
487
|
add_headers(given_headers, &block) unless @headers.value?
|
|
441
488
|
end
|
|
442
|
-
alias
|
|
489
|
+
alias set_headers_if_nil add_headers_if_nil
|
|
443
490
|
|
|
444
491
|
# Add custom data to the transaction.
|
|
445
492
|
#
|
|
@@ -454,7 +501,7 @@ module Appsignal
|
|
|
454
501
|
def add_custom_data(data)
|
|
455
502
|
@custom_data.add(data)
|
|
456
503
|
end
|
|
457
|
-
alias
|
|
504
|
+
alias set_custom_data add_custom_data
|
|
458
505
|
|
|
459
506
|
# Add breadcrumbs to the transaction.
|
|
460
507
|
#
|
|
@@ -601,8 +648,8 @@ module Appsignal
|
|
|
601
648
|
error = error.cause
|
|
602
649
|
end
|
|
603
650
|
end
|
|
604
|
-
alias
|
|
605
|
-
|
|
651
|
+
alias set_error add_error
|
|
652
|
+
alias add_exception add_error
|
|
606
653
|
|
|
607
654
|
# @!visibility private
|
|
608
655
|
# @see Helpers::Instrumentation#instrument
|
|
@@ -654,7 +701,7 @@ module Appsignal
|
|
|
654
701
|
def to_h
|
|
655
702
|
JSON.parse(@ext.to_json)
|
|
656
703
|
end
|
|
657
|
-
|
|
704
|
+
alias to_hash to_h
|
|
658
705
|
|
|
659
706
|
protected
|
|
660
707
|
|
|
@@ -738,6 +785,7 @@ module Appsignal
|
|
|
738
785
|
|
|
739
786
|
BACKTRACE_REGEX =
|
|
740
787
|
%r{(?<gem>[\w-]+ \(.+\) )?(?<path>:?/?\w+?.+?):(?<line>:?\d+)(?::in `(?<method>.+)')?$}.freeze
|
|
788
|
+
private_constant :BACKTRACE_REGEX
|
|
741
789
|
|
|
742
790
|
def first_formatted_backtrace_line(error)
|
|
743
791
|
backtrace = cleaned_backtrace(error.backtrace)
|
|
@@ -6,6 +6,7 @@ module Appsignal
|
|
|
6
6
|
REPLACEMENT_KEY = "?"
|
|
7
7
|
|
|
8
8
|
module ClassMethods
|
|
9
|
+
# rubocop:disable Style/OptionalBooleanParameter
|
|
9
10
|
def sanitize(params, only_top_level = false, key_sanitizer = nil)
|
|
10
11
|
case params
|
|
11
12
|
when Hash
|
|
@@ -16,6 +17,7 @@ module Appsignal
|
|
|
16
17
|
REPLACEMENT_KEY
|
|
17
18
|
end
|
|
18
19
|
end
|
|
20
|
+
# rubocop:enable Style/OptionalBooleanParameter
|
|
19
21
|
|
|
20
22
|
private
|
|
21
23
|
|
data/lib/appsignal/version.rb
CHANGED
data/lib/appsignal.rb
CHANGED
|
@@ -105,7 +105,7 @@ module Appsignal
|
|
|
105
105
|
#
|
|
106
106
|
# @return [void]
|
|
107
107
|
# @since 0.7.0
|
|
108
|
-
def start
|
|
108
|
+
def start
|
|
109
109
|
if ENV.fetch("_APPSIGNAL_DIAGNOSE", false)
|
|
110
110
|
internal_logger.info("Skipping start in diagnose context")
|
|
111
111
|
return
|
|
@@ -169,7 +169,7 @@ module Appsignal
|
|
|
169
169
|
# @param block [Proc] Optional block to configure the config object.
|
|
170
170
|
# @return [void]
|
|
171
171
|
# @!visibility private
|
|
172
|
-
def _load_config!(env_param = nil, &block)
|
|
172
|
+
def _load_config!(env_param = nil, &block)
|
|
173
173
|
# Ensure it's not an empty string if it's a value
|
|
174
174
|
proper_env_param = env_param&.to_s&.strip
|
|
175
175
|
# Unset it if it's an empty string
|
|
@@ -8,7 +8,7 @@ require "json"
|
|
|
8
8
|
#
|
|
9
9
|
# For even more information:
|
|
10
10
|
# https://docs.appsignal.com/ruby/integrations/puma.html
|
|
11
|
-
Puma::Plugin.create do
|
|
11
|
+
Puma::Plugin.create do
|
|
12
12
|
def start(launcher)
|
|
13
13
|
@launcher = launcher
|
|
14
14
|
log_debug "AppSignal: Puma plugin start."
|