appsignal 4.2.0 → 4.5.17
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 +443 -0
- data/README.md +0 -3
- data/Rakefile +1 -1
- data/appsignal.gemspec +2 -1
- data/build_matrix.yml +33 -0
- data/ext/agent.rb +27 -27
- data/ext/appsignal_extension.c +90 -73
- data/ext/base.rb +3 -1
- data/lib/appsignal/check_in/event.rb +55 -0
- data/lib/appsignal/check_in/scheduler.rb +8 -2
- data/lib/appsignal/check_in.rb +9 -8
- data/lib/appsignal/config.rb +36 -15
- data/lib/appsignal/custom_marker.rb +72 -0
- data/lib/appsignal/environment.rb +1 -0
- data/lib/appsignal/event_formatter/action_view/render_formatter.rb +4 -6
- data/lib/appsignal/event_formatter/view_component/render_formatter.rb +4 -6
- data/lib/appsignal/helpers/instrumentation.rb +5 -0
- data/lib/appsignal/hooks/active_job.rb +25 -5
- data/lib/appsignal/hooks/at_exit.rb +18 -4
- data/lib/appsignal/hooks/ownership.rb +44 -0
- data/lib/appsignal/hooks.rb +1 -0
- data/lib/appsignal/integrations/capistrano/appsignal.cap +4 -8
- data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +8 -11
- data/lib/appsignal/integrations/http.rb +2 -1
- data/lib/appsignal/integrations/ownership.rb +51 -0
- data/lib/appsignal/integrations/rake.rb +14 -2
- data/lib/appsignal/integrations/sidekiq.rb +14 -3
- data/lib/appsignal/internal_errors.rb +19 -0
- data/lib/appsignal/logger.rb +121 -69
- data/lib/appsignal/marker.rb +1 -1
- data/lib/appsignal/probes/sidekiq.rb +5 -1
- data/lib/appsignal/rack/body_wrapper.rb +1 -1
- data/lib/appsignal/rack/event_handler.rb +7 -5
- data/lib/appsignal/transaction.rb +91 -13
- data/lib/appsignal/version.rb +1 -1
- data/lib/appsignal.rb +82 -11
- data/resources/cacert.pem +164 -87
- metadata +8 -4
data/lib/appsignal/config.rb
CHANGED
@@ -39,8 +39,10 @@ module Appsignal
|
|
39
39
|
ENV.fetch("APPSIGNAL_APP_ENV", nil),
|
40
40
|
ENV.fetch("RAILS_ENV", nil),
|
41
41
|
ENV.fetch("RACK_ENV", nil)
|
42
|
-
].compact.each do |
|
43
|
-
|
42
|
+
].compact.each do |env_value|
|
43
|
+
value = env_value.to_s.strip
|
44
|
+
next if value.empty?
|
45
|
+
return value if value
|
44
46
|
end
|
45
47
|
|
46
48
|
loader_defaults.reverse.each do |loader_defaults|
|
@@ -91,6 +93,7 @@ module Appsignal
|
|
91
93
|
:ca_file_path => File.expand_path(File.join("../../../resources/cacert.pem"), __FILE__),
|
92
94
|
:dns_servers => [],
|
93
95
|
:enable_allocation_tracking => true,
|
96
|
+
:enable_at_exit_hook => "on_error",
|
94
97
|
:enable_at_exit_reporter => true,
|
95
98
|
:enable_host_metrics => true,
|
96
99
|
:enable_minutely_probes => true,
|
@@ -111,10 +114,12 @@ module Appsignal
|
|
111
114
|
:ignore_namespaces => [],
|
112
115
|
:instrument_http_rb => true,
|
113
116
|
:instrument_net_http => true,
|
117
|
+
:instrument_ownership => true,
|
114
118
|
:instrument_redis => true,
|
115
119
|
:instrument_sequel => true,
|
116
120
|
:log => "file",
|
117
121
|
:logging_endpoint => "https://appsignal-endpoint.net",
|
122
|
+
:ownership_set_namespace => false,
|
118
123
|
:request_headers => %w[
|
119
124
|
HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING
|
120
125
|
HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_CONNECTION
|
@@ -149,6 +154,7 @@ module Appsignal
|
|
149
154
|
:name => "APPSIGNAL_APP_NAME",
|
150
155
|
:bind_address => "APPSIGNAL_BIND_ADDRESS",
|
151
156
|
:ca_file_path => "APPSIGNAL_CA_FILE_PATH",
|
157
|
+
:enable_at_exit_hook => "APPSIGNAL_ENABLE_AT_EXIT_HOOK",
|
152
158
|
:hostname => "APPSIGNAL_HOSTNAME",
|
153
159
|
:host_role => "APPSIGNAL_HOST_ROLE",
|
154
160
|
:http_proxy => "APPSIGNAL_HTTP_PROXY",
|
@@ -160,6 +166,7 @@ module Appsignal
|
|
160
166
|
:push_api_key => "APPSIGNAL_PUSH_API_KEY",
|
161
167
|
:sidekiq_report_errors => "APPSIGNAL_SIDEKIQ_REPORT_ERRORS",
|
162
168
|
:statsd_port => "APPSIGNAL_STATSD_PORT",
|
169
|
+
:nginx_port => "APPSIGNAL_NGINX_PORT",
|
163
170
|
:working_directory_path => "APPSIGNAL_WORKING_DIRECTORY_PATH",
|
164
171
|
:revision => "APP_REVISION"
|
165
172
|
}.freeze
|
@@ -181,8 +188,10 @@ module Appsignal
|
|
181
188
|
:files_world_accessible => "APPSIGNAL_FILES_WORLD_ACCESSIBLE",
|
182
189
|
:instrument_http_rb => "APPSIGNAL_INSTRUMENT_HTTP_RB",
|
183
190
|
:instrument_net_http => "APPSIGNAL_INSTRUMENT_NET_HTTP",
|
191
|
+
:instrument_ownership => "APPSIGNAL_INSTRUMENT_OWNERSHIP",
|
184
192
|
:instrument_redis => "APPSIGNAL_INSTRUMENT_REDIS",
|
185
193
|
:instrument_sequel => "APPSIGNAL_INSTRUMENT_SEQUEL",
|
194
|
+
:ownership_set_namespace => "APPSIGNAL_OWNERSHIP_SET_NAMESPACE",
|
186
195
|
:running_in_container => "APPSIGNAL_RUNNING_IN_CONTAINER",
|
187
196
|
:send_environment_metadata => "APPSIGNAL_SEND_ENVIRONMENT_METADATA",
|
188
197
|
:send_params => "APPSIGNAL_SEND_PARAMS",
|
@@ -242,8 +251,8 @@ module Appsignal
|
|
242
251
|
)
|
243
252
|
@load_yaml_file = load_yaml_file
|
244
253
|
@root_path = root_path.to_s
|
245
|
-
@
|
246
|
-
@
|
254
|
+
@yml_config_file_error = false
|
255
|
+
@yml_config_file = yml_config_file
|
247
256
|
@valid = false
|
248
257
|
|
249
258
|
@env = env.to_s
|
@@ -385,8 +394,12 @@ module Appsignal
|
|
385
394
|
@valid
|
386
395
|
end
|
387
396
|
|
397
|
+
def active_for_env?
|
398
|
+
config_hash[:active]
|
399
|
+
end
|
400
|
+
|
388
401
|
def active?
|
389
|
-
|
402
|
+
valid? && active_for_env?
|
390
403
|
end
|
391
404
|
|
392
405
|
# @api private
|
@@ -424,6 +437,7 @@ module Appsignal
|
|
424
437
|
ENV["_APPSIGNAL_RUNNING_IN_CONTAINER"] = config_hash[:running_in_container].to_s
|
425
438
|
ENV["_APPSIGNAL_SEND_ENVIRONMENT_METADATA"] = config_hash[:send_environment_metadata].to_s
|
426
439
|
ENV["_APPSIGNAL_STATSD_PORT"] = config_hash[:statsd_port].to_s
|
440
|
+
ENV["_APPSIGNAL_NGINX_PORT"] = config_hash[:nginx_port].to_s
|
427
441
|
if config_hash[:working_directory_path]
|
428
442
|
ENV["_APPSIGNAL_WORKING_DIRECTORY_PATH"] = config_hash[:working_directory_path]
|
429
443
|
end
|
@@ -436,12 +450,16 @@ module Appsignal
|
|
436
450
|
merge(options)
|
437
451
|
end
|
438
452
|
|
453
|
+
# Apply any overrides for invalid settings.
|
439
454
|
# @api private
|
440
|
-
def
|
441
|
-
# Apply any overrides for invalid settings.
|
455
|
+
def apply_overrides
|
442
456
|
@override_config = determine_overrides
|
443
457
|
merge(override_config)
|
458
|
+
end
|
444
459
|
|
460
|
+
# @return [void]
|
461
|
+
# @api private
|
462
|
+
def validate
|
445
463
|
# Strip path from endpoint so we're backwards compatible with
|
446
464
|
# earlier versions of the gem.
|
447
465
|
# TODO: Move to its own method, maybe in `#[]=`?
|
@@ -466,6 +484,7 @@ module Appsignal
|
|
466
484
|
# of the Ruby app.
|
467
485
|
#
|
468
486
|
# @api private
|
487
|
+
# @return [void]
|
469
488
|
# @since 4.0.0
|
470
489
|
def freeze
|
471
490
|
super
|
@@ -475,9 +494,9 @@ module Appsignal
|
|
475
494
|
|
476
495
|
# @api private
|
477
496
|
def yml_config_file?
|
478
|
-
return false unless
|
497
|
+
return false unless yml_config_file
|
479
498
|
|
480
|
-
File.exist?(
|
499
|
+
File.exist?(yml_config_file)
|
481
500
|
end
|
482
501
|
|
483
502
|
private
|
@@ -486,8 +505,8 @@ module Appsignal
|
|
486
505
|
Appsignal.internal_logger
|
487
506
|
end
|
488
507
|
|
489
|
-
def
|
490
|
-
@
|
508
|
+
def yml_config_file
|
509
|
+
@yml_config_file ||=
|
491
510
|
root_path.nil? ? nil : File.join(root_path, "config", "appsignal.yml")
|
492
511
|
end
|
493
512
|
|
@@ -499,6 +518,8 @@ module Appsignal
|
|
499
518
|
# environment variable is present and not empty.
|
500
519
|
env_push_api_key = ENV["APPSIGNAL_PUSH_API_KEY"] || ""
|
501
520
|
hash[:active] = true unless env_push_api_key.strip.empty?
|
521
|
+
|
522
|
+
hash[:enable_at_exit_hook] = "always" if Appsignal::Extension.running_in_container?
|
502
523
|
end
|
503
524
|
end
|
504
525
|
|
@@ -506,7 +527,7 @@ module Appsignal
|
|
506
527
|
return unless yml_config_file?
|
507
528
|
|
508
529
|
read_options = YAML::VERSION >= "4.0.0" ? { :aliases => true } : {}
|
509
|
-
configurations = YAML.load(ERB.new(File.read(
|
530
|
+
configurations = YAML.load(ERB.new(File.read(yml_config_file)).result, **read_options)
|
510
531
|
config_for_this_env = configurations[env]
|
511
532
|
if config_for_this_env
|
512
533
|
config_for_this_env.transform_keys(&:to_sym)
|
@@ -515,10 +536,10 @@ module Appsignal
|
|
515
536
|
nil
|
516
537
|
end
|
517
538
|
rescue => e
|
518
|
-
@
|
539
|
+
@yml_config_file_error = true
|
519
540
|
message = "An error occurred while loading the AppSignal config file. " \
|
520
541
|
"Not starting AppSignal.\n" \
|
521
|
-
"File: #{
|
542
|
+
"File: #{yml_config_file.inspect}\n" \
|
522
543
|
"#{e.class.name}: #{e}"
|
523
544
|
Kernel.warn "appsignal: #{message}"
|
524
545
|
logger.error "#{message}\n#{e.backtrace.join("\n")}"
|
@@ -570,7 +591,7 @@ module Appsignal
|
|
570
591
|
# If an error was detected during config file reading/parsing and the new
|
571
592
|
# behavior is enabled to not start AppSignal on incomplete config, do not
|
572
593
|
# start AppSignal.
|
573
|
-
config[:active] = false if @
|
594
|
+
config[:active] = false if @yml_config_file_error
|
574
595
|
|
575
596
|
if config_hash[:activejob_report_errors] == "discard" &&
|
576
597
|
!Appsignal::Hooks::ActiveJobHook.version_7_1_or_higher?
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Appsignal
|
4
|
+
# Custom markers are used on AppSignal.com to indicate events in an
|
5
|
+
# application, to give additional context on graph timelines.
|
6
|
+
#
|
7
|
+
# This helper class will send a request to the AppSignal public endpoint to
|
8
|
+
# create a Custom marker for the application on AppSignal.com.
|
9
|
+
#
|
10
|
+
# @see https://docs.appsignal.com/api/public-endpoint/custom-markers.html
|
11
|
+
# Public Endpoint API markers endpoint documentation
|
12
|
+
# @see https://docs.appsignal.com/appsignal/terminology.html#markers
|
13
|
+
# Terminology: Markers
|
14
|
+
class CustomMarker
|
15
|
+
# @param icon [String] icon to use for the marker, like an emoji.
|
16
|
+
# @param message [String] name of the user that is creating the
|
17
|
+
# marker.
|
18
|
+
# @param created_at [Time/String] A Ruby time object or a valid ISO8601
|
19
|
+
# timestamp.
|
20
|
+
# @return [Boolean]
|
21
|
+
def self.report(
|
22
|
+
icon: nil,
|
23
|
+
message: nil,
|
24
|
+
created_at: nil
|
25
|
+
)
|
26
|
+
new(
|
27
|
+
{
|
28
|
+
:icon => icon,
|
29
|
+
:message => message,
|
30
|
+
:created_at => created_at.respond_to?(:iso8601) ? created_at.iso8601 : created_at
|
31
|
+
}.compact
|
32
|
+
).transmit
|
33
|
+
end
|
34
|
+
|
35
|
+
# @api private
|
36
|
+
def initialize(marker_data)
|
37
|
+
@marker_data = marker_data
|
38
|
+
end
|
39
|
+
|
40
|
+
# @api private
|
41
|
+
def transmit
|
42
|
+
unless Appsignal.config
|
43
|
+
Appsignal.internal_logger.warn(
|
44
|
+
"Did not transmit custom marker: no AppSignal config loaded"
|
45
|
+
)
|
46
|
+
return false
|
47
|
+
end
|
48
|
+
|
49
|
+
transmitter = Transmitter.new(
|
50
|
+
"#{Appsignal.config[:logging_endpoint]}/markers",
|
51
|
+
Appsignal.config
|
52
|
+
)
|
53
|
+
response = transmitter.transmit(@marker_data)
|
54
|
+
|
55
|
+
if (200...300).include?(response.code.to_i)
|
56
|
+
Appsignal.internal_logger.info("Transmitted custom marker")
|
57
|
+
true
|
58
|
+
else
|
59
|
+
Appsignal.internal_logger.error(
|
60
|
+
"Failed to transmit custom marker: #{response.code} status code"
|
61
|
+
)
|
62
|
+
false
|
63
|
+
end
|
64
|
+
rescue => e
|
65
|
+
Appsignal.internal_logger.error(
|
66
|
+
"Failed to transmit custom marker: #{e.class}: #{e.message}\n" \
|
67
|
+
"#{e.backtrace}"
|
68
|
+
)
|
69
|
+
false
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -7,17 +7,15 @@ module Appsignal
|
|
7
7
|
class RenderFormatter
|
8
8
|
BLANK = ""
|
9
9
|
|
10
|
-
attr_reader :root_path
|
11
|
-
|
12
|
-
def initialize
|
13
|
-
@root_path = "#{Rails.root}/"
|
14
|
-
end
|
15
|
-
|
16
10
|
def format(payload)
|
17
11
|
return nil unless payload[:identifier]
|
18
12
|
|
19
13
|
[payload[:identifier].sub(root_path, BLANK), nil]
|
20
14
|
end
|
15
|
+
|
16
|
+
def root_path
|
17
|
+
@root_path ||= "#{Rails.root}/"
|
18
|
+
end
|
21
19
|
end
|
22
20
|
end
|
23
21
|
end
|
@@ -7,14 +7,12 @@ module Appsignal
|
|
7
7
|
class RenderFormatter
|
8
8
|
BLANK = ""
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
def initialize
|
13
|
-
@root_path = "#{Rails.root}/"
|
10
|
+
def format(payload)
|
11
|
+
[payload[:name], payload[:identifier].sub(root_path, BLANK)]
|
14
12
|
end
|
15
13
|
|
16
|
-
def
|
17
|
-
|
14
|
+
def root_path
|
15
|
+
@root_path ||= "#{Rails.root}/"
|
18
16
|
end
|
19
17
|
end
|
20
18
|
end
|
@@ -154,6 +154,11 @@ module Appsignal
|
|
154
154
|
#
|
155
155
|
# @see monitor
|
156
156
|
def monitor_and_stop(action:, namespace: nil, &block)
|
157
|
+
Appsignal::Utils::StdoutAndLoggerMessage.warning \
|
158
|
+
"The `Appsignal.monitor_and_stop` helper is deprecated. " \
|
159
|
+
"Use the `Appsignal.monitor` along with our `enable_at_exit_hook` " \
|
160
|
+
"option instead."
|
161
|
+
|
157
162
|
monitor(:namespace => namespace, :action => action, &block)
|
158
163
|
ensure
|
159
164
|
Appsignal.stop("monitor_and_stop")
|
@@ -42,7 +42,16 @@ module Appsignal
|
|
42
42
|
end
|
43
43
|
|
44
44
|
module ActiveJobClassInstrumentation
|
45
|
-
def execute(job)
|
45
|
+
def execute(job) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
46
|
+
enqueued_at = job["enqueued_at"]
|
47
|
+
queue_start = Time.parse(enqueued_at) if enqueued_at
|
48
|
+
queue_time =
|
49
|
+
if queue_start
|
50
|
+
time_now = Time.now.utc
|
51
|
+
# Calculate queue time and store it as milliseconds
|
52
|
+
(time_now - queue_start) * 1_000
|
53
|
+
end
|
54
|
+
|
46
55
|
job_status = nil
|
47
56
|
has_wrapper_transaction = Appsignal::Transaction.current?
|
48
57
|
transaction =
|
@@ -73,10 +82,8 @@ module Appsignal
|
|
73
82
|
raise exception
|
74
83
|
ensure
|
75
84
|
if transaction
|
76
|
-
|
77
|
-
|
78
|
-
transaction.set_queue_start((Time.parse(enqueued_at).to_f * 1_000).to_i)
|
79
|
-
end
|
85
|
+
# Present in Rails 6 and up
|
86
|
+
transaction.set_queue_start((queue_start.to_f * 1_000).to_i) if queue_start
|
80
87
|
|
81
88
|
unless has_wrapper_transaction
|
82
89
|
# Only complete transaction if ActiveJob is not wrapped in
|
@@ -94,6 +101,15 @@ module Appsignal
|
|
94
101
|
ActiveJobHelpers.increment_counter metric_name, 1,
|
95
102
|
tags.merge(:status => :processed)
|
96
103
|
end
|
104
|
+
|
105
|
+
queue_name = job["queue_name"]
|
106
|
+
if queue_time && queue_name
|
107
|
+
ActiveJobHelpers.add_distribution_value(
|
108
|
+
"queue_time",
|
109
|
+
queue_time,
|
110
|
+
:queue => queue_name
|
111
|
+
)
|
112
|
+
end
|
97
113
|
end
|
98
114
|
|
99
115
|
private
|
@@ -172,6 +188,10 @@ module Appsignal
|
|
172
188
|
def self.increment_counter(key, value, tags = {})
|
173
189
|
Appsignal.increment_counter "active_job_#{key}", value, tags
|
174
190
|
end
|
191
|
+
|
192
|
+
def self.add_distribution_value(key, value, tags = {})
|
193
|
+
Appsignal.add_distribution_value("active_job_#{key}", value, tags)
|
194
|
+
end
|
175
195
|
end
|
176
196
|
end
|
177
197
|
end
|
@@ -11,27 +11,41 @@ module Appsignal
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def install
|
14
|
-
return unless Appsignal.config[:enable_at_exit_reporter]
|
15
|
-
|
16
14
|
Kernel.at_exit(&AtExitCallback.method(:call))
|
17
15
|
end
|
18
16
|
|
19
|
-
#
|
17
|
+
# Stop AppSignal before the app exists.
|
18
|
+
#
|
19
|
+
# This is the default behavior and can be customized with the
|
20
|
+
# `enable_at_exit_hook` option.
|
21
|
+
#
|
22
|
+
# When the `enable_at_exit_reporter` option is set to `true` (the
|
23
|
+
# default), it will report any unhandled errors that will crash the Ruby
|
24
|
+
# process.
|
20
25
|
#
|
21
26
|
# If this error was previously reported by any of our instrumentation,
|
22
27
|
# the error will not also be reported here. This way we don't report an
|
23
28
|
# error from a Rake task or instrumented script twice.
|
24
29
|
class AtExitCallback
|
25
30
|
def self.call
|
31
|
+
report_error = false
|
32
|
+
return unless Appsignal.config&.[](:enable_at_exit_reporter)
|
33
|
+
|
26
34
|
error = $! # rubocop:disable Style/SpecialGlobalVars
|
27
35
|
return unless error
|
28
36
|
return if ignored_error?(error)
|
29
37
|
return if Appsignal::Transaction.last_errors.include?(error)
|
30
38
|
|
39
|
+
report_error = true
|
40
|
+
|
31
41
|
Appsignal.report_error(error) do |transaction|
|
32
42
|
transaction.set_namespace("unhandled")
|
33
43
|
end
|
34
|
-
|
44
|
+
ensure
|
45
|
+
at_exit_hook = Appsignal.config&.[](:enable_at_exit_hook)
|
46
|
+
if at_exit_hook == "always" || (at_exit_hook == "on_error" && report_error)
|
47
|
+
Appsignal.stop("at_exit")
|
48
|
+
end
|
35
49
|
end
|
36
50
|
|
37
51
|
IGNORED_ERRORS = [
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Appsignal
|
4
|
+
class Hooks
|
5
|
+
# @api private
|
6
|
+
class OwnershipHook < Appsignal::Hooks::Hook
|
7
|
+
register :ownership
|
8
|
+
|
9
|
+
def dependencies_present?
|
10
|
+
defined?(::Ownership) &&
|
11
|
+
Gem::Version.new(::Ownership::VERSION) >= Gem::Version.new("0.2.0") &&
|
12
|
+
Appsignal.config &&
|
13
|
+
Appsignal.config[:instrument_ownership]
|
14
|
+
end
|
15
|
+
|
16
|
+
def install
|
17
|
+
require "appsignal/integrations/ownership"
|
18
|
+
|
19
|
+
# If a transaction is created in a code context that has an owner,
|
20
|
+
# set the namespace of the transaction to the owner.
|
21
|
+
Appsignal::Transaction.after_create <<
|
22
|
+
Appsignal::Integrations::OwnershipIntegrationHelper.method(:after_create)
|
23
|
+
|
24
|
+
# If an error was reported in a code context that has an owner,
|
25
|
+
# set the namespace of the transaction to the owner.
|
26
|
+
# In some circumstances, this will be more accurate than the last owner
|
27
|
+
# that was set for the transaction, which is what would otherwise be
|
28
|
+
# reported.
|
29
|
+
Appsignal::Transaction.before_complete <<
|
30
|
+
Appsignal::Integrations::OwnershipIntegrationHelper.method(:before_complete)
|
31
|
+
|
32
|
+
# If an owner is set in a code context that has an active transaction,
|
33
|
+
# set the namespace of the transaction to the owner.
|
34
|
+
unless ::Ownership.singleton_class.included_modules.include?(
|
35
|
+
Appsignal::Integrations::OwnershipIntegration
|
36
|
+
)
|
37
|
+
::Ownership.singleton_class.prepend Appsignal::Integrations::OwnershipIntegration
|
38
|
+
end
|
39
|
+
|
40
|
+
Appsignal::Environment.report_enabled("ownership")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/appsignal/hooks.rb
CHANGED
@@ -84,6 +84,7 @@ require "appsignal/hooks/dry_monitor"
|
|
84
84
|
require "appsignal/hooks/http"
|
85
85
|
require "appsignal/hooks/mri"
|
86
86
|
require "appsignal/hooks/net_http"
|
87
|
+
require "appsignal/hooks/ownership"
|
87
88
|
require "appsignal/hooks/passenger"
|
88
89
|
require "appsignal/hooks/puma"
|
89
90
|
require "appsignal/hooks/rake"
|
@@ -8,22 +8,18 @@ namespace :appsignal do
|
|
8
8
|
user = fetch(:appsignal_user, ENV["USER"] || ENV.fetch("USERNAME", nil))
|
9
9
|
revision = fetch(:appsignal_revision, fetch(:current_revision))
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
appsignal_env
|
14
|
-
).tap do |c|
|
15
|
-
c.merge_dsl_options(fetch(:appsignal_config, {}))
|
16
|
-
c.validate
|
11
|
+
Appsignal._load_config!(appsignal_env) do |config|
|
12
|
+
config&.merge_dsl_options(fetch(:appsignal_config, {}))
|
17
13
|
end
|
18
14
|
Appsignal._start_logger
|
19
15
|
|
20
|
-
if
|
16
|
+
if Appsignal.config&.active?
|
21
17
|
marker_data = {
|
22
18
|
:revision => revision,
|
23
19
|
:user => user
|
24
20
|
}
|
25
21
|
|
26
|
-
marker = Appsignal::Marker.new(marker_data,
|
22
|
+
marker = Appsignal::Marker.new(marker_data, Appsignal.config)
|
27
23
|
# {#dry_run?} helper was added in Capistrano 3.5.0
|
28
24
|
# https://github.com/capistrano/capistrano/commit/38d8d6d2c8485f1b5643857465b16ff01da57aff
|
29
25
|
if respond_to?(:dry_run?) && dry_run?
|
@@ -5,40 +5,37 @@ module Appsignal
|
|
5
5
|
# @api private
|
6
6
|
class Capistrano
|
7
7
|
def self.tasks(config)
|
8
|
-
config.load do
|
8
|
+
config.load do
|
9
9
|
after "deploy", "appsignal:deploy"
|
10
10
|
after "deploy:migrations", "appsignal:deploy"
|
11
11
|
|
12
12
|
namespace :appsignal do
|
13
13
|
task :deploy do
|
14
|
-
|
14
|
+
appsignal_env = fetch(:appsignal_env,
|
15
15
|
fetch(:stage, fetch(:rails_env, fetch(:rack_env, "production"))))
|
16
16
|
user = fetch(:appsignal_user, ENV["USER"] || ENV.fetch("USERNAME", nil))
|
17
17
|
revision = fetch(:appsignal_revision, fetch(:current_revision))
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
env
|
22
|
-
).tap do |c|
|
23
|
-
c.merge_dsl_options(fetch(:appsignal_config, {}))
|
24
|
-
c.validate
|
19
|
+
Appsignal._load_config!(appsignal_env) do |conf|
|
20
|
+
conf&.merge_dsl_options(fetch(:appsignal_config, {}))
|
25
21
|
end
|
26
22
|
Appsignal._start_logger
|
27
23
|
|
28
|
-
if
|
24
|
+
if Appsignal.config&.active?
|
29
25
|
marker_data = {
|
30
26
|
:revision => revision,
|
31
27
|
:user => user
|
32
28
|
}
|
33
29
|
|
34
|
-
marker = Marker.new(marker_data,
|
30
|
+
marker = Marker.new(marker_data, Appsignal.config)
|
35
31
|
if config.dry_run
|
36
32
|
puts "Dry run: AppSignal deploy marker not actually sent."
|
37
33
|
else
|
38
34
|
marker.transmit
|
39
35
|
end
|
40
36
|
else
|
41
|
-
puts "Not notifying of deploy, config is not active for
|
37
|
+
puts "Not notifying of deploy, config is not active for " \
|
38
|
+
"environment: #{appsignal_env}"
|
42
39
|
end
|
43
40
|
end
|
44
41
|
end
|
@@ -5,7 +5,8 @@ module Appsignal
|
|
5
5
|
# @api private
|
6
6
|
module HttpIntegration
|
7
7
|
def request(verb, uri, opts = {})
|
8
|
-
|
8
|
+
uri_module = defined?(HTTP::URI) ? HTTP::URI : URI
|
9
|
+
parsed_request_uri = uri.is_a?(URI) ? uri : uri_module.parse(uri.to_s)
|
9
10
|
request_uri = "#{parsed_request_uri.scheme}://#{parsed_request_uri.host}"
|
10
11
|
|
11
12
|
Appsignal.instrument("request.http_rb", "#{verb.upcase} #{request_uri}") do
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Appsignal
|
4
|
+
module Integrations
|
5
|
+
# @api private
|
6
|
+
module OwnershipIntegration
|
7
|
+
# Implement the `around_change` logic by monkey-patching the reader,
|
8
|
+
# instead of by using the `around_change=` writer. This allows customers
|
9
|
+
# to use the `around_change=` writer in their own code without
|
10
|
+
# accidentally overriding AppSignal's instrumentation.
|
11
|
+
def around_change
|
12
|
+
proc do |owner, block|
|
13
|
+
OwnershipIntegrationHelper.set(Appsignal::Transaction.current, owner)
|
14
|
+
|
15
|
+
original = super
|
16
|
+
|
17
|
+
if original
|
18
|
+
original.call(owner, block)
|
19
|
+
else
|
20
|
+
block.call
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module OwnershipIntegrationHelper
|
27
|
+
class << self
|
28
|
+
def set(transaction, owner)
|
29
|
+
return if owner.nil?
|
30
|
+
|
31
|
+
transaction.add_tags(:owner => owner)
|
32
|
+
transaction.set_namespace(owner) if set_namespace?
|
33
|
+
end
|
34
|
+
|
35
|
+
def after_create(transaction)
|
36
|
+
set(transaction, ::Ownership.owner)
|
37
|
+
end
|
38
|
+
|
39
|
+
def before_complete(transaction, error)
|
40
|
+
set(transaction, error.owner) if error.respond_to?(:owner)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def set_namespace?
|
46
|
+
Appsignal.config && Appsignal.config[:ownership_set_namespace]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -4,6 +4,16 @@ module Appsignal
|
|
4
4
|
module Integrations
|
5
5
|
# @api private
|
6
6
|
module RakeIntegration
|
7
|
+
IGNORED_ERRORS = [
|
8
|
+
# Normal exits from the application we do not need to report
|
9
|
+
SystemExit,
|
10
|
+
SignalException
|
11
|
+
].freeze
|
12
|
+
|
13
|
+
def self.ignored_error?(error)
|
14
|
+
IGNORED_ERRORS.include?(error.class)
|
15
|
+
end
|
16
|
+
|
7
17
|
def execute(*args)
|
8
18
|
transaction =
|
9
19
|
if Appsignal.config[:enable_rake_performance_instrumentation]
|
@@ -16,8 +26,10 @@ module Appsignal
|
|
16
26
|
end
|
17
27
|
rescue Exception => error # rubocop:disable Lint/RescueException
|
18
28
|
Appsignal::Integrations::RakeIntegrationHelper.register_at_exit_hook
|
19
|
-
|
20
|
-
|
29
|
+
unless RakeIntegration.ignored_error?(error)
|
30
|
+
transaction ||= _appsignal_create_transaction
|
31
|
+
transaction.set_error(error)
|
32
|
+
end
|
21
33
|
raise error
|
22
34
|
ensure
|
23
35
|
if transaction
|