appsignal 2.8.4-java → 2.9.0-java
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 -1
- data/.rubocop_todo.yml +7 -16
- data/.travis.yml +4 -1
- data/CHANGELOG.md +16 -0
- data/README.md +23 -0
- data/Rakefile +10 -7
- data/appsignal.gemspec +3 -0
- data/build_matrix.yml +5 -1
- data/ext/Rakefile +23 -16
- data/ext/agent.yml +37 -37
- data/ext/base.rb +86 -24
- data/ext/extconf.rb +33 -26
- data/gemfiles/rails-6.0.gemfile +5 -0
- data/lib/appsignal.rb +14 -489
- data/lib/appsignal/cli/diagnose.rb +84 -4
- data/lib/appsignal/cli/diagnose/paths.rb +0 -5
- data/lib/appsignal/cli/diagnose/utils.rb +17 -0
- data/lib/appsignal/cli/helpers.rb +6 -0
- data/lib/appsignal/cli/install.rb +13 -7
- data/lib/appsignal/config.rb +1 -2
- data/lib/appsignal/event_formatter.rb +4 -5
- data/lib/appsignal/event_formatter/moped/query_formatter.rb +60 -59
- data/lib/appsignal/extension.rb +2 -2
- data/lib/appsignal/helpers/instrumentation.rb +485 -0
- data/lib/appsignal/helpers/metrics.rb +55 -0
- data/lib/appsignal/hooks.rb +9 -8
- data/lib/appsignal/hooks/puma.rb +65 -9
- data/lib/appsignal/hooks/sidekiq.rb +90 -0
- data/lib/appsignal/integrations/mongo_ruby_driver.rb +7 -0
- data/lib/appsignal/integrations/railtie.rb +2 -1
- data/lib/appsignal/marker.rb +2 -3
- data/lib/appsignal/minutely.rb +164 -14
- data/lib/appsignal/rack/sinatra_instrumentation.rb +1 -1
- data/lib/appsignal/system.rb +16 -18
- data/lib/appsignal/utils/rails_helper.rb +16 -0
- data/lib/appsignal/version.rb +1 -1
- data/spec/lib/appsignal/cli/diagnose_spec.rb +129 -22
- data/spec/lib/appsignal/cli/install_spec.rb +6 -1
- data/spec/lib/appsignal/config_spec.rb +3 -3
- data/spec/lib/appsignal/event_formatter/moped/query_formatter_spec.rb +6 -0
- data/spec/lib/appsignal/event_formatter_spec.rb +168 -69
- data/spec/lib/appsignal/hooks/puma_spec.rb +129 -0
- data/spec/lib/appsignal/hooks/sidekiq_spec.rb +147 -0
- data/spec/lib/appsignal/integrations/mongo_ruby_driver_spec.rb +24 -1
- data/spec/lib/appsignal/minutely_spec.rb +251 -21
- data/spec/lib/appsignal/system_spec.rb +0 -35
- data/spec/lib/appsignal/utils/hash_sanitizer_spec.rb +39 -31
- data/spec/lib/appsignal/utils/json_spec.rb +7 -3
- data/spec/lib/appsignal_spec.rb +27 -2
- data/spec/spec_helper.rb +13 -0
- data/spec/support/helpers/log_helpers.rb +6 -0
- data/spec/support/project_fixture/config/appsignal.yml +1 -0
- data/spec/support/stubs/sidekiq/api.rb +4 -0
- metadata +8 -2
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Appsignal
|
4
|
+
module Helpers
|
5
|
+
# @api private
|
6
|
+
module Metrics
|
7
|
+
def set_gauge(key, value, tags = {})
|
8
|
+
Appsignal::Extension.set_gauge(
|
9
|
+
key.to_s,
|
10
|
+
value.to_f,
|
11
|
+
Appsignal::Utils::Data.generate(tags)
|
12
|
+
)
|
13
|
+
rescue RangeError
|
14
|
+
Appsignal.logger
|
15
|
+
.warn("Gauge value #{value} for key '#{key}' is too big")
|
16
|
+
end
|
17
|
+
|
18
|
+
def set_host_gauge(key, value)
|
19
|
+
Appsignal::Extension.set_host_gauge(key.to_s, value.to_f)
|
20
|
+
rescue RangeError
|
21
|
+
Appsignal.logger
|
22
|
+
.warn("Host gauge value #{value} for key '#{key}' is too big")
|
23
|
+
end
|
24
|
+
|
25
|
+
def set_process_gauge(key, value)
|
26
|
+
Appsignal::Extension.set_process_gauge(key.to_s, value.to_f)
|
27
|
+
rescue RangeError
|
28
|
+
Appsignal.logger
|
29
|
+
.warn("Process gauge value #{value} for key '#{key}' is too big")
|
30
|
+
end
|
31
|
+
|
32
|
+
def increment_counter(key, value = 1.0, tags = {})
|
33
|
+
Appsignal::Extension.increment_counter(
|
34
|
+
key.to_s,
|
35
|
+
value.to_f,
|
36
|
+
Appsignal::Utils::Data.generate(tags)
|
37
|
+
)
|
38
|
+
rescue RangeError
|
39
|
+
Appsignal.logger
|
40
|
+
.warn("Counter value #{value} for key '#{key}' is too big")
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_distribution_value(key, value, tags = {})
|
44
|
+
Appsignal::Extension.add_distribution_value(
|
45
|
+
key.to_s,
|
46
|
+
value.to_f,
|
47
|
+
Appsignal::Utils::Data.generate(tags)
|
48
|
+
)
|
49
|
+
rescue RangeError
|
50
|
+
Appsignal.logger
|
51
|
+
.warn("Distribution value #{value} for key '#{key}' is too big")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/appsignal/hooks.rb
CHANGED
@@ -29,14 +29,15 @@ module Appsignal
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def try_to_install(name)
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
32
|
+
return unless dependencies_present?
|
33
|
+
return if installed?
|
34
|
+
|
35
|
+
Appsignal.logger.info("Installing #{name} hook")
|
36
|
+
begin
|
37
|
+
install
|
38
|
+
@installed = true
|
39
|
+
rescue => ex
|
40
|
+
Appsignal.logger.error("Error while installing #{name} hook: #{ex}")
|
40
41
|
end
|
41
42
|
end
|
42
43
|
|
data/lib/appsignal/hooks/puma.rb
CHANGED
@@ -7,20 +7,24 @@ module Appsignal
|
|
7
7
|
register :puma
|
8
8
|
|
9
9
|
def dependencies_present?
|
10
|
-
defined?(::Puma)
|
11
|
-
::Puma.respond_to?(:cli_config) &&
|
12
|
-
::Puma.cli_config
|
10
|
+
defined?(::Puma)
|
13
11
|
end
|
14
12
|
|
15
13
|
def install
|
16
|
-
::Puma.
|
17
|
-
|
18
|
-
Appsignal.forked
|
14
|
+
if ::Puma.respond_to?(:stats)
|
15
|
+
Appsignal::Minutely.probes.register :puma, PumaProbe
|
19
16
|
end
|
20
17
|
|
21
|
-
::Puma.cli_config
|
22
|
-
|
23
|
-
|
18
|
+
if ::Puma.respond_to?(:cli_config) && ::Puma.cli_config
|
19
|
+
::Puma.cli_config.options[:before_worker_boot] ||= []
|
20
|
+
::Puma.cli_config.options[:before_worker_boot] << proc do |_id|
|
21
|
+
Appsignal.forked
|
22
|
+
end
|
23
|
+
|
24
|
+
::Puma.cli_config.options[:before_worker_shutdown] ||= []
|
25
|
+
::Puma.cli_config.options[:before_worker_shutdown] << proc do |_id|
|
26
|
+
Appsignal.stop("puma before_worker_shutdown")
|
27
|
+
end
|
24
28
|
end
|
25
29
|
|
26
30
|
::Puma::Cluster.class_eval do
|
@@ -33,5 +37,57 @@ module Appsignal
|
|
33
37
|
end
|
34
38
|
end
|
35
39
|
end
|
40
|
+
|
41
|
+
class PumaProbe
|
42
|
+
def initialize
|
43
|
+
@hostname = Appsignal.config[:hostname] || Socket.gethostname
|
44
|
+
end
|
45
|
+
|
46
|
+
def call
|
47
|
+
return unless ::Puma.stats
|
48
|
+
|
49
|
+
stats = JSON.parse Puma.stats, :symbolize_names => true
|
50
|
+
counts = {
|
51
|
+
:backlog => 0,
|
52
|
+
:running => 0,
|
53
|
+
:pool_capacity => 0,
|
54
|
+
:max_threads => 0
|
55
|
+
}
|
56
|
+
|
57
|
+
if stats[:worker_status] # Multiple workers
|
58
|
+
stats[:worker_status].each do |worker|
|
59
|
+
stat = worker[:last_status]
|
60
|
+
|
61
|
+
counts[:backlog] += stat[:backlog]
|
62
|
+
counts[:running] += stat[:running]
|
63
|
+
counts[:pool_capacity] += stat[:pool_capacity]
|
64
|
+
counts[:max_threads] += stat[:max_threads]
|
65
|
+
end
|
66
|
+
|
67
|
+
gauge(:workers, stats[:workers], :type => :count)
|
68
|
+
gauge(:workers, stats[:booted_workers], :type => :booted)
|
69
|
+
gauge(:workers, stats[:old_workers], :type => :old)
|
70
|
+
|
71
|
+
else # Single worker
|
72
|
+
counts[:backlog] += stats[:backlog]
|
73
|
+
counts[:running] += stats[:running]
|
74
|
+
counts[:pool_capacity] += stats[:pool_capacity]
|
75
|
+
counts[:max_threads] += stats[:max_threads]
|
76
|
+
end
|
77
|
+
|
78
|
+
gauge(:connection_backlog, counts[:backlog])
|
79
|
+
gauge(:pool_capacity, counts[:pool_capacity])
|
80
|
+
gauge(:threads, counts[:running], :type => :running)
|
81
|
+
gauge(:threads, counts[:max_threads], :type => :max)
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
attr_reader :hostname
|
87
|
+
|
88
|
+
def gauge(field, count, tags = {})
|
89
|
+
Appsignal.set_gauge("puma_#{field}", count, tags.merge(:hostname => hostname))
|
90
|
+
end
|
91
|
+
end
|
36
92
|
end
|
37
93
|
end
|
@@ -12,6 +12,8 @@ module Appsignal
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def install
|
15
|
+
Appsignal::Minutely.probes.register :sidekiq, SidekiqProbe
|
16
|
+
|
15
17
|
::Sidekiq.configure_server do |config|
|
16
18
|
config.server_middleware do |chain|
|
17
19
|
chain.add Appsignal::Hooks::SidekiqPlugin
|
@@ -20,6 +22,79 @@ module Appsignal
|
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
25
|
+
class SidekiqProbe
|
26
|
+
attr_reader :config
|
27
|
+
|
28
|
+
def initialize(config = {})
|
29
|
+
@config = config
|
30
|
+
@cache = {}
|
31
|
+
require "sidekiq/api"
|
32
|
+
end
|
33
|
+
|
34
|
+
def call
|
35
|
+
stats = ::Sidekiq::Stats.new
|
36
|
+
redis_info = ::Sidekiq.redis_info
|
37
|
+
gauge "worker_count", stats.workers_size
|
38
|
+
gauge "process_count", stats.processes_size
|
39
|
+
gauge "connection_count", redis_info.fetch("connected_clients")
|
40
|
+
gauge "memory_usage", redis_info.fetch("used_memory")
|
41
|
+
gauge "memory_usage_rss", redis_info.fetch("used_memory_rss")
|
42
|
+
gauge_delta :jobs_processed, "job_count", stats.processed,
|
43
|
+
:status => :processed
|
44
|
+
gauge_delta :jobs_failed, "job_count", stats.failed, :status => :failed
|
45
|
+
gauge "job_count", stats.retry_size, :status => :retry_queue
|
46
|
+
gauge_delta :jobs_dead, "job_count", stats.dead_size, :status => :died
|
47
|
+
gauge "job_count", stats.scheduled_size, :status => :scheduled
|
48
|
+
gauge "job_count", stats.enqueued, :status => :enqueued
|
49
|
+
|
50
|
+
::Sidekiq::Queue.all.each do |queue|
|
51
|
+
gauge "queue_length", queue.size, :queue => queue.name
|
52
|
+
gauge "queue_latency", queue.latency, :queue => queue.name
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
attr_reader :cache
|
59
|
+
|
60
|
+
# Track a gauge metric with the `sidekiq_` prefix
|
61
|
+
def gauge(key, value, tags = {})
|
62
|
+
tags[:hostname] = hostname if hostname
|
63
|
+
Appsignal.set_gauge "sidekiq_#{key}", value, tags
|
64
|
+
end
|
65
|
+
|
66
|
+
# Track the delta of two values for a gauge metric
|
67
|
+
#
|
68
|
+
# First call will store the data for the metric and the second call will
|
69
|
+
# set a gauge metric with the difference. This is used for absolute
|
70
|
+
# counter values which we want to track as gauges.
|
71
|
+
#
|
72
|
+
# @example
|
73
|
+
# gauge_delta :my_cache_key, "my_gauge", 10
|
74
|
+
# gauge_delta :my_cache_key, "my_gauge", 15
|
75
|
+
# # Creates a gauge with the value `5`
|
76
|
+
# @see #gauge
|
77
|
+
def gauge_delta(cache_key, key, value, tags = {})
|
78
|
+
previous_value = cache[cache_key]
|
79
|
+
cache[cache_key] = value
|
80
|
+
return unless previous_value
|
81
|
+
new_value = value - previous_value
|
82
|
+
gauge key, new_value, tags
|
83
|
+
end
|
84
|
+
|
85
|
+
def hostname
|
86
|
+
return @hostname if defined?(@hostname)
|
87
|
+
if config.key?(:hostname)
|
88
|
+
@hostname = config[:hostname]
|
89
|
+
return @hostname
|
90
|
+
end
|
91
|
+
|
92
|
+
host = nil
|
93
|
+
::Sidekiq.redis { |c| host = c.connection[:host] }
|
94
|
+
@hostname = host
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
23
98
|
# @api private
|
24
99
|
class SidekiqPlugin # rubocop:disable Metrics/ClassLength
|
25
100
|
include Appsignal::Hooks::Helpers
|
@@ -31,6 +106,7 @@ module Appsignal
|
|
31
106
|
].freeze
|
32
107
|
|
33
108
|
def call(_worker, item, _queue)
|
109
|
+
job_status = nil
|
34
110
|
transaction = Appsignal::Transaction.create(
|
35
111
|
SecureRandom.uuid,
|
36
112
|
Appsignal::Transaction::BACKGROUND_JOB,
|
@@ -43,6 +119,7 @@ module Appsignal
|
|
43
119
|
begin
|
44
120
|
yield
|
45
121
|
rescue Exception => exception # rubocop:disable Lint/RescueException
|
122
|
+
job_status = :failed
|
46
123
|
transaction.set_error(exception)
|
47
124
|
raise exception
|
48
125
|
end
|
@@ -56,11 +133,24 @@ module Appsignal
|
|
56
133
|
end
|
57
134
|
transaction.set_http_or_background_queue_start
|
58
135
|
Appsignal::Transaction.complete_current!
|
136
|
+
queue = item["queue"] || "unknown"
|
137
|
+
if job_status
|
138
|
+
increment_counter "queue_job_count", 1,
|
139
|
+
:queue => queue,
|
140
|
+
:status => job_status
|
141
|
+
end
|
142
|
+
increment_counter "queue_job_count", 1,
|
143
|
+
:queue => queue,
|
144
|
+
:status => :processed
|
59
145
|
end
|
60
146
|
end
|
61
147
|
|
62
148
|
private
|
63
149
|
|
150
|
+
def increment_counter(key, value, tags = {})
|
151
|
+
Appsignal.increment_counter "sidekiq_#{key}", value, tags
|
152
|
+
end
|
153
|
+
|
64
154
|
def formatted_action_name(job)
|
65
155
|
sidekiq_action_name = parse_action_name(job)
|
66
156
|
complete_action = sidekiq_action_name =~ /\.|#/
|
@@ -51,6 +51,13 @@ module Appsignal
|
|
51
51
|
Appsignal::Utils::Data.generate(command),
|
52
52
|
Appsignal::EventFormatter::DEFAULT
|
53
53
|
)
|
54
|
+
|
55
|
+
# Send global query metrics
|
56
|
+
Appsignal.add_distribution_value(
|
57
|
+
"mongodb_query_duration",
|
58
|
+
event.duration,
|
59
|
+
:database => event.database_name
|
60
|
+
)
|
54
61
|
end
|
55
62
|
end
|
56
63
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
Appsignal.logger.info("Loading Rails (#{Rails.version}) integration")
|
4
4
|
|
5
|
+
require "appsignal/utils/rails_helper"
|
5
6
|
require "appsignal/rack/rails_instrumentation"
|
6
7
|
|
7
8
|
module Appsignal
|
@@ -17,7 +18,7 @@ module Appsignal
|
|
17
18
|
Appsignal.config = Appsignal::Config.new(
|
18
19
|
Rails.root,
|
19
20
|
Rails.env,
|
20
|
-
:name =>
|
21
|
+
:name => Appsignal::Utils::RailsHelper.detected_rails_app_name,
|
21
22
|
:log_path => Rails.root.join("log")
|
22
23
|
)
|
23
24
|
|
data/lib/appsignal/marker.rb
CHANGED
@@ -53,11 +53,10 @@ module Appsignal
|
|
53
53
|
"revision: #{marker_data[:revision]}, user: #{marker_data[:user]}"
|
54
54
|
|
55
55
|
response = transmitter.transmit(marker_data)
|
56
|
-
|
57
|
-
puts "AppSignal has been notified of this deploy!"
|
58
|
-
else
|
56
|
+
unless response.code == "200"
|
59
57
|
raise "#{response.code} at #{transmitter.uri}"
|
60
58
|
end
|
59
|
+
puts "AppSignal has been notified of this deploy!"
|
61
60
|
rescue => e
|
62
61
|
puts "Something went wrong while trying to notify AppSignal: #{e}"
|
63
62
|
end
|
data/lib/appsignal/minutely.rb
CHANGED
@@ -1,35 +1,185 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Appsignal
|
4
|
-
# @api private
|
5
4
|
class Minutely
|
5
|
+
class ProbeCollection
|
6
|
+
include Appsignal::Utils::DeprecationMessage
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@probes = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
# @return [Integer] Number of probes that are registered.
|
13
|
+
def count
|
14
|
+
probes.count
|
15
|
+
end
|
16
|
+
|
17
|
+
# Clears all probes from the list.
|
18
|
+
# @return [void]
|
19
|
+
def clear
|
20
|
+
probes.clear
|
21
|
+
end
|
22
|
+
|
23
|
+
# Fetch a probe using its name.
|
24
|
+
# @param key [Symbol/String] The name of the probe to fetch.
|
25
|
+
# @return [Object] Returns the registered probe.
|
26
|
+
def [](key)
|
27
|
+
probes[key]
|
28
|
+
end
|
29
|
+
|
30
|
+
# @param probe [Object] Any object that listens to the `call` method will
|
31
|
+
# be used as a probe.
|
32
|
+
# @deprecated Use {#register} instead.
|
33
|
+
# @return [void]
|
34
|
+
def <<(probe)
|
35
|
+
deprecation_message "Deprecated `Appsignal::Minute.probes <<` " \
|
36
|
+
"call. Please use `Appsignal::Minutely.probes.register` instead.",
|
37
|
+
logger
|
38
|
+
register probe.object_id, probe
|
39
|
+
end
|
40
|
+
|
41
|
+
# Register a new minutely probe.
|
42
|
+
#
|
43
|
+
# Supported probe types are:
|
44
|
+
#
|
45
|
+
# - Lambda - A lambda is an object that listens to a `call` method call.
|
46
|
+
# This `call` method is called every minute.
|
47
|
+
# - Class - A class object is an object that listens to a `new` and
|
48
|
+
# `call` method call. The `new` method is called when the Minutely
|
49
|
+
# probe thread is started to initialize all probes. This allows probes
|
50
|
+
# to load dependencies once beforehand. Their `call` method is called
|
51
|
+
# every minute.
|
52
|
+
# - Class instance - A class instance object is an object that listens to
|
53
|
+
# a `call` method call. The `call` method is called every minute.
|
54
|
+
#
|
55
|
+
# @example Register a new probe
|
56
|
+
# Appsignal::Minutely.probes.register :my_probe, lambda {}
|
57
|
+
#
|
58
|
+
# @example Overwrite an existing registered probe
|
59
|
+
# Appsignal::Minutely.probes.register :my_probe, lambda {}
|
60
|
+
# Appsignal::Minutely.probes.register :my_probe, lambda { puts "hello" }
|
61
|
+
#
|
62
|
+
# @example Add a lambda as a probe
|
63
|
+
# Appsignal::Minutely.probes.register :my_probe, lambda { puts "hello" }
|
64
|
+
# # "hello" # printed every minute
|
65
|
+
#
|
66
|
+
# @example Add a probe instance
|
67
|
+
# class MyProbe
|
68
|
+
# def initialize
|
69
|
+
# puts "started"
|
70
|
+
# end
|
71
|
+
#
|
72
|
+
# def call
|
73
|
+
# puts "called"
|
74
|
+
# end
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
# Appsignal::Minutely.probes.register :my_probe, MyProbe.new
|
78
|
+
# # "started" # printed immediately
|
79
|
+
# # "called" # printed every minute
|
80
|
+
#
|
81
|
+
# @example Add a probe class
|
82
|
+
# class MyProbe
|
83
|
+
# def initialize
|
84
|
+
# # Add things that only need to be done on start up for this probe
|
85
|
+
# require "some/library/dependency"
|
86
|
+
# @cache = {} # initialize a local cache variable
|
87
|
+
# puts "started"
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
# def call
|
91
|
+
# puts "called"
|
92
|
+
# end
|
93
|
+
# end
|
94
|
+
#
|
95
|
+
# Appsignal::Minutely.probes.register :my_probe, MyProbe
|
96
|
+
# Appsignal::Minutely.start # This is called for you
|
97
|
+
# # "started" # Printed on Appsignal::Minutely.start
|
98
|
+
# # "called" # Repeated every minute
|
99
|
+
#
|
100
|
+
# @param name [Symbol/String] Name of the probe. Can be used with {[]}.
|
101
|
+
# This name will be used in errors in the log and allows overwriting of
|
102
|
+
# probes by registering new ones with the same name.
|
103
|
+
# @param probe [Object] Any object that listens to the `call` method will
|
104
|
+
# be used as a probe.
|
105
|
+
# @return [void]
|
106
|
+
def register(name, probe)
|
107
|
+
if probes.key?(name)
|
108
|
+
logger.debug "A probe with the name `#{name}` is already " \
|
109
|
+
"registered. Overwriting the entry with the new probe."
|
110
|
+
end
|
111
|
+
probes[name] = probe
|
112
|
+
end
|
113
|
+
|
114
|
+
# @api private
|
115
|
+
def each(&block)
|
116
|
+
probes.each(&block)
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
attr_reader :probes
|
122
|
+
|
123
|
+
def logger
|
124
|
+
Appsignal.logger
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
6
128
|
class << self
|
7
|
-
#
|
8
|
-
#
|
129
|
+
# @see ProbeCollection
|
130
|
+
# @return [ProbeCollection] Returns list of probes.
|
9
131
|
def probes
|
10
|
-
@@probes ||=
|
132
|
+
@@probes ||= ProbeCollection.new
|
11
133
|
end
|
12
134
|
|
135
|
+
# @api private
|
13
136
|
def start
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
137
|
+
stop
|
138
|
+
initialize_probes
|
139
|
+
@@thread = Thread.new do
|
140
|
+
loop do
|
141
|
+
logger = Appsignal.logger
|
142
|
+
logger.debug("Gathering minutely metrics with #{probes.count} probes")
|
143
|
+
probe_instances.each do |name, probe|
|
144
|
+
begin
|
145
|
+
logger.debug("Gathering minutely metrics with '#{name}' probe")
|
146
|
+
probe.call
|
147
|
+
rescue => ex
|
148
|
+
logger.error("Error in minutely probe '#{name}': #{ex}")
|
149
|
+
end
|
20
150
|
end
|
21
|
-
|
22
|
-
Appsignal.logger.error("Error in minutely thread: #{ex}")
|
151
|
+
sleep(Appsignal::Minutely.wait_time)
|
23
152
|
end
|
24
153
|
end
|
25
154
|
end
|
26
155
|
|
156
|
+
# @api private
|
157
|
+
def stop
|
158
|
+
defined?(@@thread) && @@thread.kill
|
159
|
+
probe_instances.clear
|
160
|
+
end
|
161
|
+
|
162
|
+
# @api private
|
27
163
|
def wait_time
|
28
164
|
60 - Time.now.sec
|
29
165
|
end
|
30
166
|
|
31
|
-
|
32
|
-
|
167
|
+
# @api private
|
168
|
+
def register_garbage_collection_probe
|
169
|
+
probes.register :garbage_collection, GCProbe.new
|
170
|
+
end
|
171
|
+
|
172
|
+
private
|
173
|
+
|
174
|
+
def initialize_probes
|
175
|
+
probes.each do |name, probe|
|
176
|
+
instance = probe.respond_to?(:new) ? probe.new : probe
|
177
|
+
probe_instances[name] = instance
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def probe_instances
|
182
|
+
@@probe_instances ||= {}
|
33
183
|
end
|
34
184
|
end
|
35
185
|
|