appsignal 2.10.8-java → 2.11.0.beta.1-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/.rubocop.yml +3 -0
- data/.semaphore/semaphore.yml +75 -61
- data/CHANGELOG.md +21 -0
- data/build_matrix.yml +13 -7
- data/ext/agent.yml +19 -19
- data/ext/appsignal_extension.c +10 -1
- data/ext/base.rb +11 -2
- data/gemfiles/padrino.gemfile +2 -2
- data/gemfiles/rails-4.2.gemfile +9 -2
- data/gemfiles/rails-5.0.gemfile +1 -0
- data/gemfiles/rails-5.1.gemfile +1 -0
- data/gemfiles/rails-5.2.gemfile +1 -0
- data/gemfiles/rails-6.0.gemfile +1 -0
- data/gemfiles/resque-1.gemfile +7 -0
- data/gemfiles/{resque.gemfile → resque-2.gemfile} +1 -1
- 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.rb +2 -0
- data/lib/appsignal/hooks/active_job.rb +89 -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/resque.rb +60 -0
- data/lib/appsignal/hooks/sequel.rb +2 -0
- data/lib/appsignal/hooks/sidekiq.rb +18 -191
- data/lib/appsignal/integrations/object.rb +4 -0
- data/lib/appsignal/integrations/que.rb +1 -1
- data/lib/appsignal/integrations/resque.rb +9 -12
- data/lib/appsignal/integrations/resque_active_job.rb +9 -24
- 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 +32 -7
- data/lib/appsignal/utils/deprecation_message.rb +5 -1
- 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/activejob_spec.rb +458 -0
- data/spec/lib/appsignal/hooks/puma_spec.rb +2 -181
- data/spec/lib/appsignal/hooks/resque_spec.rb +185 -0
- data/spec/lib/appsignal/hooks/sidekiq_spec.rb +292 -546
- data/spec/lib/appsignal/integrations/padrino_spec.rb +1 -1
- data/spec/lib/appsignal/integrations/que_spec.rb +25 -6
- data/spec/lib/appsignal/integrations/resque_active_job_spec.rb +20 -137
- data/spec/lib/appsignal/integrations/resque_spec.rb +20 -85
- data/spec/lib/appsignal/probes/puma_spec.rb +180 -0
- data/spec/lib/appsignal/probes/sidekiq_spec.rb +204 -0
- data/spec/lib/appsignal/rack/js_exception_catcher_spec.rb +9 -4
- data/spec/lib/appsignal/transaction_spec.rb +35 -20
- data/spec/lib/appsignal_spec.rb +22 -0
- data/spec/lib/puma/appsignal_spec.rb +1 -1
- data/spec/support/helpers/action_mailer_helpers.rb +25 -0
- data/spec/support/helpers/dependency_helper.rb +12 -0
- data/spec/support/helpers/env_helpers.rb +1 -1
- data/spec/support/helpers/environment_metdata_helper.rb +16 -0
- data/spec/support/helpers/transaction_helpers.rb +6 -0
- data/spec/support/stubs/sidekiq/api.rb +2 -2
- metadata +25 -5
@@ -4,18 +4,15 @@ module Appsignal
|
|
4
4
|
module Integrations
|
5
5
|
# @api private
|
6
6
|
module ResquePlugin
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
"
|
14
|
-
:
|
15
|
-
|
16
|
-
) do
|
17
|
-
yield
|
18
|
-
end
|
7
|
+
def self.extended(_)
|
8
|
+
callers = caller
|
9
|
+
Appsignal::Utils::DeprecationMessage.message \
|
10
|
+
"The AppSignal ResquePlugin is deprecated and does " \
|
11
|
+
"nothing on extend. In this version of the AppSignal Ruby gem " \
|
12
|
+
"the integration with Resque is automatic on all Resque workers. " \
|
13
|
+
"Please remove the following line from this file to remove this " \
|
14
|
+
"message: extend Appsignal::Integrations::ResquePlugin\n" \
|
15
|
+
"#{callers.first}"
|
19
16
|
end
|
20
17
|
end
|
21
18
|
end
|
@@ -4,30 +4,15 @@ module Appsignal
|
|
4
4
|
module Integrations
|
5
5
|
# @api private
|
6
6
|
module ResqueActiveJobPlugin
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
Appsignal.monitor_single_transaction(
|
18
|
-
"perform_job.resque",
|
19
|
-
:class => job.class.to_s,
|
20
|
-
:method => "perform",
|
21
|
-
:params => params,
|
22
|
-
:metadata => {
|
23
|
-
:id => job.job_id,
|
24
|
-
:queue => job.queue_name
|
25
|
-
}
|
26
|
-
) do
|
27
|
-
block.call
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
7
|
+
def self.included(_)
|
8
|
+
callers = caller
|
9
|
+
Appsignal::Utils::DeprecationMessage.message \
|
10
|
+
"The AppSignal ResqueActiveJobPlugin is deprecated and does " \
|
11
|
+
"nothing on extend. In this version of the AppSignal Ruby gem " \
|
12
|
+
"the integration with Resque is automatic on all Resque workers. " \
|
13
|
+
"Please remove the following line from this file to remove this " \
|
14
|
+
"message: include Appsignal::Integrations::ResqueActiveJobPlugin\n" \
|
15
|
+
"#{callers.first}"
|
31
16
|
end
|
32
17
|
end
|
33
18
|
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
|
|
@@ -221,6 +221,16 @@ module Appsignal
|
|
221
221
|
set_action_if_nil(group_and_action.compact.join("#"))
|
222
222
|
end
|
223
223
|
|
224
|
+
# Set queue start time for transaction.
|
225
|
+
#
|
226
|
+
# Most commononly called by {set_http_or_background_queue_start}.
|
227
|
+
#
|
228
|
+
# @param start [Integer] Queue start time in milliseconds.
|
229
|
+
# @raise [RangeError] When the queue start time value is too big, this
|
230
|
+
# method raises a RangeError.
|
231
|
+
# @raise [TypeError] Raises a TypeError when the given `start` argument is
|
232
|
+
# not an Integer.
|
233
|
+
# @return [void]
|
224
234
|
def set_queue_start(start)
|
225
235
|
return unless start
|
226
236
|
@ext.set_queue_start(start)
|
@@ -228,12 +238,27 @@ module Appsignal
|
|
228
238
|
Appsignal.logger.warn("Queue start value #{start} is too big")
|
229
239
|
end
|
230
240
|
|
241
|
+
# Set the queue time based on the HTTP header or `:queue_start` env key
|
242
|
+
# value.
|
243
|
+
#
|
244
|
+
# This method will first try to read the queue time from the HTTP headers
|
245
|
+
# `X-Request-Start` or `X-Queue-Start`. Which are parsed by Rack as
|
246
|
+
# `HTTP_X_QUEUE_START` and `HTTP_X_REQUEST_START`.
|
247
|
+
# The header value is parsed by AppSignal as either milliseconds or
|
248
|
+
# microseconds.
|
249
|
+
#
|
250
|
+
# If no headers are found, or the value could not be parsed, it falls back
|
251
|
+
# on the `:queue_start` env key on this Transaction's {request} environment
|
252
|
+
# (called like `request.env[:queue_start]`). This value is parsed by
|
253
|
+
# AppSignal as seconds.
|
254
|
+
#
|
255
|
+
# @see https://docs.appsignal.com/ruby/instrumentation/request-queue-time.html
|
256
|
+
# @return [void]
|
231
257
|
def set_http_or_background_queue_start
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
end
|
258
|
+
start = http_queue_start || background_queue_start
|
259
|
+
return unless start
|
260
|
+
|
261
|
+
set_queue_start(start)
|
237
262
|
end
|
238
263
|
|
239
264
|
def set_metadata(key, value)
|
@@ -346,14 +371,14 @@ module Appsignal
|
|
346
371
|
#
|
347
372
|
# @return [nil] if no {#environment} is present.
|
348
373
|
# @return [nil] if there is no `:queue_start` in the {#environment}.
|
349
|
-
# @return [Integer]
|
374
|
+
# @return [Integer] `:queue_start` time (in seconds) converted to milliseconds
|
350
375
|
def background_queue_start
|
351
376
|
env = environment
|
352
377
|
return unless env
|
353
378
|
queue_start = env[:queue_start]
|
354
379
|
return unless queue_start
|
355
380
|
|
356
|
-
(queue_start.to_f * 1000.0).to_i
|
381
|
+
(queue_start.to_f * 1000.0).to_i # Convert seconds to milliseconds
|
357
382
|
end
|
358
383
|
|
359
384
|
# Returns HTTP queue start time in milliseconds.
|
@@ -1,10 +1,14 @@
|
|
1
1
|
module Appsignal
|
2
2
|
module Utils
|
3
3
|
module DeprecationMessage
|
4
|
-
def
|
4
|
+
def self.message(message, logger = Appsignal.logger)
|
5
5
|
$stderr.puts "appsignal WARNING: #{message}"
|
6
6
|
logger.warn message
|
7
7
|
end
|
8
|
+
|
9
|
+
def deprecation_message(message, logger = Appsignal.logger)
|
10
|
+
Appsignal::Utils::DeprecationMessage.message(message, logger)
|
11
|
+
end
|
8
12
|
end
|
9
13
|
end
|
10
14
|
end
|
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
|