appsignal 3.5.4 → 3.5.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.semaphore/semaphore.yml +147 -9
  3. data/CHANGELOG.md +23 -0
  4. data/README.md +2 -0
  5. data/build_matrix.yml +5 -9
  6. data/ext/Rakefile +7 -1
  7. data/ext/agent.rb +27 -27
  8. data/gemfiles/redis-4.gemfile +5 -0
  9. data/gemfiles/redis-5.gemfile +6 -0
  10. data/lib/appsignal/cli/diagnose.rb +1 -1
  11. data/lib/appsignal/config.rb +10 -5
  12. data/lib/appsignal/demo.rb +1 -1
  13. data/lib/appsignal/environment.rb +24 -13
  14. data/lib/appsignal/event_formatter.rb +1 -1
  15. data/lib/appsignal/extension/jruby.rb +4 -3
  16. data/lib/appsignal/extension.rb +1 -1
  17. data/lib/appsignal/helpers/instrumentation.rb +7 -7
  18. data/lib/appsignal/helpers/metrics.rb +3 -3
  19. data/lib/appsignal/hooks/redis.rb +1 -0
  20. data/lib/appsignal/hooks/redis_client.rb +27 -0
  21. data/lib/appsignal/hooks.rb +3 -2
  22. data/lib/appsignal/integrations/hanami.rb +1 -1
  23. data/lib/appsignal/integrations/padrino.rb +1 -1
  24. data/lib/appsignal/integrations/railtie.rb +1 -1
  25. data/lib/appsignal/integrations/redis_client.rb +20 -0
  26. data/lib/appsignal/integrations/sidekiq.rb +1 -1
  27. data/lib/appsignal/integrations/sinatra.rb +1 -1
  28. data/lib/appsignal/minutely.rb +4 -4
  29. data/lib/appsignal/probes/gvl.rb +1 -1
  30. data/lib/appsignal/probes/helpers.rb +1 -1
  31. data/lib/appsignal/probes/mri.rb +1 -1
  32. data/lib/appsignal/probes/sidekiq.rb +5 -5
  33. data/lib/appsignal/rack/generic_instrumentation.rb +1 -1
  34. data/lib/appsignal/rack/rails_instrumentation.rb +2 -2
  35. data/lib/appsignal/rack/sinatra_instrumentation.rb +2 -2
  36. data/lib/appsignal/rack/streaming_listener.rb +1 -1
  37. data/lib/appsignal/span.rb +2 -2
  38. data/lib/appsignal/transaction.rb +11 -11
  39. data/lib/appsignal/utils/deprecation_message.rb +2 -2
  40. data/lib/appsignal/version.rb +1 -1
  41. data/lib/appsignal.rb +37 -31
  42. data/spec/lib/appsignal/config_spec.rb +2 -2
  43. data/spec/lib/appsignal/hooks/activejob_spec.rb +1 -1
  44. data/spec/lib/appsignal/hooks/redis_client_spec.rb +222 -0
  45. data/spec/lib/appsignal/hooks/redis_spec.rb +98 -76
  46. data/spec/lib/appsignal/hooks_spec.rb +4 -4
  47. data/spec/lib/appsignal/integrations/railtie_spec.rb +2 -2
  48. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +3 -3
  49. data/spec/lib/appsignal/integrations/sinatra_spec.rb +2 -2
  50. data/spec/lib/appsignal/minutely_spec.rb +2 -2
  51. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +1 -1
  52. data/spec/lib/appsignal/transaction_spec.rb +4 -4
  53. data/spec/lib/appsignal_spec.rb +34 -32
  54. data/spec/spec_helper.rb +1 -1
  55. data/spec/support/fixtures/projects/valid/config/appsignal.yml +3 -3
  56. data/spec/support/helpers/config_helpers.rb +6 -2
  57. data/spec/support/helpers/dependency_helper.rb +9 -1
  58. data/spec/support/helpers/log_helpers.rb +2 -2
  59. metadata +8 -3
data/lib/appsignal.rb CHANGED
@@ -46,7 +46,11 @@ module Appsignal
46
46
  # @see extension_loaded?
47
47
  attr_accessor :extension_loaded
48
48
  # @!attribute [rw] logger
49
- # Accessor for the AppSignal logger.
49
+ # Accessor for the internal AppSignal logger.
50
+ #
51
+ # Not to be confused with our logging feature.
52
+ # This is part of our private internal API. Do not call this method
53
+ # directly.
50
54
  #
51
55
  # If no logger has been set, it will return a "in memory logger", using
52
56
  # `in_memory_log`. Once AppSignal is started (using {.start}) the
@@ -57,7 +61,7 @@ module Appsignal
57
61
  # @api private
58
62
  # @return [Logger]
59
63
  # @see start_logger
60
- attr_writer :logger
64
+ attr_writer :internal_logger
61
65
 
62
66
  # @api private
63
67
  def testing?
@@ -91,11 +95,11 @@ module Appsignal
91
95
  # @since 0.7.0
92
96
  def start
93
97
  unless extension_loaded?
94
- logger.info("Not starting appsignal, extension is not loaded")
98
+ internal_logger.info("Not starting appsignal, extension is not loaded")
95
99
  return
96
100
  end
97
101
 
98
- logger.debug("Starting appsignal")
102
+ internal_logger.debug("Starting appsignal")
99
103
 
100
104
  @config ||= Config.new(
101
105
  Dir.pwd,
@@ -103,9 +107,9 @@ module Appsignal
103
107
  )
104
108
 
105
109
  if config.valid?
106
- logger.level = config.log_level
110
+ internal_logger.level = config.log_level
107
111
  if config.active?
108
- logger.info "Starting AppSignal #{Appsignal::VERSION} " \
112
+ internal_logger.info "Starting AppSignal #{Appsignal::VERSION} " \
109
113
  "(#{$PROGRAM_NAME}, Ruby #{RUBY_VERSION}, #{RUBY_PLATFORM})"
110
114
  config.write_to_environment
111
115
  Appsignal::Extension.start
@@ -120,10 +124,10 @@ module Appsignal
120
124
 
121
125
  collect_environment_metadata
122
126
  else
123
- logger.info("Not starting, not active for #{config.env}")
127
+ internal_logger.info("Not starting, not active for #{config.env}")
124
128
  end
125
129
  else
126
- logger.error("Not starting, no valid config for this environment")
130
+ internal_logger.error("Not starting, no valid config for this environment")
127
131
  end
128
132
  end
129
133
 
@@ -143,9 +147,9 @@ module Appsignal
143
147
  # @since 1.0.0
144
148
  def stop(called_by = nil)
145
149
  if called_by
146
- logger.debug("Stopping appsignal (#{called_by})")
150
+ internal_logger.debug("Stopping appsignal (#{called_by})")
147
151
  else
148
- logger.debug("Stopping appsignal")
152
+ internal_logger.debug("Stopping appsignal")
149
153
  end
150
154
  Appsignal::Extension.stop
151
155
  end
@@ -154,7 +158,7 @@ module Appsignal
154
158
  return unless active?
155
159
 
156
160
  Appsignal.start_logger
157
- logger.debug("Forked process, resubscribing and restarting extension")
161
+ internal_logger.debug("Forked process, resubscribing and restarting extension")
158
162
  Appsignal::Extension.start
159
163
  end
160
164
 
@@ -162,7 +166,8 @@ module Appsignal
162
166
  Appsignal::Extension.get_server_state(key)
163
167
  end
164
168
 
165
- # In memory logger used before any logger is started with {.start_logger}.
169
+ # In memory internal logger used before any internal logger is started with
170
+ # {.start_logger}.
166
171
  #
167
172
  # The contents of this logger are flushed to the logger in {.start_logger}.
168
173
  #
@@ -176,11 +181,12 @@ module Appsignal
176
181
  end
177
182
  end
178
183
 
179
- def logger
180
- @logger ||= Appsignal::Utils::IntegrationLogger.new(in_memory_log).tap do |l|
181
- l.level = ::Logger::INFO
182
- l.formatter = log_formatter("appsignal")
183
- end
184
+ def internal_logger
185
+ @internal_logger ||=
186
+ Appsignal::Utils::IntegrationLogger.new(in_memory_log).tap do |l|
187
+ l.level = ::Logger::INFO
188
+ l.formatter = log_formatter("appsignal")
189
+ end
184
190
  end
185
191
 
186
192
  # @api private
@@ -192,7 +198,7 @@ module Appsignal
192
198
  end
193
199
  end
194
200
 
195
- # Start the AppSignal logger.
201
+ # Start the AppSignal internal logger.
196
202
  #
197
203
  # Sets the log level and sets the logger. Uses a file-based logger or the
198
204
  # STDOUT-based logger. See the `:log` configuration option.
@@ -201,18 +207,18 @@ module Appsignal
201
207
  # @since 0.7.0
202
208
  def start_logger
203
209
  if config && config[:log] == "file" && config.log_file_path
204
- start_file_logger(config.log_file_path)
210
+ start_internal_file_logger(config.log_file_path)
205
211
  else
206
- start_stdout_logger
212
+ start_internal_stdout_logger
207
213
  end
208
214
 
209
- logger.level =
215
+ internal_logger.level =
210
216
  if config
211
217
  config.log_level
212
218
  else
213
219
  Appsignal::Config::DEFAULT_LOG_LEVEL
214
220
  end
215
- logger << @in_memory_log.string if @in_memory_log
221
+ internal_logger << @in_memory_log.string if @in_memory_log
216
222
  end
217
223
 
218
224
  # Returns if the C-extension was loaded properly.
@@ -255,18 +261,18 @@ module Appsignal
255
261
 
256
262
  private
257
263
 
258
- def start_stdout_logger
259
- @logger = Appsignal::Utils::IntegrationLogger.new($stdout)
260
- logger.formatter = log_formatter("appsignal")
264
+ def start_internal_stdout_logger
265
+ @internal_logger = Appsignal::Utils::IntegrationLogger.new($stdout)
266
+ internal_logger.formatter = log_formatter("appsignal")
261
267
  end
262
268
 
263
- def start_file_logger(path)
264
- @logger = Appsignal::Utils::IntegrationLogger.new(path)
265
- logger.formatter = log_formatter
269
+ def start_internal_file_logger(path)
270
+ @internal_logger = Appsignal::Utils::IntegrationLogger.new(path)
271
+ internal_logger.formatter = log_formatter
266
272
  rescue SystemCallError => error
267
- start_stdout_logger
268
- logger.warn "Unable to start logger with log path '#{path}'."
269
- logger.warn error
273
+ start_internal_stdout_logger
274
+ internal_logger.warn "Unable to start internal logger with log path '#{path}'."
275
+ internal_logger.warn error
270
276
  end
271
277
 
272
278
  def collect_environment_metadata
@@ -265,7 +265,7 @@ describe Appsignal::Config do
265
265
 
266
266
  context "with an overriden config file" do
267
267
  let(:config) do
268
- project_fixture_config("production", {}, Appsignal.logger,
268
+ project_fixture_config("production", {}, Appsignal.internal_logger,
269
269
  File.join(project_fixture_path, "config", "appsignal.yml"))
270
270
  end
271
271
 
@@ -276,7 +276,7 @@ describe Appsignal::Config do
276
276
 
277
277
  context "with an invalid overriden config file" do
278
278
  let(:config) do
279
- project_fixture_config("production", {}, Appsignal.logger,
279
+ project_fixture_config("production", {}, Appsignal.internal_logger,
280
280
  File.join(project_fixture_path, "config", "missing.yml"))
281
281
  end
282
282
 
@@ -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
@@ -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