appsignal 3.4.13 → 3.6.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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.semaphore/semaphore.yml +180 -14
  3. data/CHANGELOG.md +164 -0
  4. data/README.md +2 -0
  5. data/Rakefile +3 -1
  6. data/build_matrix.yml +7 -13
  7. data/ext/Rakefile +8 -1
  8. data/ext/agent.rb +27 -27
  9. data/ext/appsignal_extension.c +0 -24
  10. data/ext/base.rb +4 -1
  11. data/gemfiles/redis-4.gemfile +5 -0
  12. data/gemfiles/redis-5.gemfile +6 -0
  13. data/lib/appsignal/cli/diagnose/paths.rb +33 -10
  14. data/lib/appsignal/cli/diagnose.rb +6 -1
  15. data/lib/appsignal/config.rb +19 -5
  16. data/lib/appsignal/demo.rb +1 -1
  17. data/lib/appsignal/environment.rb +24 -13
  18. data/lib/appsignal/event_formatter.rb +1 -1
  19. data/lib/appsignal/extension/jruby.rb +4 -17
  20. data/lib/appsignal/extension.rb +1 -1
  21. data/lib/appsignal/helpers/instrumentation.rb +10 -10
  22. data/lib/appsignal/helpers/metrics.rb +15 -13
  23. data/lib/appsignal/hooks/active_job.rb +9 -1
  24. data/lib/appsignal/hooks/redis.rb +1 -0
  25. data/lib/appsignal/hooks/redis_client.rb +27 -0
  26. data/lib/appsignal/hooks.rb +3 -2
  27. data/lib/appsignal/integrations/hanami.rb +1 -1
  28. data/lib/appsignal/integrations/padrino.rb +1 -1
  29. data/lib/appsignal/integrations/railtie.rb +1 -1
  30. data/lib/appsignal/integrations/redis_client.rb +20 -0
  31. data/lib/appsignal/integrations/sidekiq.rb +2 -2
  32. data/lib/appsignal/integrations/sinatra.rb +1 -1
  33. data/lib/appsignal/logger.rb +2 -0
  34. data/lib/appsignal/minutely.rb +4 -4
  35. data/lib/appsignal/probes/gvl.rb +1 -1
  36. data/lib/appsignal/probes/helpers.rb +1 -1
  37. data/lib/appsignal/probes/mri.rb +1 -1
  38. data/lib/appsignal/probes/sidekiq.rb +10 -8
  39. data/lib/appsignal/rack/body_wrapper.rb +161 -0
  40. data/lib/appsignal/rack/generic_instrumentation.rb +18 -5
  41. data/lib/appsignal/rack/rails_instrumentation.rb +17 -5
  42. data/lib/appsignal/rack/sinatra_instrumentation.rb +17 -5
  43. data/lib/appsignal/rack/streaming_listener.rb +27 -36
  44. data/lib/appsignal/span.rb +2 -2
  45. data/lib/appsignal/transaction.rb +46 -10
  46. data/lib/appsignal/utils/deprecation_message.rb +2 -2
  47. data/lib/appsignal/version.rb +1 -1
  48. data/lib/appsignal.rb +38 -31
  49. data/resources/cacert.pem +321 -159
  50. data/spec/lib/appsignal/cli/diagnose/utils_spec.rb +11 -0
  51. data/spec/lib/appsignal/cli/diagnose_spec.rb +38 -12
  52. data/spec/lib/appsignal/config_spec.rb +3 -2
  53. data/spec/lib/appsignal/hooks/activejob_spec.rb +26 -1
  54. data/spec/lib/appsignal/hooks/redis_client_spec.rb +222 -0
  55. data/spec/lib/appsignal/hooks/redis_spec.rb +98 -76
  56. data/spec/lib/appsignal/hooks_spec.rb +4 -4
  57. data/spec/lib/appsignal/integrations/railtie_spec.rb +2 -2
  58. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +3 -3
  59. data/spec/lib/appsignal/integrations/sinatra_spec.rb +2 -2
  60. data/spec/lib/appsignal/minutely_spec.rb +2 -2
  61. data/spec/lib/appsignal/probes/sidekiq_spec.rb +29 -6
  62. data/spec/lib/appsignal/rack/body_wrapper_spec.rb +220 -0
  63. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +3 -2
  64. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +5 -3
  65. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +3 -1
  66. data/spec/lib/appsignal/rack/streaming_listener_spec.rb +9 -53
  67. data/spec/lib/appsignal/transaction_spec.rb +95 -2
  68. data/spec/lib/appsignal_spec.rb +62 -60
  69. data/spec/spec_helper.rb +1 -1
  70. data/spec/support/fixtures/projects/valid/config/appsignal.yml +3 -3
  71. data/spec/support/helpers/config_helpers.rb +6 -2
  72. data/spec/support/helpers/dependency_helper.rb +9 -1
  73. data/spec/support/helpers/log_helpers.rb +2 -2
  74. metadata +9 -2
@@ -152,6 +152,7 @@ describe Appsignal::Config do
152
152
  it "merges with the default config" do
153
153
  expect(config.config_hash).to eq(
154
154
  :active => true,
155
+ :activejob_report_errors => "all",
155
156
  :ca_file_path => File.join(resources_dir, "cacert.pem"),
156
157
  :debug => false,
157
158
  :dns_servers => [],
@@ -265,7 +266,7 @@ describe Appsignal::Config do
265
266
 
266
267
  context "with an overriden config file" do
267
268
  let(:config) do
268
- project_fixture_config("production", {}, Appsignal.logger,
269
+ project_fixture_config("production", {}, Appsignal.internal_logger,
269
270
  File.join(project_fixture_path, "config", "appsignal.yml"))
270
271
  end
271
272
 
@@ -276,7 +277,7 @@ describe Appsignal::Config do
276
277
 
277
278
  context "with an invalid overriden config file" do
278
279
  let(:config) do
279
- project_fixture_config("production", {}, Appsignal.logger,
280
+ project_fixture_config("production", {}, Appsignal.internal_logger,
280
281
  File.join(project_fixture_path, "config", "missing.yml"))
281
282
  end
282
283
 
@@ -76,7 +76,7 @@ if DependencyHelper.active_job_present?
76
76
  ActiveJob::Base.queue_adapter = :inline
77
77
 
78
78
  start_agent
79
- Appsignal.logger = test_logger(log)
79
+ Appsignal.internal_logger = test_logger(log)
80
80
  class ActiveJobTestJob < ActiveJob::Base
81
81
  def perform(*_args)
82
82
  end
@@ -222,6 +222,31 @@ if DependencyHelper.active_job_present?
222
222
  expect(events).to eq(expected_perform_events)
223
223
  end
224
224
 
225
+ context "with activejob_report_errors set to none" do
226
+ it "does not report the error" do
227
+ Appsignal.config = project_fixture_config("production")
228
+ Appsignal.config[:activejob_report_errors] = "none"
229
+
230
+ # Other calls we're testing in another test
231
+ allow(Appsignal).to receive(:increment_counter)
232
+ tags = { :queue => queue }
233
+ expect(Appsignal).to receive(:increment_counter)
234
+ .with("active_job_queue_job_count", 1, tags.merge(:status => :failed))
235
+ expect(Appsignal).to receive(:increment_counter)
236
+ .with("active_job_queue_job_count", 1, tags.merge(:status => :processed))
237
+
238
+ expect do
239
+ perform_job(ActiveJobErrorTestJob)
240
+ end.to raise_error(RuntimeError, "uh oh")
241
+
242
+ transaction = last_transaction
243
+ transaction_hash = transaction.to_h
244
+ expect(transaction_hash).to include(
245
+ "error" => nil
246
+ )
247
+ end
248
+ end
249
+
225
250
  if DependencyHelper.rails_version >= Gem::Version.new("5.0.0")
226
251
  context "with priority" do
227
252
  before do
@@ -0,0 +1,222 @@
1
+ describe Appsignal::Hooks::RedisClientHook do
2
+ before do
3
+ Appsignal.config = project_fixture_config
4
+ end
5
+
6
+ if DependencyHelper.redis_client_present?
7
+ context "with redis_client" do
8
+ context "with instrumentation enabled" do
9
+ describe "#dependencies_present?" do
10
+ subject { described_class.new.dependencies_present? }
11
+
12
+ it { is_expected.to be_truthy }
13
+ end
14
+
15
+ context "with rest-client gem" do
16
+ describe "integration" do
17
+ before do
18
+ Appsignal.config.config_hash[:instrument_redis] = true
19
+ end
20
+
21
+ context "install" do
22
+ before do
23
+ Appsignal::Hooks.load_hooks
24
+ end
25
+
26
+ it "includes the integration for the ruby connection" do
27
+ # Test if the last included module (prepended module) was our
28
+ # integration. That's not certain with the assertions below
29
+ # because we have to overwrite the `process` method for the test.
30
+ expect(RedisClient::RubyConnection.included_modules.first)
31
+ .to eql(Appsignal::Integrations::RedisClientIntegration)
32
+ end
33
+ end
34
+
35
+ context "requirements" do
36
+ it "driver should have the write method" do
37
+ # Since we stub the driver class below, to make sure that we don't
38
+ # create a real connection, the test won't fail if the method definition
39
+ # is changed.
40
+ method = RedisClient::RubyConnection.instance_method(:write)
41
+ expect(method.arity).to eql(1)
42
+ end
43
+ end
44
+
45
+ context "instrumentation" do
46
+ before do
47
+ start_agent
48
+ # Stub RedisClient::RubyConnection class so that it doesn't perform an actual
49
+ # Redis query. This class will be included (prepended) with the
50
+ # AppSignal Redis integration.
51
+ stub_const("RedisClient::RubyConnection", Class.new do
52
+ def initialize(config)
53
+ @config = config
54
+ end
55
+
56
+ def write(_commands)
57
+ "stub_write"
58
+ end
59
+ end)
60
+ # Load the integration again for the stubbed RedisClient::RubyConnection class.
61
+ # Call it directly because {Appsignal::Hooks.load_hooks} keeps
62
+ # track if it was installed already or not.
63
+ Appsignal::Hooks::RedisClientHook.new.install
64
+ end
65
+ let!(:transaction) do
66
+ Appsignal::Transaction.create("uuid", Appsignal::Transaction::HTTP_REQUEST, "test")
67
+ end
68
+ let!(:client_config) { RedisClient::Config.new(:id => "stub_id") }
69
+ around { |example| keep_transactions { example.run } }
70
+
71
+ it "instrument a redis call" do
72
+ connection = RedisClient::RubyConnection.new client_config
73
+ expect(connection.write([:get, "key"])).to eql("stub_write")
74
+
75
+ transaction_hash = transaction.to_h
76
+ expect(transaction_hash["events"]).to include(
77
+ hash_including(
78
+ "name" => "query.redis",
79
+ "body" => "get ?",
80
+ "title" => "stub_id"
81
+ )
82
+ )
83
+ end
84
+
85
+ it "instrument a redis script call" do
86
+ connection = ::RedisClient::RubyConnection.new client_config
87
+ script = "return redis.call('set',KEYS[1],ARGV[1])"
88
+ keys = ["foo"]
89
+ argv = ["bar"]
90
+ expect(connection.write([:eval, script, keys.size, keys,
91
+ argv])).to eql("stub_write")
92
+
93
+ transaction_hash = transaction.to_h
94
+ expect(transaction_hash["events"]).to include(
95
+ hash_including(
96
+ "name" => "query.redis",
97
+ "body" => "#{script} ? ?",
98
+ "title" => "stub_id"
99
+ )
100
+ )
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ if DependencyHelper.hiredis_client_present?
107
+ context "with hiredis driver" do
108
+ describe "integration" do
109
+ before do
110
+ Appsignal.config.config_hash[:instrument_redis] = true
111
+ end
112
+
113
+ context "install" do
114
+ before do
115
+ Appsignal::Hooks.load_hooks
116
+ end
117
+
118
+ it "includes the integration in the HiredisConnection class" do
119
+ # Test if the last included module (prepended module) was our
120
+ # integration. That's not certain with the assertions below
121
+ # because we have to overwrite the `process` method for the test.
122
+ expect(RedisClient::HiredisConnection.included_modules.first)
123
+ .to eql(Appsignal::Integrations::RedisClientIntegration)
124
+ end
125
+ end
126
+
127
+ context "requirements" do
128
+ it "driver should have the write method" do
129
+ # Since we stub the driver class below, to make sure that we don't
130
+ # create a real connection, the test won't fail if the method definition
131
+ # is changed.
132
+ method = RedisClient::HiredisConnection.instance_method(:write)
133
+ expect(method.arity).to eql(1)
134
+ end
135
+ end
136
+
137
+ context "instrumentation" do
138
+ before do
139
+ start_agent
140
+ # Stub RedisClient::HiredisConnection class so that it doesn't perform an actual
141
+ # Redis query. This class will be included (prepended) with the
142
+ # AppSignal Redis integration.
143
+ stub_const("RedisClient::HiredisConnection", Class.new do
144
+ def initialize(config)
145
+ @config = config
146
+ end
147
+
148
+ def write(_commands)
149
+ "stub_write"
150
+ end
151
+ end)
152
+ # Load the integration again for the stubbed RedisClient::HiredisConnection class.
153
+ # Call it directly because {Appsignal::Hooks.load_hooks} keeps
154
+ # track if it was installed already or not.
155
+ Appsignal::Hooks::RedisClientHook.new.install
156
+ end
157
+ let!(:transaction) do
158
+ Appsignal::Transaction.create("uuid", Appsignal::Transaction::HTTP_REQUEST,
159
+ "test")
160
+ end
161
+ let!(:client_config) { RedisClient::Config.new(:id => "stub_id") }
162
+ around { |example| keep_transactions { example.run } }
163
+
164
+ it "instrument a redis call" do
165
+ connection = RedisClient::HiredisConnection.new client_config
166
+ expect(connection.write([:get, "key"])).to eql("stub_write")
167
+
168
+ transaction_hash = transaction.to_h
169
+ expect(transaction_hash["events"]).to include(
170
+ hash_including(
171
+ "name" => "query.redis",
172
+ "body" => "get ?",
173
+ "title" => "stub_id"
174
+ )
175
+ )
176
+ end
177
+
178
+ it "instrument a redis script call" do
179
+ connection = ::RedisClient::HiredisConnection.new client_config
180
+ script = "return redis.call('set',KEYS[1],ARGV[1])"
181
+ keys = ["foo"]
182
+ argv = ["bar"]
183
+ expect(connection.write([:eval, script, keys.size, keys,
184
+ argv])).to eql("stub_write")
185
+
186
+ transaction_hash = transaction.to_h
187
+ expect(transaction_hash["events"]).to include(
188
+ hash_including(
189
+ "name" => "query.redis",
190
+ "body" => "#{script} ? ?",
191
+ "title" => "stub_id"
192
+ )
193
+ )
194
+ end
195
+ end
196
+ end
197
+ end
198
+ end
199
+ end
200
+
201
+ context "with instrumentation disabled" do
202
+ before do
203
+ Appsignal.config.config_hash[:instrument_redis] = false
204
+ end
205
+
206
+ describe "#dependencies_present?" do
207
+ subject { described_class.new.dependencies_present? }
208
+
209
+ it { is_expected.to be_falsy }
210
+ end
211
+ end
212
+ end
213
+ else
214
+ context "without redis" do
215
+ describe "#dependencies_present?" do
216
+ subject { described_class.new.dependencies_present? }
217
+
218
+ it { is_expected.to be_falsy }
219
+ end
220
+ end
221
+ end
222
+ end
@@ -5,100 +5,122 @@ describe Appsignal::Hooks::RedisHook do
5
5
 
6
6
  if DependencyHelper.redis_present?
7
7
  context "with redis" do
8
- context "with instrumentation enabled" do
9
- describe "#dependencies_present?" do
10
- subject { described_class.new.dependencies_present? }
8
+ if DependencyHelper.redis_client_present?
9
+ context "with redis-client" do
10
+ context "with instrumentation enabled" do
11
+ describe "#dependencies_present?" do
12
+ subject { described_class.new.dependencies_present? }
11
13
 
12
- it { is_expected.to be_truthy }
14
+ it { is_expected.to be_falsey }
15
+ end
16
+ end
13
17
  end
18
+ else
19
+ context "with instrumentation enabled" do
20
+ describe "#dependencies_present?" do
21
+ subject { described_class.new.dependencies_present? }
14
22
 
15
- describe "integration" do
16
- before do
17
- Appsignal.config.config_hash[:instrument_redis] = true
23
+ it { is_expected.to be_truthy }
18
24
  end
19
25
 
20
- context "install" do
26
+ describe "integration" do
21
27
  before do
22
- Appsignal::Hooks.load_hooks
28
+ Appsignal.config.config_hash[:instrument_redis] = true
23
29
  end
24
30
 
25
- it "does something" do
26
- # Test if the last included module (prepended module) was our
27
- # integration. That's not certain with the assertions below
28
- # because we have to overwrite the `process` method for the test.
29
- expect(Redis::Client.included_modules.first)
30
- .to eql(Appsignal::Integrations::RedisIntegration)
31
- end
32
- end
31
+ context "install" do
32
+ before do
33
+ Appsignal::Hooks.load_hooks
34
+ end
33
35
 
34
- context "instrumentation" do
35
- before do
36
- start_agent
37
- # Stub Redis::Client class so that it doesn't perform an actual
38
- # Redis query. This class will be included (prepended) with the
39
- # AppSignal Redis integration.
40
- stub_const("Redis::Client", Class.new do
41
- def id
42
- "stub_id"
43
- end
44
-
45
- def write(_commands)
46
- "stub_write"
47
- end
48
- end)
49
- # Load the integration again for the stubbed Redis::Client class.
50
- # Call it directly because {Appsignal::Hooks.load_hooks} keeps
51
- # track if it was installed already or not.
52
- Appsignal::Hooks::RedisHook.new.install
53
- end
54
- let!(:transaction) do
55
- Appsignal::Transaction.create("uuid", Appsignal::Transaction::HTTP_REQUEST, "test")
36
+ it "prepends instrumentation module" do
37
+ # Test if the last included module (prepended module) was our
38
+ # integration. That's not certain with the assertions below
39
+ # because we have to overwrite the `process` method for the test.
40
+ expect(Redis::Client.included_modules.first)
41
+ .to eql(Appsignal::Integrations::RedisIntegration)
42
+ end
56
43
  end
57
- around { |example| keep_transactions { example.run } }
58
-
59
- it "instrument a redis call" do
60
- client = Redis::Client.new
61
- expect(client.write([:get, "key"])).to eql("stub_write")
62
-
63
- transaction_hash = transaction.to_h
64
- expect(transaction_hash["events"]).to include(
65
- hash_including(
66
- "name" => "query.redis",
67
- "body" => "get ?",
68
- "title" => "stub_id"
69
- )
70
- )
44
+
45
+ context "requirements" do
46
+ it "driver should have the write method" do
47
+ # Since we stub the client class below, to make sure that we don't
48
+ # create a real connection, the test won't fail if the method definition
49
+ # is changed.
50
+ method = Redis::Client.instance_method(:call)
51
+ expect(method.arity).to eql(1)
52
+ end
71
53
  end
72
54
 
73
- it "instrument a redis script call" do
74
- client = Redis::Client.new
75
- script = "return redis.call('set',KEYS[1],ARGV[1])"
76
- keys = ["foo"]
77
- argv = ["bar"]
78
- expect(client.write([:eval, script, keys.size, keys, argv])).to eql("stub_write")
79
-
80
- transaction_hash = transaction.to_h
81
- expect(transaction_hash["events"]).to include(
82
- hash_including(
83
- "name" => "query.redis",
84
- "body" => "#{script} ? ?",
85
- "title" => "stub_id"
86
- )
87
- )
55
+ context "instrumentation" do
56
+ before do
57
+ start_agent
58
+ # Stub Redis::Client class so that it doesn't perform an actual
59
+ # Redis query. This class will be included (prepended) with the
60
+ # AppSignal Redis integration.
61
+ stub_const("Redis::Client", Class.new do
62
+ def id
63
+ "stub_id"
64
+ end
65
+
66
+ def write(_commands)
67
+ "stub_write"
68
+ end
69
+ end)
70
+ # Load the integration again for the stubbed Redis::Client class.
71
+ # Call it directly because {Appsignal::Hooks.load_hooks} keeps
72
+ # track if it was installed already or not.
73
+ Appsignal::Hooks::RedisHook.new.install
74
+ end
75
+ let!(:transaction) do
76
+ Appsignal::Transaction.create("uuid", Appsignal::Transaction::HTTP_REQUEST, "test")
77
+ end
78
+ around { |example| keep_transactions { example.run } }
79
+
80
+ it "instrument a redis call" do
81
+ client = Redis::Client.new
82
+ expect(client.write([:get, "key"])).to eql("stub_write")
83
+
84
+ transaction_hash = transaction.to_h
85
+ expect(transaction_hash["events"]).to include(
86
+ hash_including(
87
+ "name" => "query.redis",
88
+ "body" => "get ?",
89
+ "title" => "stub_id"
90
+ )
91
+ )
92
+ end
93
+
94
+ it "instrument a redis script call" do
95
+ client = Redis::Client.new
96
+ script = "return redis.call('set',KEYS[1],ARGV[1])"
97
+ keys = ["foo"]
98
+ argv = ["bar"]
99
+ expect(client.write([:eval, script, keys.size, keys, argv])).to eql("stub_write")
100
+
101
+ transaction_hash = transaction.to_h
102
+ expect(transaction_hash["events"]).to include(
103
+ hash_including(
104
+ "name" => "query.redis",
105
+ "body" => "#{script} ? ?",
106
+ "title" => "stub_id"
107
+ )
108
+ )
109
+ end
88
110
  end
89
111
  end
90
112
  end
91
- end
92
113
 
93
- context "with instrumentation disabled" do
94
- before do
95
- Appsignal.config.config_hash[:instrument_redis] = false
96
- end
114
+ context "with instrumentation disabled" do
115
+ before do
116
+ Appsignal.config.config_hash[:instrument_redis] = false
117
+ end
97
118
 
98
- describe "#dependencies_present?" do
99
- subject { described_class.new.dependencies_present? }
119
+ describe "#dependencies_present?" do
120
+ subject { described_class.new.dependencies_present? }
100
121
 
101
- it { is_expected.to be_falsy }
122
+ it { is_expected.to be_falsy }
123
+ end
102
124
  end
103
125
  end
104
126
  end
@@ -67,12 +67,12 @@ describe Appsignal::Hooks do
67
67
  expect(Appsignal::Hooks.hooks[:mock_error_hook]).to be_instance_of(MockErrorHook)
68
68
  expect(Appsignal::Hooks.hooks[:mock_error_hook].installed?).to be_falsy
69
69
 
70
- expect(Appsignal.logger).to receive(:error)
70
+ expect(Appsignal.internal_logger).to receive(:error)
71
71
  .with("Error while installing mock_error_hook hook: error").once
72
- expect(Appsignal.logger).to receive(:debug).ordered do |message|
72
+ expect(Appsignal.internal_logger).to receive(:debug).ordered do |message|
73
73
  expect(message).to eq("Installing mock_error_hook hook")
74
74
  end
75
- expect(Appsignal.logger).to receive(:debug).ordered do |message|
75
+ expect(Appsignal.internal_logger).to receive(:debug).ordered do |message|
76
76
  # Start of the error backtrace as debug log
77
77
  expect(message).to start_with(File.expand_path("../../..", __dir__))
78
78
  end
@@ -89,7 +89,7 @@ describe Appsignal::Hooks do
89
89
  let(:log_stream) { std_stream }
90
90
  let(:log) { log_contents(log_stream) }
91
91
  before do
92
- Appsignal.logger = test_logger(log_stream)
92
+ Appsignal.internal_logger = test_logger(log_stream)
93
93
  end
94
94
 
95
95
  def call_constant(&block)
@@ -18,9 +18,9 @@ if DependencyHelper.rails_present?
18
18
  describe "#initialize_appsignal" do
19
19
  let(:app) { MyApp::Application.new }
20
20
 
21
- describe ".logger" do
21
+ describe ".internal_logger" do
22
22
  before { Appsignal::Integrations::Railtie.initialize_appsignal(app) }
23
- subject { Appsignal.logger }
23
+ subject { Appsignal.internal_logger }
24
24
 
25
25
  it { is_expected.to be_a Logger }
26
26
  end
@@ -4,7 +4,7 @@ describe Appsignal::Integrations::SidekiqErrorHandler do
4
4
  let(:log) { StringIO.new }
5
5
  before do
6
6
  start_agent
7
- Appsignal.logger = test_logger(log)
7
+ Appsignal.internal_logger = test_logger(log)
8
8
  end
9
9
  around { |example| keep_transactions { example.run } }
10
10
 
@@ -86,7 +86,7 @@ describe Appsignal::Integrations::SidekiqMiddleware, :with_yaml_parse_error => f
86
86
  let(:log) { StringIO.new }
87
87
  before do
88
88
  start_agent
89
- Appsignal.logger = test_logger(log)
89
+ Appsignal.internal_logger = test_logger(log)
90
90
  end
91
91
  around { |example| keep_transactions { example.run } }
92
92
  after :with_yaml_parse_error => false do
@@ -423,7 +423,7 @@ if DependencyHelper.active_job_present?
423
423
  end
424
424
  around do |example|
425
425
  start_agent
426
- Appsignal.logger = test_logger(log)
426
+ Appsignal.internal_logger = test_logger(log)
427
427
  ActiveJob::Base.queue_adapter = :sidekiq
428
428
 
429
429
  class ActiveJobSidekiqTestJob < ActiveJob::Base
@@ -16,8 +16,8 @@ if DependencyHelper.sinatra_present?
16
16
  before { allow(Appsignal).to receive(:active?).and_return(true) }
17
17
  after { uninstall_sinatra_integration }
18
18
 
19
- context "Appsignal.logger" do
20
- subject { Appsignal.logger }
19
+ context "Appsignal.internal_logger" do
20
+ subject { Appsignal.internal_logger }
21
21
 
22
22
  it "sets a logger" do
23
23
  install_sinatra_integration
@@ -42,7 +42,7 @@ describe Appsignal::Minutely do
42
42
  let(:log_stream) { StringIO.new }
43
43
  let(:log) { log_contents(log_stream) }
44
44
  before do
45
- Appsignal.logger = test_logger(log_stream)
45
+ Appsignal.internal_logger = test_logger(log_stream)
46
46
  # Speed up test time
47
47
  allow(Appsignal::Minutely).to receive(:initial_wait_time).and_return(0.001)
48
48
  allow(Appsignal::Minutely).to receive(:wait_time).and_return(0.001)
@@ -287,7 +287,7 @@ describe Appsignal::Minutely do
287
287
  describe "#register" do
288
288
  let(:log_stream) { std_stream }
289
289
  let(:log) { log_contents(log_stream) }
290
- before { Appsignal.logger = test_logger(log_stream) }
290
+ before { Appsignal.internal_logger = test_logger(log_stream) }
291
291
 
292
292
  it "adds the by key probe" do
293
293
  probe = lambda {}
@@ -73,6 +73,20 @@ describe Appsignal::Probes::SidekiqProbe do
73
73
  module Sidekiq7Mock
74
74
  VERSION = "7.0.0".freeze
75
75
 
76
+ def self.redis_info_data=(info)
77
+ @redis_info_data = info
78
+ end
79
+
80
+ def self.redis_info_data
81
+ return @redis_info_data if defined?(@redis_info_data)
82
+
83
+ {
84
+ "connected_clients" => 2,
85
+ "used_memory" => 1024,
86
+ "used_memory_rss" => 512
87
+ }
88
+ end
89
+
76
90
  def self.redis
77
91
  yield Client.new
78
92
  end
@@ -83,11 +97,7 @@ describe Appsignal::Probes::SidekiqProbe do
83
97
  end
84
98
 
85
99
  def info
86
- {
87
- "connected_clients" => 2,
88
- "used_memory" => 1024,
89
- "used_memory_rss" => 512
90
- }
100
+ Sidekiq7Mock.redis_info_data
91
101
  end
92
102
  end
93
103
 
@@ -227,6 +237,19 @@ describe Appsignal::Probes::SidekiqProbe do
227
237
  probe.call
228
238
  probe.call
229
239
  end
240
+
241
+ context "when redis info doesn't contain requested keys" do
242
+ before { Sidekiq7Mock.redis_info_data = {} }
243
+
244
+ it "doesn't create metrics for nil values" do
245
+ expect_gauge("connection_count").never
246
+ expect_gauge("memory_usage").never
247
+ expect_gauge("memory_usage_rss").never
248
+ # Call probe twice so we can calculate the delta for some gauge values
249
+ probe.call
250
+ probe.call
251
+ end
252
+ end
230
253
  end
231
254
 
232
255
  context "with Sidekiq 6" do
@@ -301,7 +324,7 @@ describe Appsignal::Probes::SidekiqProbe do
301
324
  end
302
325
  end
303
326
 
304
- def expect_gauge(key, value, tags = {})
327
+ def expect_gauge(key, value = anything, tags = {})
305
328
  expect(Appsignal).to receive(:set_gauge)
306
329
  .with("sidekiq_#{key}", value, expected_default_tags.merge(tags))
307
330
  .and_call_original