appsignal 2.10.7-java → 2.11.0.alpha.2-java
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
@@ -27,9 +27,8 @@ module Appsignal
|
|
27
27
|
method_name = "perform"
|
28
28
|
else
|
29
29
|
# Delayed Job
|
30
|
-
args = extract_value(
|
31
|
-
|
32
|
-
class_name, method_name = class_and_method_name.split("#")
|
30
|
+
args = extract_value(payload, :args, {})
|
31
|
+
class_name, method_name = class_and_method_name_from_object_or_hash(payload, job.name)
|
33
32
|
end
|
34
33
|
|
35
34
|
params = Appsignal::Utils::HashSanitizer.sanitize(
|
@@ -54,6 +53,20 @@ module Appsignal
|
|
54
53
|
end
|
55
54
|
end
|
56
55
|
|
56
|
+
def self.class_and_method_name_from_object_or_hash(payload, default_name)
|
57
|
+
# Attempt to find appsignal_name override
|
58
|
+
class_and_method_name = extract_value(payload, :appsignal_name, nil)
|
59
|
+
return class_and_method_name.split("#") if class_and_method_name.is_a?(String)
|
60
|
+
|
61
|
+
pound_split = default_name.split("#")
|
62
|
+
return pound_split if pound_split.length == 2
|
63
|
+
|
64
|
+
dot_split = default_name.split(".")
|
65
|
+
return default_name if dot_split.length == 2
|
66
|
+
|
67
|
+
["unknown"]
|
68
|
+
end
|
69
|
+
|
57
70
|
def self.extract_value(object_or_hash, field, default_value = nil, convert_to_s = false)
|
58
71
|
value = nil
|
59
72
|
|
@@ -14,12 +14,18 @@ module Appsignal
|
|
14
14
|
Appsignal.config[:filter_parameters]
|
15
15
|
)
|
16
16
|
|
17
|
+
queue_start =
|
18
|
+
if job.respond_to?(:enqueued_at) && job.enqueued_at
|
19
|
+
Time.parse(job.enqueued_at).utc
|
20
|
+
end
|
21
|
+
|
17
22
|
Appsignal.monitor_single_transaction(
|
18
23
|
"perform_job.resque",
|
19
|
-
:class
|
20
|
-
:method
|
21
|
-
:params
|
22
|
-
:
|
24
|
+
:class => job.class.to_s,
|
25
|
+
:method => "perform",
|
26
|
+
:params => params,
|
27
|
+
:queue_start => queue_start,
|
28
|
+
:metadata => {
|
23
29
|
:id => job.job_id,
|
24
30
|
:queue => job.queue_name
|
25
31
|
}
|
@@ -28,6 +34,8 @@ module Appsignal
|
|
28
34
|
end
|
29
35
|
end
|
30
36
|
end
|
37
|
+
|
38
|
+
Appsignal::Environment.report("ruby_active_job_resque_enabled") { true }
|
31
39
|
end
|
32
40
|
end
|
33
41
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Appsignal
|
2
|
+
module Probes
|
3
|
+
# @api private
|
4
|
+
class PumaProbe
|
5
|
+
def initialize
|
6
|
+
@hostname = Appsignal.config[:hostname] || Socket.gethostname
|
7
|
+
end
|
8
|
+
|
9
|
+
def call
|
10
|
+
puma_stats = fetch_puma_stats
|
11
|
+
return unless puma_stats
|
12
|
+
|
13
|
+
stats = JSON.parse puma_stats, :symbolize_names => true
|
14
|
+
counts = {}
|
15
|
+
count_keys = [:backlog, :running, :pool_capacity, :max_threads]
|
16
|
+
|
17
|
+
if stats[:worker_status] # Multiple workers
|
18
|
+
stats[:worker_status].each do |worker|
|
19
|
+
stat = worker[:last_status]
|
20
|
+
count_keys.each do |key|
|
21
|
+
count_if_present counts, key, stat
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
gauge(:workers, stats[:workers], :type => :count)
|
26
|
+
gauge(:workers, stats[:booted_workers], :type => :booted)
|
27
|
+
gauge(:workers, stats[:old_workers], :type => :old)
|
28
|
+
else # Single worker
|
29
|
+
count_keys.each do |key|
|
30
|
+
count_if_present counts, key, stats
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
gauge(:connection_backlog, counts[:backlog]) if counts[:backlog]
|
35
|
+
gauge(:pool_capacity, counts[:pool_capacity]) if counts[:pool_capacity]
|
36
|
+
gauge(:threads, counts[:running], :type => :running) if counts[:running]
|
37
|
+
gauge(:threads, counts[:max_threads], :type => :max) if counts[:max_threads]
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
attr_reader :hostname
|
43
|
+
|
44
|
+
def gauge(field, count, tags = {})
|
45
|
+
Appsignal.set_gauge("puma_#{field}", count, tags.merge(:hostname => hostname))
|
46
|
+
end
|
47
|
+
|
48
|
+
def count_if_present(counts, key, stats)
|
49
|
+
stat_value = stats[key]
|
50
|
+
return unless stat_value
|
51
|
+
counts[key] ||= 0
|
52
|
+
counts[key] += stat_value
|
53
|
+
end
|
54
|
+
|
55
|
+
def fetch_puma_stats
|
56
|
+
::Puma.stats
|
57
|
+
rescue NoMethodError # rubocop:disable Lint/HandleExceptions
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module Appsignal
|
2
|
+
module Probes
|
3
|
+
# @api private
|
4
|
+
class SidekiqProbe
|
5
|
+
attr_reader :config
|
6
|
+
|
7
|
+
def self.dependencies_present?
|
8
|
+
Gem::Version.new(::Redis::VERSION) >= Gem::Version.new("3.3.5")
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(config = {})
|
12
|
+
@config = config
|
13
|
+
@cache = {}
|
14
|
+
config_string = " with config: #{config}" unless config.empty?
|
15
|
+
Appsignal.logger.debug("Initializing Sidekiq probe#{config_string}")
|
16
|
+
require "sidekiq/api"
|
17
|
+
end
|
18
|
+
|
19
|
+
def call
|
20
|
+
track_redis_info
|
21
|
+
track_stats
|
22
|
+
track_queues
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
attr_reader :cache
|
28
|
+
|
29
|
+
def track_redis_info
|
30
|
+
return unless ::Sidekiq.respond_to?(:redis_info)
|
31
|
+
redis_info = ::Sidekiq.redis_info
|
32
|
+
|
33
|
+
gauge "connection_count", redis_info.fetch("connected_clients")
|
34
|
+
gauge "memory_usage", redis_info.fetch("used_memory")
|
35
|
+
gauge "memory_usage_rss", redis_info.fetch("used_memory_rss")
|
36
|
+
end
|
37
|
+
|
38
|
+
def track_stats
|
39
|
+
stats = ::Sidekiq::Stats.new
|
40
|
+
|
41
|
+
gauge "worker_count", stats.workers_size
|
42
|
+
gauge "process_count", stats.processes_size
|
43
|
+
gauge_delta :jobs_processed, "job_count", stats.processed,
|
44
|
+
:status => :processed
|
45
|
+
gauge_delta :jobs_failed, "job_count", stats.failed, :status => :failed
|
46
|
+
gauge "job_count", stats.retry_size, :status => :retry_queue
|
47
|
+
gauge_delta :jobs_dead, "job_count", stats.dead_size, :status => :died
|
48
|
+
gauge "job_count", stats.scheduled_size, :status => :scheduled
|
49
|
+
gauge "job_count", stats.enqueued, :status => :enqueued
|
50
|
+
end
|
51
|
+
|
52
|
+
def track_queues
|
53
|
+
::Sidekiq::Queue.all.each do |queue|
|
54
|
+
gauge "queue_length", queue.size, :queue => queue.name
|
55
|
+
# Convert latency from seconds to milliseconds
|
56
|
+
gauge "queue_latency", queue.latency * 1_000.0, :queue => queue.name
|
57
|
+
end
|
58
|
+
end
|
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
|
+
Appsignal.logger.debug "Sidekiq probe: Using hostname config " \
|
90
|
+
"option #{@hostname.inspect} as hostname"
|
91
|
+
return @hostname
|
92
|
+
end
|
93
|
+
|
94
|
+
host = nil
|
95
|
+
::Sidekiq.redis { |c| host = c.connection[:host] }
|
96
|
+
Appsignal.logger.debug "Sidekiq probe: Using Redis server hostname " \
|
97
|
+
"#{host.inspect} as hostname"
|
98
|
+
@hostname = host
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -29,8 +29,11 @@ module Appsignal
|
|
29
29
|
Appsignal.logger.debug \
|
30
30
|
"Initializing Appsignal::Rack::JSExceptionCatcher"
|
31
31
|
deprecation_message "The Appsignal::Rack::JSExceptionCatcher is " \
|
32
|
-
"deprecated
|
33
|
-
"integration
|
32
|
+
"deprecated and will be removed in a future version. Please use " \
|
33
|
+
"the official AppSignal JavaScript integration by disabling " \
|
34
|
+
"`enable_frontend_error_catching` in your configuration and " \
|
35
|
+
"installing AppSignal for JavaScript instead. " \
|
36
|
+
"(https://docs.appsignal.com/front-end/)"
|
34
37
|
@app = app
|
35
38
|
end
|
36
39
|
|
@@ -228,12 +228,27 @@ module Appsignal
|
|
228
228
|
Appsignal.logger.warn("Queue start value #{start} is too big")
|
229
229
|
end
|
230
230
|
|
231
|
+
# Set the queue time based on the HTTP header or `:queue_start` env key
|
232
|
+
# value.
|
233
|
+
#
|
234
|
+
# This method will first try to read the queue time from the HTTP headers
|
235
|
+
# `X-Request-Start` or `X-Queue-Start`. Which are parsed by Rack as
|
236
|
+
# `HTTP_X_QUEUE_START` and `HTTP_X_REQUEST_START`.
|
237
|
+
# The header value is parsed by AppSignal as either milliseconds or
|
238
|
+
# microseconds.
|
239
|
+
#
|
240
|
+
# If no headers are found, or the value could not be parsed, it falls back
|
241
|
+
# on the `:queue_start` env key on this Transaction's {request} environment
|
242
|
+
# (called like `request.env[:queue_start]`). This value is parsed by
|
243
|
+
# AppSignal as seconds.
|
244
|
+
#
|
245
|
+
# @see https://docs.appsignal.com/ruby/instrumentation/request-queue-time.html
|
246
|
+
# @return [void]
|
231
247
|
def set_http_or_background_queue_start
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
end
|
248
|
+
start = http_queue_start || background_queue_start
|
249
|
+
return unless start
|
250
|
+
|
251
|
+
set_queue_start(start)
|
237
252
|
end
|
238
253
|
|
239
254
|
def set_metadata(key, value)
|
@@ -346,14 +361,14 @@ module Appsignal
|
|
346
361
|
#
|
347
362
|
# @return [nil] if no {#environment} is present.
|
348
363
|
# @return [nil] if there is no `:queue_start` in the {#environment}.
|
349
|
-
# @return [Integer]
|
364
|
+
# @return [Integer] `:queue_start` time (in seconds) converted to milliseconds
|
350
365
|
def background_queue_start
|
351
366
|
env = environment
|
352
367
|
return unless env
|
353
368
|
queue_start = env[:queue_start]
|
354
369
|
return unless queue_start
|
355
370
|
|
356
|
-
(queue_start.to_f * 1000.0).to_i
|
371
|
+
(queue_start.to_f * 1000.0).to_i # Convert seconds to milliseconds
|
357
372
|
end
|
358
373
|
|
359
374
|
# Returns HTTP queue start time in milliseconds.
|
data/lib/appsignal/version.rb
CHANGED
@@ -17,7 +17,8 @@ Puma::Plugin.create do
|
|
17
17
|
launcher.events.on_booted do
|
18
18
|
require "appsignal"
|
19
19
|
if ::Puma.respond_to?(:stats)
|
20
|
-
|
20
|
+
require "appsignal/probes/puma"
|
21
|
+
Appsignal::Minutely.probes.register :puma, Appsignal::Probes::PumaProbe
|
21
22
|
end
|
22
23
|
Appsignal.start
|
23
24
|
Appsignal.start_logger
|
@@ -263,7 +263,8 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
|
|
263
263
|
},
|
264
264
|
"download" => {
|
265
265
|
"download_url" => kind_of(String),
|
266
|
-
"checksum" => "verified"
|
266
|
+
"checksum" => "verified",
|
267
|
+
"http_proxy" => nil
|
267
268
|
},
|
268
269
|
"build" => {
|
269
270
|
"time" => kind_of(String),
|
@@ -148,6 +148,7 @@ describe Appsignal::Config do
|
|
148
148
|
:instrument_redis => true,
|
149
149
|
:instrument_sequel => true,
|
150
150
|
:skip_session_data => false,
|
151
|
+
:send_environment_metadata => true,
|
151
152
|
:send_params => true,
|
152
153
|
:endpoint => "https://push.appsignal.com",
|
153
154
|
:push_api_key => "abc",
|
@@ -411,7 +412,8 @@ describe Appsignal::Config do
|
|
411
412
|
:instrument_sequel => false,
|
412
413
|
:files_world_accessible => false,
|
413
414
|
:request_headers => %w[accept accept-charset],
|
414
|
-
:revision => "v2.5.1"
|
415
|
+
:revision => "v2.5.1",
|
416
|
+
:send_environment_metadata => false
|
415
417
|
}
|
416
418
|
end
|
417
419
|
before do
|
@@ -428,6 +430,7 @@ describe Appsignal::Config do
|
|
428
430
|
ENV["APPSIGNAL_INSTRUMENT_SEQUEL"] = "false"
|
429
431
|
ENV["APPSIGNAL_FILES_WORLD_ACCESSIBLE"] = "false"
|
430
432
|
ENV["APPSIGNAL_REQUEST_HEADERS"] = "accept,accept-charset"
|
433
|
+
ENV["APPSIGNAL_SEND_ENVIRONMENT_METADATA"] = "false"
|
431
434
|
ENV["APP_REVISION"] = "v2.5.1"
|
432
435
|
end
|
433
436
|
|
@@ -527,6 +530,7 @@ describe Appsignal::Config do
|
|
527
530
|
config[:running_in_container] = false
|
528
531
|
config[:dns_servers] = ["8.8.8.8", "8.8.4.4"]
|
529
532
|
config[:transaction_debug_mode] = true
|
533
|
+
config[:send_environment_metadata] = false
|
530
534
|
config[:revision] = "v2.5.1"
|
531
535
|
config.write_to_environment
|
532
536
|
end
|
@@ -555,6 +559,7 @@ describe Appsignal::Config do
|
|
555
559
|
expect(ENV["_APPSIGNAL_DNS_SERVERS"]).to eq "8.8.8.8,8.8.4.4"
|
556
560
|
expect(ENV["_APPSIGNAL_FILES_WORLD_ACCESSIBLE"]).to eq "true"
|
557
561
|
expect(ENV["_APPSIGNAL_TRANSACTION_DEBUG_MODE"]).to eq "true"
|
562
|
+
expect(ENV["_APPSIGNAL_SEND_ENVIRONMENT_METADATA"]).to eq "false"
|
558
563
|
expect(ENV["_APP_REVISION"]).to eq "v2.5.1"
|
559
564
|
expect(ENV).to_not have_key("_APPSIGNAL_WORKING_DIR_PATH")
|
560
565
|
expect(ENV).to_not have_key("_APPSIGNAL_WORKING_DIRECTORY_PATH")
|
@@ -0,0 +1,167 @@
|
|
1
|
+
describe Appsignal::Environment do
|
2
|
+
include EnvironmentMetadataHelper
|
3
|
+
|
4
|
+
before(:context) { start_agent }
|
5
|
+
before { capture_environment_metadata_report_calls }
|
6
|
+
|
7
|
+
def report(key, &value_block)
|
8
|
+
described_class.report(key, &value_block)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe ".report" do
|
12
|
+
it "sends environment metadata to the extension" do
|
13
|
+
logs =
|
14
|
+
capture_logs do
|
15
|
+
report("_test_ruby_version") { "1.0.0" }
|
16
|
+
expect_environment_metadata("_test_ruby_version", "1.0.0")
|
17
|
+
end
|
18
|
+
expect(logs).to be_empty
|
19
|
+
end
|
20
|
+
|
21
|
+
context "when the key is a non String type" do
|
22
|
+
it "does not set the value" do
|
23
|
+
logs =
|
24
|
+
capture_logs do
|
25
|
+
report(:_test_symbol) { "1.0.0" }
|
26
|
+
expect_not_environment_metadata(:_test_symbol)
|
27
|
+
expect_not_environment_metadata("_test_symbol")
|
28
|
+
end
|
29
|
+
expect(logs).to contains_log(
|
30
|
+
:error,
|
31
|
+
"Unable to report on environment metadata: Unsupported value type for :_test_symbol"
|
32
|
+
)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "when the key is nil" do
|
37
|
+
it "does not set the value" do
|
38
|
+
logs =
|
39
|
+
capture_logs do
|
40
|
+
report(nil) { "1" }
|
41
|
+
expect_not_environment_metadata(nil)
|
42
|
+
end
|
43
|
+
expect(logs).to contains_log(
|
44
|
+
:error,
|
45
|
+
"Unable to report on environment metadata: Unsupported value type for nil"
|
46
|
+
)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "when the value is true or false" do
|
51
|
+
it "reports true or false as Strings" do
|
52
|
+
logs =
|
53
|
+
capture_logs do
|
54
|
+
report("_test_true") { true }
|
55
|
+
report("_test_false") { false }
|
56
|
+
expect_environment_metadata("_test_true", "true")
|
57
|
+
expect_environment_metadata("_test_false", "false")
|
58
|
+
end
|
59
|
+
expect(logs).to be_empty
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "when the value is nil" do
|
64
|
+
it "does not set the value" do
|
65
|
+
logs =
|
66
|
+
capture_logs do
|
67
|
+
report("_test_ruby_version") { nil }
|
68
|
+
expect_not_environment_metadata("_test_ruby_version")
|
69
|
+
end
|
70
|
+
expect(logs).to contains_log(
|
71
|
+
:error,
|
72
|
+
"Unable to report on environment metadata \"_test_ruby_version\": " \
|
73
|
+
"Unsupported value type for nil"
|
74
|
+
)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context "when the value block raises an error" do
|
79
|
+
it "does not re-raise the error and writes it to the log" do
|
80
|
+
logs =
|
81
|
+
capture_logs do
|
82
|
+
report("_test_error") { raise "uh oh" }
|
83
|
+
expect_not_environment_metadata("_test_error")
|
84
|
+
end
|
85
|
+
expect(logs).to contains_log(
|
86
|
+
:error,
|
87
|
+
"Unable to report on environment metadata \"_test_error\":\n" \
|
88
|
+
"RuntimeError: uh oh"
|
89
|
+
)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context "when something unforseen errors" do
|
94
|
+
it "does not re-raise the error and writes it to the log" do
|
95
|
+
klass = Class.new do
|
96
|
+
def inspect
|
97
|
+
raise "inspect error"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
logs =
|
102
|
+
capture_logs do
|
103
|
+
report(klass.new) { raise "value error" }
|
104
|
+
expect(Appsignal::Extension).to_not have_received(:set_environment_metadata)
|
105
|
+
end
|
106
|
+
expect(logs).to contains_log(
|
107
|
+
:error,
|
108
|
+
"Unable to report on environment metadata:\n" \
|
109
|
+
"RuntimeError: inspect error"
|
110
|
+
)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe ".report_supported_gems" do
|
116
|
+
it "reports about all AppSignal supported gems in the bundle" do
|
117
|
+
logs = capture_logs { described_class.report_supported_gems }
|
118
|
+
|
119
|
+
expect(logs).to be_empty
|
120
|
+
|
121
|
+
bundle_gem_specs = ::Bundler.rubygems.all_specs
|
122
|
+
rack_spec = bundle_gem_specs.find { |s| s.name == "rack" }
|
123
|
+
rake_spec = bundle_gem_specs.find { |s| s.name == "rake" }
|
124
|
+
expect_environment_metadata("ruby_rack_version", rack_spec.version.to_s)
|
125
|
+
expect_environment_metadata("ruby_rake_version", rake_spec.version.to_s)
|
126
|
+
expect(rack_spec.version.to_s).to_not be_empty
|
127
|
+
expect(rake_spec.version.to_s).to_not be_empty
|
128
|
+
end
|
129
|
+
|
130
|
+
context "when something unforseen errors" do
|
131
|
+
it "does not re-raise the error and writes it to the log" do
|
132
|
+
expect(Bundler).to receive(:rubygems).and_raise(RuntimeError, "bundler error")
|
133
|
+
|
134
|
+
logs = capture_logs { described_class.report_supported_gems }
|
135
|
+
expect(logs).to contains_log(
|
136
|
+
:error,
|
137
|
+
"Unable to report supported gems:\nRuntimeError: bundler error"
|
138
|
+
)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe ".report_enabled" do
|
144
|
+
it "reports a feature being enabled" do
|
145
|
+
logs = capture_logs { described_class.report_enabled("a_test") }
|
146
|
+
|
147
|
+
expect(logs).to be_empty
|
148
|
+
expect_environment_metadata("ruby_a_test_enabled", "true")
|
149
|
+
end
|
150
|
+
|
151
|
+
context "when something unforseen errors" do
|
152
|
+
it "does not re-raise the error and writes it to the log" do
|
153
|
+
klass = Class.new do
|
154
|
+
def to_s
|
155
|
+
raise "to_s error"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
logs = capture_logs { described_class.report_enabled(klass.new) }
|
160
|
+
expect(logs).to contains_log(
|
161
|
+
:error,
|
162
|
+
"Unable to report integration enabled:\nRuntimeError: to_s error"
|
163
|
+
)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|