appsignal 2.4.0 → 2.4.1
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/.gitignore +1 -0
- data/.rubocop_todo.yml +1 -1
- data/.travis.yml +1 -0
- data/CHANGELOG.md +8 -0
- data/Rakefile +1 -0
- data/ext/extconf.rb +10 -9
- data/gemfiles/que.gemfile +5 -0
- data/lib/appsignal/cli/diagnose.rb +3 -1
- data/lib/appsignal/hooks.rb +1 -0
- data/lib/appsignal/hooks/que.rb +21 -0
- data/lib/appsignal/hooks/sidekiq.rb +119 -39
- data/lib/appsignal/integrations/que.rb +43 -0
- data/lib/appsignal/system.rb +54 -0
- data/lib/appsignal/transaction.rb +7 -0
- data/lib/appsignal/version.rb +1 -1
- data/spec/lib/appsignal/cli/diagnose_spec.rb +2 -0
- data/spec/lib/appsignal/hooks/que_spec.rb +19 -0
- data/spec/lib/appsignal/hooks/sidekiq_spec.rb +336 -176
- data/spec/lib/appsignal/integrations/que_spec.rb +174 -0
- data/spec/lib/appsignal/system_spec.rb +111 -0
- data/spec/support/helpers/dependency_helper.rb +4 -0
- data/spec/support/helpers/log_helpers.rb +11 -6
- data/spec/support/helpers/transaction_helpers.rb +6 -0
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9969df5b54cc4d39fa5c1b3e5572715adbe9b912
|
4
|
+
data.tar.gz: a6ea0af4047d5cde79e766bdf34180b3600c2f97
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 036c096b3039a580a5d75e472f0a0382e3e0b3f277b77ce8c5af16e4f0de539ee20a379c956c8715d7ee700b33392a3eca474d539b9a5697a24c6ff592a5cbd2
|
7
|
+
data.tar.gz: 574d5a9c4a20eb7dd8def062b90ec0978f5f0ff78e977a796e5a14043659405971d31ef4824df4c8be8554924f103f6c0699c5516f05f4bd5aa2ce552f6eb4df
|
data/.gitignore
CHANGED
data/.rubocop_todo.yml
CHANGED
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
# 2.4.1
|
2
|
+
* Add Que integration. PR #361
|
3
|
+
* Support Sidekiq delayed extension job action names better. Now action names
|
4
|
+
are reported as their class and class method name (`MyClass.method`), rather
|
5
|
+
than `Sidekiq::Extensions::DelayedClass#perform` for all jobs through that
|
6
|
+
extension. PR #362
|
7
|
+
* Support Sidekiq Enterprise encrypted values. PR #365
|
8
|
+
|
1
9
|
# 2.4.0
|
2
10
|
- Add separate GNU linux build. PR #351 and
|
3
11
|
Commit d1763f4dcb685608468a73f3192226f60f66b217
|
data/Rakefile
CHANGED
data/ext/extconf.rb
CHANGED
@@ -6,19 +6,13 @@ require "zlib"
|
|
6
6
|
require "rubygems/package"
|
7
7
|
require "yaml"
|
8
8
|
require File.expand_path("../../lib/appsignal/version.rb", __FILE__)
|
9
|
+
require File.expand_path("../../lib/appsignal/system.rb", __FILE__)
|
9
10
|
|
10
11
|
EXT_PATH = File.expand_path("..", __FILE__).freeze
|
11
12
|
AGENT_CONFIG = YAML.load(File.read(File.join(EXT_PATH, "agent.yml"))).freeze
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
# Detect musl platforms
|
16
|
-
# Use `export APPSIGNAL_BUILD_FOR_MUSL=1` if the detection doesn't work.
|
17
|
-
if ENV["APPSIGNAL_BUILD_FOR_MUSL"] || (local_os =~ /linux/ && `ldd --version 2>&1` =~ /musl/)
|
18
|
-
"linux-musl"
|
19
|
-
end
|
20
|
-
OS = chosen_os || local_os
|
21
|
-
ARCH = "#{Gem::Platform.local.cpu}-#{OS}".freeze
|
14
|
+
PLATFORM = Appsignal::System.agent_platform
|
15
|
+
ARCH = "#{Gem::Platform.local.cpu}-#{PLATFORM}".freeze
|
22
16
|
CA_CERT_PATH = File.join(EXT_PATH, "../resources/cacert.pem").freeze
|
23
17
|
|
24
18
|
def ext_path(path)
|
@@ -36,8 +30,15 @@ def installation_failed(reason)
|
|
36
30
|
end
|
37
31
|
end
|
38
32
|
|
33
|
+
def write_agent_platform
|
34
|
+
File.open(File.join(EXT_PATH, "appsignal.platform"), "w") do |file|
|
35
|
+
file.write PLATFORM
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
39
|
def install
|
40
40
|
logger.info "Installing appsignal agent #{Appsignal::VERSION} for Ruby #{RUBY_VERSION} on #{RUBY_PLATFORM}"
|
41
|
+
write_agent_platform
|
41
42
|
|
42
43
|
if RUBY_PLATFORM =~ /java/
|
43
44
|
installation_failed(
|
@@ -285,6 +285,8 @@ module Appsignal
|
|
285
285
|
save :language, "ruby"
|
286
286
|
puts_and_save :package_version, "Gem version", Appsignal::VERSION
|
287
287
|
puts_and_save :agent_version, "Agent version", Appsignal::Extension.agent_version
|
288
|
+
puts_and_save :agent_platform, "Agent platform",
|
289
|
+
Appsignal::System.installed_agent_platform
|
288
290
|
puts_and_save :package_install_path, "Gem install path", gem_path
|
289
291
|
puts_and_save :extension_loaded, "Extension loaded", Appsignal.extension_loaded
|
290
292
|
end
|
@@ -297,7 +299,7 @@ module Appsignal
|
|
297
299
|
puts_and_save :architecture, "Architecture", rbconfig["host_cpu"]
|
298
300
|
|
299
301
|
os_label = os = rbconfig["host_os"]
|
300
|
-
os_label = "#{
|
302
|
+
os_label = "#{os} (Microsoft Windows is not supported.)" if Gem.win_platform?
|
301
303
|
save :os, os
|
302
304
|
puts_value "Operating System", os_label
|
303
305
|
|
data/lib/appsignal/hooks.rb
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Appsignal
|
2
|
+
class Hooks
|
3
|
+
# @api private
|
4
|
+
class QueHook < Appsignal::Hooks::Hook
|
5
|
+
register :que
|
6
|
+
|
7
|
+
def dependencies_present?
|
8
|
+
defined?(::Que::Job)
|
9
|
+
end
|
10
|
+
|
11
|
+
def install
|
12
|
+
require "appsignal/integrations/que"
|
13
|
+
::Que::Job.send(:include, Appsignal::Integrations::QuePlugin)
|
14
|
+
|
15
|
+
::Que.error_notifier = proc do |error, _job|
|
16
|
+
Appsignal::Transaction.current.set_error(error)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -1,64 +1,144 @@
|
|
1
|
+
require "yaml"
|
2
|
+
|
1
3
|
module Appsignal
|
2
4
|
class Hooks
|
5
|
+
class SidekiqHook < Appsignal::Hooks::Hook
|
6
|
+
register :sidekiq
|
7
|
+
|
8
|
+
def dependencies_present?
|
9
|
+
defined?(::Sidekiq)
|
10
|
+
end
|
11
|
+
|
12
|
+
def install
|
13
|
+
::Sidekiq.configure_server do |config|
|
14
|
+
config.server_middleware do |chain|
|
15
|
+
chain.add Appsignal::Hooks::SidekiqPlugin
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
3
21
|
# @api private
|
4
22
|
class SidekiqPlugin
|
5
23
|
include Appsignal::Hooks::Helpers
|
6
24
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
error_backtrace enqueued_at retry
|
12
|
-
jid retry created_at wrapped
|
13
|
-
))
|
14
|
-
end
|
25
|
+
JOB_KEYS = Set.new(%w(
|
26
|
+
args backtrace class created_at enqueued_at error_backtrace error_class
|
27
|
+
error_message failed_at jid retried_at retry wrapped
|
28
|
+
)).freeze
|
15
29
|
|
16
30
|
def call(_worker, item, _queue)
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
item["
|
22
|
-
|
23
|
-
|
24
|
-
:filter_parameters => Appsignal.config[:filter_parameters]
|
31
|
+
transaction = Appsignal::Transaction.create(
|
32
|
+
SecureRandom.uuid,
|
33
|
+
Appsignal::Transaction::BACKGROUND_JOB,
|
34
|
+
Appsignal::Transaction::GenericRequest.new(
|
35
|
+
:queue_start => item["enqueued_at"]
|
36
|
+
)
|
37
|
+
)
|
25
38
|
|
26
|
-
Appsignal.
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
39
|
+
Appsignal.instrument "perform_job.sidekiq" do
|
40
|
+
begin
|
41
|
+
yield
|
42
|
+
rescue Exception => exception # rubocop:disable Lint/RescueException
|
43
|
+
transaction.set_error(exception)
|
44
|
+
raise exception
|
45
|
+
end
|
46
|
+
end
|
47
|
+
ensure
|
48
|
+
if transaction
|
49
|
+
transaction.set_action_if_nil(formatted_action_name(item))
|
50
|
+
transaction.params = filtered_arguments(item)
|
51
|
+
formatted_metadata(item).each do |key, value|
|
52
|
+
transaction.set_metadata key, value
|
53
|
+
end
|
54
|
+
transaction.set_http_or_background_queue_start
|
55
|
+
Appsignal::Transaction.complete_current!
|
36
56
|
end
|
37
57
|
end
|
38
58
|
|
59
|
+
private
|
60
|
+
|
61
|
+
def formatted_action_name(job)
|
62
|
+
sidekiq_action_name = parse_action_name(job)
|
63
|
+
return sidekiq_action_name if sidekiq_action_name =~ /\.|#/
|
64
|
+
"#{sidekiq_action_name}#perform"
|
65
|
+
end
|
66
|
+
|
67
|
+
def filtered_arguments(job)
|
68
|
+
Appsignal::Utils::ParamsSanitizer.sanitize(
|
69
|
+
parse_arguments(job),
|
70
|
+
:filter_parameters => Appsignal.config[:filter_parameters]
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
39
74
|
def formatted_metadata(item)
|
40
|
-
{}.tap do |
|
41
|
-
item.each do |key,
|
42
|
-
|
75
|
+
{}.tap do |hash|
|
76
|
+
(item || {}).each do |key, value|
|
77
|
+
next if JOB_KEYS.include?(key)
|
78
|
+
hash[key] = truncate(string_or_inspect(value))
|
43
79
|
end
|
44
80
|
end
|
45
81
|
end
|
46
|
-
end
|
47
82
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
83
|
+
# Based on: https://github.com/mperham/sidekiq/blob/63ee43353bd3b753beb0233f64865e658abeb1c3/lib/sidekiq/api.rb#L316-L334
|
84
|
+
def parse_action_name(job)
|
85
|
+
args = job["args"]
|
86
|
+
case job["class"]
|
87
|
+
when /\ASidekiq::Extensions::Delayed/
|
88
|
+
safe_load(job["args"][0], job["class"]) do |target, method, _|
|
89
|
+
"#{target}.#{method}"
|
90
|
+
end
|
91
|
+
when "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper"
|
92
|
+
job_class = job["wrapped"] || args[0]
|
93
|
+
if "ActionMailer::DeliveryJob" == job_class
|
94
|
+
# MailerClass#mailer_method
|
95
|
+
args[0]["arguments"][0..1].join("#")
|
96
|
+
else
|
97
|
+
job_class
|
98
|
+
end
|
99
|
+
else
|
100
|
+
job["class"]
|
101
|
+
end
|
53
102
|
end
|
54
103
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
104
|
+
# Based on: https://github.com/mperham/sidekiq/blob/63ee43353bd3b753beb0233f64865e658abeb1c3/lib/sidekiq/api.rb#L336-L358
|
105
|
+
def parse_arguments(job)
|
106
|
+
args = job["args"]
|
107
|
+
case job["class"]
|
108
|
+
when /\ASidekiq::Extensions::Delayed/
|
109
|
+
safe_load(args[0], args) do |_, _, arg|
|
110
|
+
arg
|
111
|
+
end
|
112
|
+
when "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper"
|
113
|
+
is_wrapped = job["wrapped"]
|
114
|
+
job_args = is_wrapped ? args[0]["arguments"] : []
|
115
|
+
if "ActionMailer::DeliveryJob" == (is_wrapped || args[0])
|
116
|
+
# Remove MailerClass, mailer_method and "deliver_now"
|
117
|
+
job_args.drop(3)
|
118
|
+
else
|
119
|
+
job_args
|
59
120
|
end
|
121
|
+
else
|
122
|
+
# Sidekiq Enterprise argument encryption.
|
123
|
+
# More information: https://github.com/mperham/sidekiq/wiki/Ent-Encryption
|
124
|
+
if job["encrypt".freeze]
|
125
|
+
# No point in showing 150+ bytes of random garbage
|
126
|
+
args[-1] = "[encrypted data]".freeze
|
127
|
+
end
|
128
|
+
args
|
60
129
|
end
|
61
130
|
end
|
131
|
+
|
132
|
+
# Based on: https://github.com/mperham/sidekiq/blob/63ee43353bd3b753beb0233f64865e658abeb1c3/lib/sidekiq/api.rb#L403-L412
|
133
|
+
def safe_load(content, default)
|
134
|
+
yield(*YAML.load(content))
|
135
|
+
rescue => error
|
136
|
+
# Sidekiq issue #1761: in dev mode, it's possible to have jobs enqueued
|
137
|
+
# which haven't been loaded into memory yet so the YAML can't be
|
138
|
+
# loaded.
|
139
|
+
Appsignal.logger.warn "Unable to load YAML: #{error.message}"
|
140
|
+
default
|
141
|
+
end
|
62
142
|
end
|
63
143
|
end
|
64
144
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Appsignal
|
2
|
+
module Integrations
|
3
|
+
module QuePlugin
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval do
|
6
|
+
def _run_with_appsignal
|
7
|
+
env = {
|
8
|
+
:metadata => {
|
9
|
+
:id => attrs[:job_id],
|
10
|
+
:queue => attrs[:queue],
|
11
|
+
:run_at => attrs[:run_at].to_s,
|
12
|
+
:priority => attrs[:priority],
|
13
|
+
:attempts => attrs[:error_count].to_i
|
14
|
+
},
|
15
|
+
:params => attrs[:args]
|
16
|
+
}
|
17
|
+
|
18
|
+
request = Appsignal::Transaction::GenericRequest.new(env)
|
19
|
+
|
20
|
+
transaction = Appsignal::Transaction.create(
|
21
|
+
SecureRandom.uuid,
|
22
|
+
Appsignal::Transaction::BACKGROUND_JOB,
|
23
|
+
request
|
24
|
+
)
|
25
|
+
|
26
|
+
begin
|
27
|
+
Appsignal.instrument("perform_job.que") { _run_without_appsignal }
|
28
|
+
rescue Exception => error # rubocop:disable Lint/RescueException
|
29
|
+
transaction.set_error(error)
|
30
|
+
raise error
|
31
|
+
ensure
|
32
|
+
transaction.set_action "#{attrs[:job_class]}#run"
|
33
|
+
Appsignal::Transaction.complete_current!
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
alias_method :_run_without_appsignal, :_run
|
38
|
+
alias_method :_run, :_run_with_appsignal
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/appsignal/system.rb
CHANGED
@@ -5,8 +5,62 @@ module Appsignal
|
|
5
5
|
#
|
6
6
|
# @api private
|
7
7
|
module System
|
8
|
+
MUSL_TARGET = "linux-musl".freeze
|
9
|
+
GEM_EXT_PATH = File.expand_path("../../../ext", __FILE__).freeze
|
10
|
+
|
8
11
|
def self.heroku?
|
9
12
|
ENV.key? "DYNO".freeze
|
10
13
|
end
|
14
|
+
|
15
|
+
# Returns the platform for which the agent was installed.
|
16
|
+
#
|
17
|
+
# This value is saved when the gem is installed in `ext/extconf.rb`.
|
18
|
+
# We use this value to build the diagnose report with the installed
|
19
|
+
# platform, rather than the detected platform in {.agent_platform} during
|
20
|
+
# the diagnose run.
|
21
|
+
#
|
22
|
+
# @api private
|
23
|
+
# @return [String]
|
24
|
+
def self.installed_agent_platform
|
25
|
+
platform_file = File.join(GEM_EXT_PATH, "appsignal.platform")
|
26
|
+
return unless File.exist?(platform_file)
|
27
|
+
File.read(platform_file)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Detect agent and extension platform build
|
31
|
+
#
|
32
|
+
# Used by `ext/extconf.rb` to select which build it should download and
|
33
|
+
# install.
|
34
|
+
#
|
35
|
+
# Use `export APPSIGNAL_BUILD_FOR_MUSL=1` if the detection doesn't work
|
36
|
+
# and to force selection of the musl build.
|
37
|
+
#
|
38
|
+
# @api private
|
39
|
+
# @return [String]
|
40
|
+
def self.agent_platform
|
41
|
+
return MUSL_TARGET if ENV["APPSIGNAL_BUILD_FOR_MUSL"]
|
42
|
+
|
43
|
+
local_os = Gem::Platform.local.os
|
44
|
+
if local_os =~ /linux/
|
45
|
+
ldd_output = ldd_version_output
|
46
|
+
return MUSL_TARGET if ldd_output.include? "musl"
|
47
|
+
ldd_version = ldd_output.match(/\d+\.\d+/)
|
48
|
+
if ldd_version && versionify(ldd_version[0]) < versionify("2.15")
|
49
|
+
return MUSL_TARGET
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
local_os
|
54
|
+
end
|
55
|
+
|
56
|
+
# @api private
|
57
|
+
def self.versionify(version)
|
58
|
+
Gem::Version.new(version)
|
59
|
+
end
|
60
|
+
|
61
|
+
# @api private
|
62
|
+
def self.ldd_version_output
|
63
|
+
`ldd --version 2>&1`
|
64
|
+
end
|
11
65
|
end
|
12
66
|
end
|
@@ -54,6 +54,12 @@ module Appsignal
|
|
54
54
|
rescue => e
|
55
55
|
Appsignal.logger.error("Failed to complete transaction ##{current.transaction_id}. #{e.message}")
|
56
56
|
ensure
|
57
|
+
clear_current_transaction!
|
58
|
+
end
|
59
|
+
|
60
|
+
# Remove current transaction from current Thread.
|
61
|
+
# @api private
|
62
|
+
def clear_current_transaction!
|
57
63
|
Thread.current[:appsignal_transaction] = nil
|
58
64
|
end
|
59
65
|
|
@@ -312,6 +318,7 @@ module Appsignal
|
|
312
318
|
finish_event(name, title, body, body_format)
|
313
319
|
end
|
314
320
|
|
321
|
+
# @api private
|
315
322
|
def to_h
|
316
323
|
JSON.parse(@ext.to_json)
|
317
324
|
end
|