appsignal 3.4.4 → 3.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +1 -1
  4. data/.semaphore/semaphore.yml +683 -52
  5. data/CHANGELOG.md +353 -4
  6. data/README.md +3 -0
  7. data/Rakefile +4 -2
  8. data/appsignal.gemspec +1 -1
  9. data/build_matrix.yml +27 -13
  10. data/ext/Rakefile +8 -1
  11. data/ext/agent.rb +27 -27
  12. data/ext/appsignal_extension.c +0 -24
  13. data/ext/base.rb +5 -2
  14. data/gemfiles/dry-monitor.gemfile +5 -0
  15. data/gemfiles/rails-7.1.gemfile +7 -0
  16. data/gemfiles/redis-4.gemfile +5 -0
  17. data/gemfiles/redis-5.gemfile +6 -0
  18. data/lib/appsignal/auth_check.rb +1 -1
  19. data/lib/appsignal/cli/diagnose/paths.rb +33 -10
  20. data/lib/appsignal/cli/diagnose.rb +15 -1
  21. data/lib/appsignal/config.rb +72 -7
  22. data/lib/appsignal/demo.rb +1 -1
  23. data/lib/appsignal/environment.rb +24 -13
  24. data/lib/appsignal/event_formatter/action_view/render_formatter.rb +1 -1
  25. data/lib/appsignal/event_formatter/rom/sql_formatter.rb +18 -0
  26. data/lib/appsignal/event_formatter/sequel/sql_formatter.rb +1 -1
  27. data/lib/appsignal/event_formatter.rb +2 -2
  28. data/lib/appsignal/extension/jruby.rb +4 -17
  29. data/lib/appsignal/extension.rb +1 -1
  30. data/lib/appsignal/heartbeat.rb +71 -0
  31. data/lib/appsignal/helpers/instrumentation.rb +10 -10
  32. data/lib/appsignal/helpers/metrics.rb +15 -13
  33. data/lib/appsignal/hooks/active_job.rb +9 -1
  34. data/lib/appsignal/hooks/active_support_notifications.rb +18 -9
  35. data/lib/appsignal/hooks/dry_monitor.rb +20 -0
  36. data/lib/appsignal/hooks/redis.rb +1 -0
  37. data/lib/appsignal/hooks/redis_client.rb +28 -0
  38. data/lib/appsignal/hooks.rb +4 -2
  39. data/lib/appsignal/integrations/active_support_notifications.rb +26 -0
  40. data/lib/appsignal/integrations/dry_monitor.rb +22 -0
  41. data/lib/appsignal/integrations/hanami.rb +1 -1
  42. data/lib/appsignal/integrations/padrino.rb +1 -1
  43. data/lib/appsignal/integrations/railtie.rb +28 -6
  44. data/lib/appsignal/integrations/redis_client.rb +20 -0
  45. data/lib/appsignal/integrations/sidekiq.rb +2 -2
  46. data/lib/appsignal/integrations/sinatra.rb +1 -1
  47. data/lib/appsignal/logger.rb +7 -5
  48. data/lib/appsignal/minutely.rb +4 -4
  49. data/lib/appsignal/probes/gvl.rb +1 -1
  50. data/lib/appsignal/probes/helpers.rb +1 -1
  51. data/lib/appsignal/probes/mri.rb +1 -1
  52. data/lib/appsignal/probes/sidekiq.rb +10 -8
  53. data/lib/appsignal/rack/generic_instrumentation.rb +1 -1
  54. data/lib/appsignal/rack/rails_instrumentation.rb +2 -2
  55. data/lib/appsignal/rack/sinatra_instrumentation.rb +5 -4
  56. data/lib/appsignal/rack/streaming_listener.rb +1 -1
  57. data/lib/appsignal/span.rb +2 -2
  58. data/lib/appsignal/transaction.rb +69 -14
  59. data/lib/appsignal/utils/deprecation_message.rb +2 -2
  60. data/lib/appsignal/utils/hash_sanitizer.rb +21 -9
  61. data/lib/appsignal/version.rb +1 -1
  62. data/lib/appsignal.rb +38 -31
  63. data/lib/puma/plugin/appsignal.rb +1 -1
  64. data/resources/cacert.pem +321 -159
  65. data/spec/lib/appsignal/capistrano2_spec.rb +2 -2
  66. data/spec/lib/appsignal/capistrano3_spec.rb +2 -2
  67. data/spec/lib/appsignal/cli/diagnose/utils_spec.rb +11 -0
  68. data/spec/lib/appsignal/cli/diagnose_spec.rb +70 -13
  69. data/spec/lib/appsignal/config_spec.rb +75 -18
  70. data/spec/lib/appsignal/environment_spec.rb +3 -3
  71. data/spec/lib/appsignal/event_formatter/mongo_ruby_driver/query_formatter_spec.rb +1 -1
  72. data/spec/lib/appsignal/event_formatter/rom/sql_formatter_spec.rb +22 -0
  73. data/spec/lib/appsignal/heartbeat_spec.rb +89 -0
  74. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +6 -0
  75. data/spec/lib/appsignal/hooks/activejob_spec.rb +26 -1
  76. data/spec/lib/appsignal/hooks/dry_monitor_spec.rb +104 -0
  77. data/spec/lib/appsignal/hooks/redis_client_spec.rb +238 -0
  78. data/spec/lib/appsignal/hooks/redis_spec.rb +98 -76
  79. data/spec/lib/appsignal/hooks/resque_spec.rb +1 -1
  80. data/spec/lib/appsignal/hooks_spec.rb +5 -5
  81. data/spec/lib/appsignal/integrations/railtie_spec.rb +128 -59
  82. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +20 -15
  83. data/spec/lib/appsignal/integrations/sinatra_spec.rb +2 -2
  84. data/spec/lib/appsignal/minutely_spec.rb +2 -2
  85. data/spec/lib/appsignal/probes/sidekiq_spec.rb +29 -6
  86. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +1 -1
  87. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +163 -71
  88. data/spec/lib/appsignal/rack/streaming_listener_spec.rb +1 -0
  89. data/spec/lib/appsignal/transaction_spec.rb +139 -10
  90. data/spec/lib/appsignal/utils/hash_sanitizer_spec.rb +42 -4
  91. data/spec/lib/appsignal_spec.rb +63 -61
  92. data/spec/lib/puma/appsignal_spec.rb +1 -1
  93. data/spec/spec_helper.rb +7 -7
  94. data/spec/support/fixtures/projects/valid/config/appsignal.yml +3 -3
  95. data/spec/support/helpers/config_helpers.rb +6 -2
  96. data/spec/support/helpers/dependency_helper.rb +13 -1
  97. data/spec/support/helpers/log_helpers.rb +2 -2
  98. data/spec/support/helpers/rails_helper.rb +28 -0
  99. data/spec/support/matchers/have_colorized_text.rb +1 -1
  100. metadata +19 -5
  101. data/ext/._appsignal-agent +0 -0
@@ -0,0 +1,238 @@
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
+ context "with gem version new than 0.14.0" do
13
+ before { stub_const("RedisClient::VERSION", "1.2.3") }
14
+
15
+ it { is_expected.to be_truthy }
16
+ end
17
+
18
+ context "with gem version 0.14.0" do
19
+ before { stub_const("RedisClient::VERSION", "0.14.0") }
20
+
21
+ it { is_expected.to be_truthy }
22
+ end
23
+
24
+ context "with gem version older than 0.14.0" do
25
+ before { stub_const("RedisClient::VERSION", "0.13.9") }
26
+
27
+ it { is_expected.to be_falsy }
28
+ end
29
+ end
30
+
31
+ context "with rest-client gem" do
32
+ describe "integration" do
33
+ before do
34
+ Appsignal.config.config_hash[:instrument_redis] = true
35
+ end
36
+
37
+ context "install" do
38
+ before do
39
+ Appsignal::Hooks.load_hooks
40
+ end
41
+
42
+ it "includes the integration for the ruby connection" do
43
+ # Test if the last included module (prepended module) was our
44
+ # integration. That's not certain with the assertions below
45
+ # because we have to overwrite the `process` method for the test.
46
+ expect(RedisClient::RubyConnection.included_modules.first)
47
+ .to eql(Appsignal::Integrations::RedisClientIntegration)
48
+ end
49
+ end
50
+
51
+ context "requirements" do
52
+ it "driver should have the write method" do
53
+ # Since we stub the driver class below, to make sure that we don't
54
+ # create a real connection, the test won't fail if the method definition
55
+ # is changed.
56
+ method = RedisClient::RubyConnection.instance_method(:write)
57
+ expect(method.arity).to eql(1)
58
+ end
59
+ end
60
+
61
+ context "instrumentation" do
62
+ before do
63
+ start_agent
64
+ # Stub RedisClient::RubyConnection class so that it doesn't perform an actual
65
+ # Redis query. This class will be included (prepended) with the
66
+ # AppSignal Redis integration.
67
+ stub_const("RedisClient::RubyConnection", Class.new do
68
+ def initialize(config)
69
+ @config = config
70
+ end
71
+
72
+ def write(_commands)
73
+ "stub_write"
74
+ end
75
+ end)
76
+ # Load the integration again for the stubbed RedisClient::RubyConnection class.
77
+ # Call it directly because {Appsignal::Hooks.load_hooks} keeps
78
+ # track if it was installed already or not.
79
+ Appsignal::Hooks::RedisClientHook.new.install
80
+ end
81
+ let!(:transaction) do
82
+ Appsignal::Transaction.create("uuid", Appsignal::Transaction::HTTP_REQUEST, "test")
83
+ end
84
+ let!(:client_config) { RedisClient::Config.new(:id => "stub_id") }
85
+ around { |example| keep_transactions { example.run } }
86
+
87
+ it "instrument a redis call" do
88
+ connection = RedisClient::RubyConnection.new client_config
89
+ expect(connection.write([:get, "key"])).to eql("stub_write")
90
+
91
+ transaction_hash = transaction.to_h
92
+ expect(transaction_hash["events"]).to include(
93
+ hash_including(
94
+ "name" => "query.redis",
95
+ "body" => "get ?",
96
+ "title" => "stub_id"
97
+ )
98
+ )
99
+ end
100
+
101
+ it "instrument a redis script call" do
102
+ connection = ::RedisClient::RubyConnection.new client_config
103
+ script = "return redis.call('set',KEYS[1],ARGV[1])"
104
+ keys = ["foo"]
105
+ argv = ["bar"]
106
+ expect(connection.write([:eval, script, keys.size, keys,
107
+ argv])).to eql("stub_write")
108
+
109
+ transaction_hash = transaction.to_h
110
+ expect(transaction_hash["events"]).to include(
111
+ hash_including(
112
+ "name" => "query.redis",
113
+ "body" => "#{script} ? ?",
114
+ "title" => "stub_id"
115
+ )
116
+ )
117
+ end
118
+ end
119
+ end
120
+ end
121
+
122
+ if DependencyHelper.hiredis_client_present?
123
+ context "with hiredis driver" do
124
+ describe "integration" do
125
+ before do
126
+ Appsignal.config.config_hash[:instrument_redis] = true
127
+ end
128
+
129
+ context "install" do
130
+ before do
131
+ Appsignal::Hooks.load_hooks
132
+ end
133
+
134
+ it "includes the integration in the HiredisConnection class" do
135
+ # Test if the last included module (prepended module) was our
136
+ # integration. That's not certain with the assertions below
137
+ # because we have to overwrite the `process` method for the test.
138
+ expect(RedisClient::HiredisConnection.included_modules.first)
139
+ .to eql(Appsignal::Integrations::RedisClientIntegration)
140
+ end
141
+ end
142
+
143
+ context "requirements" do
144
+ it "driver should have the write method" do
145
+ # Since we stub the driver class below, to make sure that we don't
146
+ # create a real connection, the test won't fail if the method definition
147
+ # is changed.
148
+ method = RedisClient::HiredisConnection.instance_method(:write)
149
+ expect(method.arity).to eql(1)
150
+ end
151
+ end
152
+
153
+ context "instrumentation" do
154
+ before do
155
+ start_agent
156
+ # Stub RedisClient::HiredisConnection class so that it doesn't perform an actual
157
+ # Redis query. This class will be included (prepended) with the
158
+ # AppSignal Redis integration.
159
+ stub_const("RedisClient::HiredisConnection", Class.new do
160
+ def initialize(config)
161
+ @config = config
162
+ end
163
+
164
+ def write(_commands)
165
+ "stub_write"
166
+ end
167
+ end)
168
+ # Load the integration again for the stubbed RedisClient::HiredisConnection class.
169
+ # Call it directly because {Appsignal::Hooks.load_hooks} keeps
170
+ # track if it was installed already or not.
171
+ Appsignal::Hooks::RedisClientHook.new.install
172
+ end
173
+ let!(:transaction) do
174
+ Appsignal::Transaction.create("uuid", Appsignal::Transaction::HTTP_REQUEST,
175
+ "test")
176
+ end
177
+ let!(:client_config) { RedisClient::Config.new(:id => "stub_id") }
178
+ around { |example| keep_transactions { example.run } }
179
+
180
+ it "instrument a redis call" do
181
+ connection = RedisClient::HiredisConnection.new client_config
182
+ expect(connection.write([:get, "key"])).to eql("stub_write")
183
+
184
+ transaction_hash = transaction.to_h
185
+ expect(transaction_hash["events"]).to include(
186
+ hash_including(
187
+ "name" => "query.redis",
188
+ "body" => "get ?",
189
+ "title" => "stub_id"
190
+ )
191
+ )
192
+ end
193
+
194
+ it "instrument a redis script call" do
195
+ connection = ::RedisClient::HiredisConnection.new client_config
196
+ script = "return redis.call('set',KEYS[1],ARGV[1])"
197
+ keys = ["foo"]
198
+ argv = ["bar"]
199
+ expect(connection.write([:eval, script, keys.size, keys,
200
+ argv])).to eql("stub_write")
201
+
202
+ transaction_hash = transaction.to_h
203
+ expect(transaction_hash["events"]).to include(
204
+ hash_including(
205
+ "name" => "query.redis",
206
+ "body" => "#{script} ? ?",
207
+ "title" => "stub_id"
208
+ )
209
+ )
210
+ end
211
+ end
212
+ end
213
+ end
214
+ end
215
+ end
216
+
217
+ context "with instrumentation disabled" do
218
+ before do
219
+ Appsignal.config.config_hash[:instrument_redis] = false
220
+ end
221
+
222
+ describe "#dependencies_present?" do
223
+ subject { described_class.new.dependencies_present? }
224
+
225
+ it { is_expected.to be_falsy }
226
+ end
227
+ end
228
+ end
229
+ else
230
+ context "without redis-client" do
231
+ describe "#dependencies_present?" do
232
+ subject { described_class.new.dependencies_present? }
233
+
234
+ it { is_expected.to be_falsy }
235
+ end
236
+ end
237
+ end
238
+ 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
@@ -160,7 +160,7 @@ describe Appsignal::Hooks::ResqueHook do
160
160
  end
161
161
  after { Object.send(:remove_const, :ActiveJobMock) }
162
162
 
163
- it "does not set arguments but lets the ActiveJob intergration handle it" do
163
+ it "does not set arguments but lets the ActiveJob integration handle it" do
164
164
  perform_job(
165
165
  ResqueTestJob,
166
166
  "class" => "ActiveJob::QueueAdapters::ResqueAdapter::JobWrapper",
@@ -47,7 +47,7 @@ describe Appsignal::Hooks do
47
47
  Appsignal::Hooks.hooks.delete(:mock_present_hook)
48
48
  end
49
49
 
50
- it "should not install if depencies are not present" do
50
+ it "should not install if dependencies are not present" do
51
51
  Appsignal::Hooks::Hook.register(:mock_not_present_hook, MockNotPresentHook)
52
52
 
53
53
  expect(Appsignal::Hooks.hooks[:mock_not_present_hook]).to be_instance_of(MockNotPresentHook)
@@ -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)