appsignal 2.10.7 → 2.11.0.alpha.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.semaphore/semaphore.yml +45 -53
- data/CHANGELOG.md +18 -0
- data/build_matrix.yml +13 -6
- data/ext/agent.yml +19 -19
- data/ext/appsignal_extension.c +10 -1
- data/ext/base.rb +15 -4
- data/gemfiles/padrino.gemfile +2 -2
- data/lib/appsignal.rb +21 -1
- data/lib/appsignal/capistrano.rb +2 -0
- data/lib/appsignal/config.rb +6 -2
- data/lib/appsignal/environment.rb +126 -0
- data/lib/appsignal/extension/jruby.rb +10 -0
- data/lib/appsignal/hooks/net_http.rb +2 -0
- data/lib/appsignal/hooks/puma.rb +2 -58
- data/lib/appsignal/hooks/redis.rb +2 -0
- data/lib/appsignal/hooks/sequel.rb +2 -0
- data/lib/appsignal/hooks/sidekiq.rb +2 -99
- data/lib/appsignal/integrations/delayed_job_plugin.rb +16 -3
- data/lib/appsignal/integrations/object.rb +4 -0
- data/lib/appsignal/integrations/resque_active_job.rb +12 -4
- data/lib/appsignal/probes/puma.rb +61 -0
- data/lib/appsignal/probes/sidekiq.rb +102 -0
- data/lib/appsignal/rack/js_exception_catcher.rb +5 -2
- data/lib/appsignal/transaction.rb +22 -7
- data/lib/appsignal/version.rb +1 -1
- data/lib/puma/plugin/appsignal.rb +2 -1
- data/spec/lib/appsignal/cli/diagnose_spec.rb +2 -1
- data/spec/lib/appsignal/config_spec.rb +6 -1
- data/spec/lib/appsignal/environment_spec.rb +167 -0
- data/spec/lib/appsignal/hooks/delayed_job_spec.rb +198 -166
- data/spec/lib/appsignal/hooks/puma_spec.rb +2 -181
- data/spec/lib/appsignal/hooks/sidekiq_spec.rb +256 -462
- data/spec/lib/appsignal/integrations/padrino_spec.rb +1 -1
- data/spec/lib/appsignal/integrations/resque_active_job_spec.rb +55 -13
- data/spec/lib/appsignal/probes/puma_spec.rb +180 -0
- data/spec/lib/appsignal/probes/sidekiq_spec.rb +201 -0
- data/spec/lib/appsignal/rack/js_exception_catcher_spec.rb +9 -4
- data/spec/lib/appsignal/transaction_spec.rb +30 -13
- data/spec/lib/appsignal_spec.rb +22 -0
- data/spec/lib/puma/appsignal_spec.rb +1 -1
- data/spec/support/helpers/dependency_helper.rb +5 -0
- data/spec/support/helpers/env_helpers.rb +1 -1
- data/spec/support/helpers/environment_metdata_helper.rb +16 -0
- data/spec/support/stubs/sidekiq/api.rb +1 -1
- metadata +19 -8
data/ext/appsignal_extension.c
CHANGED
@@ -639,6 +639,14 @@ static VALUE running_in_container() {
|
|
639
639
|
return appsignal_running_in_container() == 1 ? Qtrue : Qfalse;
|
640
640
|
}
|
641
641
|
|
642
|
+
static VALUE set_environment_metadata(VALUE self, VALUE key, VALUE value) {
|
643
|
+
appsignal_set_environment_metadata(
|
644
|
+
make_appsignal_string(key),
|
645
|
+
make_appsignal_string(value)
|
646
|
+
);
|
647
|
+
return Qnil;
|
648
|
+
}
|
649
|
+
|
642
650
|
void Init_appsignal_extension(void) {
|
643
651
|
Appsignal = rb_define_module("Appsignal");
|
644
652
|
Extension = rb_define_class_under(Appsignal, "Extension", rb_cObject);
|
@@ -697,9 +705,10 @@ void Init_appsignal_extension(void) {
|
|
697
705
|
// Get JSON content of a data
|
698
706
|
rb_define_method(Data, "to_s", data_to_s, 0);
|
699
707
|
|
700
|
-
//
|
708
|
+
// Other helper methods
|
701
709
|
rb_define_singleton_method(Extension, "install_allocation_event_hook", install_allocation_event_hook, 0);
|
702
710
|
rb_define_singleton_method(Extension, "running_in_container?", running_in_container, 0);
|
711
|
+
rb_define_singleton_method(Extension, "set_environment_metadata", set_environment_metadata, 2);
|
703
712
|
|
704
713
|
// Metrics
|
705
714
|
rb_define_singleton_method(Extension, "set_gauge", set_gauge, 3);
|
data/ext/base.rb
CHANGED
@@ -32,7 +32,8 @@ def report
|
|
32
32
|
"version" => "#{rbconfig["ruby_version"]}-p#{rbconfig["PATCHLEVEL"]}"
|
33
33
|
},
|
34
34
|
"download" => {
|
35
|
-
"checksum" => "unverified"
|
35
|
+
"checksum" => "unverified",
|
36
|
+
"http_proxy" => http_proxy
|
36
37
|
},
|
37
38
|
"build" => {
|
38
39
|
"time" => Time.now.utc,
|
@@ -126,7 +127,11 @@ def download_archive(type)
|
|
126
127
|
report["download"]["download_url"] = download_url
|
127
128
|
|
128
129
|
begin
|
129
|
-
return open(
|
130
|
+
return open(
|
131
|
+
download_url,
|
132
|
+
:ssl_ca_cert => CA_CERT_PATH,
|
133
|
+
:proxy => http_proxy
|
134
|
+
)
|
130
135
|
rescue
|
131
136
|
next
|
132
137
|
end
|
@@ -142,14 +147,16 @@ def download_archive(type)
|
|
142
147
|
end
|
143
148
|
|
144
149
|
def verify_archive(archive, type)
|
145
|
-
|
150
|
+
expected_checksum = ARCH_CONFIG[type]["checksum"]
|
151
|
+
actual_checksum = Digest::SHA256.hexdigest(archive.read)
|
152
|
+
if actual_checksum == expected_checksum
|
146
153
|
report["download"]["checksum"] = "verified"
|
147
154
|
true
|
148
155
|
else
|
149
156
|
report["download"]["checksum"] = "invalid"
|
150
157
|
abort_installation(
|
151
158
|
"Checksum of downloaded archive could not be verified: " \
|
152
|
-
"Expected '#{
|
159
|
+
"Expected '#{expected_checksum}', got '#{actual_checksum}'."
|
153
160
|
)
|
154
161
|
end
|
155
162
|
end
|
@@ -172,3 +179,7 @@ def store_download_version_on_report
|
|
172
179
|
path = File.expand_path(File.join(File.dirname(__FILE__), "appsignal.version"))
|
173
180
|
report["build"]["agent_version"] = File.read(path).strip
|
174
181
|
end
|
182
|
+
|
183
|
+
def http_proxy
|
184
|
+
Gem.configuration[:http_proxy] || ENV["http_proxy"] || ENV["HTTP_PROXY"]
|
185
|
+
end
|
data/gemfiles/padrino.gemfile
CHANGED
data/lib/appsignal.rb
CHANGED
@@ -134,11 +134,17 @@ module Appsignal
|
|
134
134
|
|
135
135
|
if config[:enable_allocation_tracking] && !Appsignal::System.jruby?
|
136
136
|
Appsignal::Extension.install_allocation_event_hook
|
137
|
+
Appsignal::Environment.report_enabled("allocation_tracking")
|
137
138
|
end
|
138
139
|
|
139
|
-
|
140
|
+
if config[:enable_gc_instrumentation]
|
141
|
+
GC::Profiler.enable
|
142
|
+
Appsignal::Environment.report_enabled("gc_instrumentation")
|
143
|
+
end
|
140
144
|
|
141
145
|
Appsignal::Minutely.start if config[:enable_minutely_probes]
|
146
|
+
|
147
|
+
collect_environment_metadata
|
142
148
|
else
|
143
149
|
logger.info("Not starting, not active for #{config.env}")
|
144
150
|
end
|
@@ -309,9 +315,23 @@ module Appsignal
|
|
309
315
|
logger.warn "Unable to start logger with log path '#{path}'."
|
310
316
|
logger.warn error
|
311
317
|
end
|
318
|
+
|
319
|
+
def collect_environment_metadata
|
320
|
+
Appsignal::Environment.report("ruby_version") do
|
321
|
+
"#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}"
|
322
|
+
end
|
323
|
+
Appsignal::Environment.report("ruby_engine") { RUBY_ENGINE }
|
324
|
+
if defined?(RUBY_ENGINE_VERSION)
|
325
|
+
Appsignal::Environment.report("ruby_engine_version") do
|
326
|
+
RUBY_ENGINE_VERSION
|
327
|
+
end
|
328
|
+
end
|
329
|
+
Appsignal::Environment.report_supported_gems
|
330
|
+
end
|
312
331
|
end
|
313
332
|
end
|
314
333
|
|
334
|
+
require "appsignal/environment"
|
315
335
|
require "appsignal/system"
|
316
336
|
require "appsignal/utils"
|
317
337
|
require "appsignal/extension"
|
data/lib/appsignal/capistrano.rb
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
require "appsignal"
|
4
4
|
require "capistrano/version"
|
5
5
|
|
6
|
+
Appsignal::Environment.report_enabled("capistrano")
|
7
|
+
|
6
8
|
if defined?(Capistrano::VERSION) && Gem::Version.new(Capistrano::VERSION) >= Gem::Version.new(3)
|
7
9
|
# Capistrano 3+
|
8
10
|
load File.expand_path("../integrations/capistrano/appsignal.cap", __FILE__)
|
data/lib/appsignal/config.rb
CHANGED
@@ -18,6 +18,7 @@ module Appsignal
|
|
18
18
|
:ignore_namespaces => [],
|
19
19
|
:filter_parameters => [],
|
20
20
|
:filter_session_data => [],
|
21
|
+
:send_environment_metadata => true,
|
21
22
|
:send_params => true,
|
22
23
|
:request_headers => %w[
|
23
24
|
HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING
|
@@ -62,6 +63,7 @@ module Appsignal
|
|
62
63
|
"APPSIGNAL_IGNORE_NAMESPACES" => :ignore_namespaces,
|
63
64
|
"APPSIGNAL_FILTER_PARAMETERS" => :filter_parameters,
|
64
65
|
"APPSIGNAL_FILTER_SESSION_DATA" => :filter_session_data,
|
66
|
+
"APPSIGNAL_SEND_ENVIRONMENT_METADATA" => :send_environment_metadata,
|
65
67
|
"APPSIGNAL_SEND_PARAMS" => :send_params,
|
66
68
|
"APPSIGNAL_HTTP_PROXY" => :http_proxy,
|
67
69
|
"APPSIGNAL_ENABLE_ALLOCATION_TRACKING" => :enable_allocation_tracking,
|
@@ -222,6 +224,7 @@ module Appsignal
|
|
222
224
|
ENV["_APPSIGNAL_DNS_SERVERS"] = config_hash[:dns_servers].join(",")
|
223
225
|
ENV["_APPSIGNAL_FILES_WORLD_ACCESSIBLE"] = config_hash[:files_world_accessible].to_s
|
224
226
|
ENV["_APPSIGNAL_TRANSACTION_DEBUG_MODE"] = config_hash[:transaction_debug_mode].to_s
|
227
|
+
ENV["_APPSIGNAL_SEND_ENVIRONMENT_METADATA"] = config_hash[:send_environment_metadata].to_s
|
225
228
|
ENV["_APP_REVISION"] = config_hash[:revision].to_s
|
226
229
|
end
|
227
230
|
|
@@ -337,8 +340,9 @@ module Appsignal
|
|
337
340
|
APPSIGNAL_SKIP_SESSION_DATA APPSIGNAL_ENABLE_FRONTEND_ERROR_CATCHING
|
338
341
|
APPSIGNAL_ENABLE_ALLOCATION_TRACKING APPSIGNAL_ENABLE_GC_INSTRUMENTATION
|
339
342
|
APPSIGNAL_RUNNING_IN_CONTAINER APPSIGNAL_ENABLE_HOST_METRICS
|
340
|
-
APPSIGNAL_SEND_PARAMS
|
341
|
-
APPSIGNAL_FILES_WORLD_ACCESSIBLE
|
343
|
+
APPSIGNAL_SEND_ENVIRONMENT_METADATA APPSIGNAL_SEND_PARAMS
|
344
|
+
APPSIGNAL_ENABLE_MINUTELY_PROBES APPSIGNAL_FILES_WORLD_ACCESSIBLE
|
345
|
+
APPSIGNAL_TRANSACTION_DEBUG_MODE].each do |var|
|
342
346
|
env_var = ENV[var]
|
343
347
|
next unless env_var
|
344
348
|
config[ENV_TO_KEY_MAPPING[var]] = env_var.casecmp("true").zero?
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module Appsignal
|
2
|
+
# @api private
|
3
|
+
class Environment
|
4
|
+
# Add environment metadata.
|
5
|
+
#
|
6
|
+
# The key and value of the environment metadata must be a String, even if
|
7
|
+
# it's actually of another type.
|
8
|
+
#
|
9
|
+
# The value of the environment metadata is given as a block that captures
|
10
|
+
# errors that might be raised while fetching the value. It will not
|
11
|
+
# re-raise errors, but instead log them using the {Appsignal.logger}. This
|
12
|
+
# ensures AppSignal will not cause an error in the application when
|
13
|
+
# collecting this metadata.
|
14
|
+
#
|
15
|
+
# @example Reporting a key and value
|
16
|
+
# Appsignal::Environment.report("ruby_version") { RUBY_VERSION }
|
17
|
+
#
|
18
|
+
# @example When a value is nil
|
19
|
+
# Appsignal::Environment.report("ruby_version") { nil }
|
20
|
+
# # Key and value do not get reported. A warning gets logged instead.
|
21
|
+
#
|
22
|
+
# @example When an error occurs
|
23
|
+
# Appsignal::Environment.report("ruby_version") { raise "uh oh" }
|
24
|
+
# # Error does not get reraised. A warning gets logged instead.
|
25
|
+
#
|
26
|
+
# @param key [String] The name of the key of the environment metadata value.
|
27
|
+
# @yieldreturn [String] The value of the key of the environment metadata.
|
28
|
+
# @return [void]
|
29
|
+
def self.report(key)
|
30
|
+
key =
|
31
|
+
case key
|
32
|
+
when String
|
33
|
+
key
|
34
|
+
else
|
35
|
+
Appsignal.logger.error "Unable to report on environment metadata: " \
|
36
|
+
"Unsupported value type for #{key.inspect}"
|
37
|
+
return
|
38
|
+
end
|
39
|
+
|
40
|
+
yielded_value =
|
41
|
+
begin
|
42
|
+
yield
|
43
|
+
rescue => e
|
44
|
+
Appsignal.logger.error \
|
45
|
+
"Unable to report on environment metadata #{key.inspect}:\n" \
|
46
|
+
"#{e.class}: #{e}"
|
47
|
+
return
|
48
|
+
end
|
49
|
+
|
50
|
+
value =
|
51
|
+
case yielded_value
|
52
|
+
when TrueClass, FalseClass
|
53
|
+
yielded_value.to_s
|
54
|
+
when String
|
55
|
+
yielded_value
|
56
|
+
else
|
57
|
+
Appsignal.logger.error "Unable to report on environment metadata " \
|
58
|
+
"#{key.inspect}: Unsupported value type for " \
|
59
|
+
"#{yielded_value.inspect}"
|
60
|
+
return
|
61
|
+
end
|
62
|
+
|
63
|
+
Appsignal::Extension.set_environment_metadata(key, value)
|
64
|
+
rescue => e
|
65
|
+
Appsignal.logger.error "Unable to report on environment metadata:\n" \
|
66
|
+
"#{e.class}: #{e}"
|
67
|
+
end
|
68
|
+
|
69
|
+
# @see report_supported_gems
|
70
|
+
SUPPORTED_GEMS = %w[
|
71
|
+
actioncable
|
72
|
+
activejob
|
73
|
+
capistrano
|
74
|
+
celluloid
|
75
|
+
data_mapper
|
76
|
+
delayed_job
|
77
|
+
mongo_ruby_driver
|
78
|
+
padrino
|
79
|
+
passenger
|
80
|
+
puma
|
81
|
+
que
|
82
|
+
rack
|
83
|
+
rails
|
84
|
+
rake
|
85
|
+
redis
|
86
|
+
resque
|
87
|
+
sequel
|
88
|
+
shoryuken
|
89
|
+
sidekiq
|
90
|
+
sinatra
|
91
|
+
unicorn
|
92
|
+
webmachine
|
93
|
+
].freeze
|
94
|
+
|
95
|
+
# Report on the list of AppSignal supported gems
|
96
|
+
#
|
97
|
+
# This list is used to report if which AppSignal supported gems are present
|
98
|
+
# in this app and what version. This data will help AppSignal improve its
|
99
|
+
# support by knowing what gems and versions of gems it still needs to
|
100
|
+
# support or can drop support for.
|
101
|
+
#
|
102
|
+
# It will ask Bundler to report name and version information from the gems
|
103
|
+
# that are present in the app bundle.
|
104
|
+
def self.report_supported_gems
|
105
|
+
return unless defined?(Bundler) # Do nothing if Bundler is not present
|
106
|
+
|
107
|
+
bundle_gem_specs = ::Bundler.rubygems.all_specs
|
108
|
+
SUPPORTED_GEMS.each do |gem_name|
|
109
|
+
gem_spec = bundle_gem_specs.find { |spec| spec.name == gem_name }
|
110
|
+
next unless gem_spec
|
111
|
+
|
112
|
+
report("ruby_#{gem_name}_version") { gem_spec.version.to_s }
|
113
|
+
end
|
114
|
+
rescue => e
|
115
|
+
Appsignal.logger.error "Unable to report supported gems:\n" \
|
116
|
+
"#{e.class}: #{e}"
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.report_enabled(feature)
|
120
|
+
Appsignal::Environment.report("ruby_#{feature}_enabled") { true }
|
121
|
+
rescue => e
|
122
|
+
Appsignal.logger.error "Unable to report integration enabled:\n" \
|
123
|
+
"#{e.class}: #{e}"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -60,6 +60,9 @@ module Appsignal
|
|
60
60
|
[:appsignal_string],
|
61
61
|
:appsignal_string
|
62
62
|
attach_function :appsignal_running_in_container, [], :bool
|
63
|
+
attach_function :appsignal_set_environment_metadata,
|
64
|
+
[:appsignal_string, :appsignal_string],
|
65
|
+
:void
|
63
66
|
|
64
67
|
# Metrics methods
|
65
68
|
attach_function :appsignal_set_gauge,
|
@@ -224,6 +227,13 @@ module Appsignal
|
|
224
227
|
appsignal_running_in_container
|
225
228
|
end
|
226
229
|
|
230
|
+
def set_environment_metadata(key, value)
|
231
|
+
appsignal_set_environment_metadata(
|
232
|
+
make_appsignal_string(key),
|
233
|
+
make_appsignal_string(value)
|
234
|
+
)
|
235
|
+
end
|
236
|
+
|
227
237
|
def set_gauge(key, value, tags)
|
228
238
|
appsignal_set_gauge(make_appsignal_string(key), value, tags.pointer)
|
229
239
|
end
|
data/lib/appsignal/hooks/puma.rb
CHANGED
@@ -24,7 +24,8 @@ module Appsignal
|
|
24
24
|
# runs in the Puma main process.
|
25
25
|
# For more information:
|
26
26
|
# https://docs.appsignal.com/ruby/integrations/puma.html
|
27
|
-
|
27
|
+
require "appsignal/probes/puma"
|
28
|
+
Appsignal::Minutely.probes.register :puma, ::Appsignal::Probes::PumaProbe
|
28
29
|
end
|
29
30
|
|
30
31
|
return unless defined?(::Puma::Cluster)
|
@@ -39,62 +40,5 @@ module Appsignal
|
|
39
40
|
end
|
40
41
|
end
|
41
42
|
end
|
42
|
-
|
43
|
-
class PumaProbe
|
44
|
-
def initialize
|
45
|
-
@hostname = Appsignal.config[:hostname] || Socket.gethostname
|
46
|
-
end
|
47
|
-
|
48
|
-
def call
|
49
|
-
puma_stats = fetch_puma_stats
|
50
|
-
return unless puma_stats
|
51
|
-
|
52
|
-
stats = JSON.parse puma_stats, :symbolize_names => true
|
53
|
-
counts = {}
|
54
|
-
count_keys = [:backlog, :running, :pool_capacity, :max_threads]
|
55
|
-
|
56
|
-
if stats[:worker_status] # Multiple workers
|
57
|
-
stats[:worker_status].each do |worker|
|
58
|
-
stat = worker[:last_status]
|
59
|
-
count_keys.each do |key|
|
60
|
-
count_if_present counts, key, stat
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
gauge(:workers, stats[:workers], :type => :count)
|
65
|
-
gauge(:workers, stats[:booted_workers], :type => :booted)
|
66
|
-
gauge(:workers, stats[:old_workers], :type => :old)
|
67
|
-
else # Single worker
|
68
|
-
count_keys.each do |key|
|
69
|
-
count_if_present counts, key, stats
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
gauge(:connection_backlog, counts[:backlog]) if counts[:backlog]
|
74
|
-
gauge(:pool_capacity, counts[:pool_capacity]) if counts[:pool_capacity]
|
75
|
-
gauge(:threads, counts[:running], :type => :running) if counts[:running]
|
76
|
-
gauge(:threads, counts[:max_threads], :type => :max) if counts[:max_threads]
|
77
|
-
end
|
78
|
-
|
79
|
-
private
|
80
|
-
|
81
|
-
attr_reader :hostname
|
82
|
-
|
83
|
-
def gauge(field, count, tags = {})
|
84
|
-
Appsignal.set_gauge("puma_#{field}", count, tags.merge(:hostname => hostname))
|
85
|
-
end
|
86
|
-
|
87
|
-
def count_if_present(counts, key, stats)
|
88
|
-
stat_value = stats[key]
|
89
|
-
return unless stat_value
|
90
|
-
counts[key] ||= 0
|
91
|
-
counts[key] += stat_value
|
92
|
-
end
|
93
|
-
|
94
|
-
def fetch_puma_stats
|
95
|
-
::Puma.stats
|
96
|
-
rescue NoMethodError # rubocop:disable Lint/HandleExceptions
|
97
|
-
end
|
98
|
-
end
|
99
43
|
end
|
100
44
|
end
|
@@ -12,7 +12,8 @@ module Appsignal
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def install
|
15
|
-
|
15
|
+
require "appsignal/probes/sidekiq"
|
16
|
+
Appsignal::Minutely.probes.register :sidekiq, Appsignal::Probes::SidekiqProbe
|
16
17
|
|
17
18
|
::Sidekiq.configure_server do |config|
|
18
19
|
config.server_middleware do |chain|
|
@@ -22,104 +23,6 @@ module Appsignal
|
|
22
23
|
end
|
23
24
|
end
|
24
25
|
|
25
|
-
class SidekiqProbe
|
26
|
-
attr_reader :config
|
27
|
-
|
28
|
-
def self.dependencies_present?
|
29
|
-
Gem::Version.new(::Redis::VERSION) >= Gem::Version.new("3.3.5")
|
30
|
-
end
|
31
|
-
|
32
|
-
def initialize(config = {})
|
33
|
-
@config = config
|
34
|
-
@cache = {}
|
35
|
-
config_string = " with config: #{config}" unless config.empty?
|
36
|
-
Appsignal.logger.debug("Initializing Sidekiq probe#{config_string}")
|
37
|
-
require "sidekiq/api"
|
38
|
-
end
|
39
|
-
|
40
|
-
def call
|
41
|
-
track_redis_info
|
42
|
-
track_stats
|
43
|
-
track_queues
|
44
|
-
end
|
45
|
-
|
46
|
-
private
|
47
|
-
|
48
|
-
attr_reader :cache
|
49
|
-
|
50
|
-
def track_redis_info
|
51
|
-
return unless ::Sidekiq.respond_to?(:redis_info)
|
52
|
-
redis_info = ::Sidekiq.redis_info
|
53
|
-
|
54
|
-
gauge "connection_count", redis_info.fetch("connected_clients")
|
55
|
-
gauge "memory_usage", redis_info.fetch("used_memory")
|
56
|
-
gauge "memory_usage_rss", redis_info.fetch("used_memory_rss")
|
57
|
-
end
|
58
|
-
|
59
|
-
def track_stats
|
60
|
-
stats = ::Sidekiq::Stats.new
|
61
|
-
|
62
|
-
gauge "worker_count", stats.workers_size
|
63
|
-
gauge "process_count", stats.processes_size
|
64
|
-
gauge_delta :jobs_processed, "job_count", stats.processed,
|
65
|
-
:status => :processed
|
66
|
-
gauge_delta :jobs_failed, "job_count", stats.failed, :status => :failed
|
67
|
-
gauge "job_count", stats.retry_size, :status => :retry_queue
|
68
|
-
gauge_delta :jobs_dead, "job_count", stats.dead_size, :status => :died
|
69
|
-
gauge "job_count", stats.scheduled_size, :status => :scheduled
|
70
|
-
gauge "job_count", stats.enqueued, :status => :enqueued
|
71
|
-
end
|
72
|
-
|
73
|
-
def track_queues
|
74
|
-
::Sidekiq::Queue.all.each do |queue|
|
75
|
-
gauge "queue_length", queue.size, :queue => queue.name
|
76
|
-
# Convert latency from seconds to milliseconds
|
77
|
-
gauge "queue_latency", queue.latency * 1_000.0, :queue => queue.name
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
# Track a gauge metric with the `sidekiq_` prefix
|
82
|
-
def gauge(key, value, tags = {})
|
83
|
-
tags[:hostname] = hostname if hostname
|
84
|
-
Appsignal.set_gauge "sidekiq_#{key}", value, tags
|
85
|
-
end
|
86
|
-
|
87
|
-
# Track the delta of two values for a gauge metric
|
88
|
-
#
|
89
|
-
# First call will store the data for the metric and the second call will
|
90
|
-
# set a gauge metric with the difference. This is used for absolute
|
91
|
-
# counter values which we want to track as gauges.
|
92
|
-
#
|
93
|
-
# @example
|
94
|
-
# gauge_delta :my_cache_key, "my_gauge", 10
|
95
|
-
# gauge_delta :my_cache_key, "my_gauge", 15
|
96
|
-
# # Creates a gauge with the value `5`
|
97
|
-
# @see #gauge
|
98
|
-
def gauge_delta(cache_key, key, value, tags = {})
|
99
|
-
previous_value = cache[cache_key]
|
100
|
-
cache[cache_key] = value
|
101
|
-
return unless previous_value
|
102
|
-
new_value = value - previous_value
|
103
|
-
gauge key, new_value, tags
|
104
|
-
end
|
105
|
-
|
106
|
-
def hostname
|
107
|
-
return @hostname if defined?(@hostname)
|
108
|
-
if config.key?(:hostname)
|
109
|
-
@hostname = config[:hostname]
|
110
|
-
Appsignal.logger.debug "Sidekiq probe: Using hostname config " \
|
111
|
-
"option #{@hostname.inspect} as hostname"
|
112
|
-
return @hostname
|
113
|
-
end
|
114
|
-
|
115
|
-
host = nil
|
116
|
-
::Sidekiq.redis { |c| host = c.connection[:host] }
|
117
|
-
Appsignal.logger.debug "Sidekiq probe: Using Redis server hostname " \
|
118
|
-
"#{host.inspect} as hostname"
|
119
|
-
@hostname = host
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
26
|
# @api private
|
124
27
|
class SidekiqPlugin # rubocop:disable Metrics/ClassLength
|
125
28
|
include Appsignal::Hooks::Helpers
|