appsignal 3.5.3 → 3.5.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.semaphore/semaphore.yml +180 -14
  3. data/CHANGELOG.md +36 -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 +25 -6
  14. data/lib/appsignal/cli/diagnose.rb +1 -1
  15. data/lib/appsignal/config.rb +9 -4
  16. data/lib/appsignal/environment.rb +24 -13
  17. data/lib/appsignal/event_formatter.rb +1 -1
  18. data/lib/appsignal/extension/jruby.rb +4 -17
  19. data/lib/appsignal/extension.rb +1 -1
  20. data/lib/appsignal/helpers/instrumentation.rb +7 -7
  21. data/lib/appsignal/helpers/metrics.rb +15 -13
  22. data/lib/appsignal/hooks/redis.rb +1 -0
  23. data/lib/appsignal/hooks/redis_client.rb +27 -0
  24. data/lib/appsignal/hooks.rb +3 -2
  25. data/lib/appsignal/integrations/hanami.rb +1 -1
  26. data/lib/appsignal/integrations/padrino.rb +1 -1
  27. data/lib/appsignal/integrations/railtie.rb +1 -1
  28. data/lib/appsignal/integrations/redis_client.rb +20 -0
  29. data/lib/appsignal/integrations/sidekiq.rb +1 -1
  30. data/lib/appsignal/integrations/sinatra.rb +1 -1
  31. data/lib/appsignal/minutely.rb +4 -4
  32. data/lib/appsignal/probes/gvl.rb +1 -1
  33. data/lib/appsignal/probes/helpers.rb +1 -1
  34. data/lib/appsignal/probes/mri.rb +1 -1
  35. data/lib/appsignal/probes/sidekiq.rb +5 -5
  36. data/lib/appsignal/rack/generic_instrumentation.rb +1 -1
  37. data/lib/appsignal/rack/rails_instrumentation.rb +2 -2
  38. data/lib/appsignal/rack/sinatra_instrumentation.rb +2 -2
  39. data/lib/appsignal/rack/streaming_listener.rb +1 -1
  40. data/lib/appsignal/span.rb +2 -2
  41. data/lib/appsignal/transaction.rb +11 -11
  42. data/lib/appsignal/utils/deprecation_message.rb +2 -2
  43. data/lib/appsignal/version.rb +1 -1
  44. data/lib/appsignal.rb +37 -31
  45. data/spec/lib/appsignal/cli/diagnose_spec.rb +17 -12
  46. data/spec/lib/appsignal/config_spec.rb +2 -2
  47. data/spec/lib/appsignal/hooks/activejob_spec.rb +1 -1
  48. data/spec/lib/appsignal/hooks/redis_client_spec.rb +222 -0
  49. data/spec/lib/appsignal/hooks/redis_spec.rb +98 -76
  50. data/spec/lib/appsignal/hooks_spec.rb +4 -4
  51. data/spec/lib/appsignal/integrations/railtie_spec.rb +2 -2
  52. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +3 -3
  53. data/spec/lib/appsignal/integrations/sinatra_spec.rb +2 -2
  54. data/spec/lib/appsignal/minutely_spec.rb +2 -2
  55. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +1 -1
  56. data/spec/lib/appsignal/transaction_spec.rb +4 -4
  57. data/spec/lib/appsignal_spec.rb +62 -60
  58. data/spec/spec_helper.rb +1 -1
  59. data/spec/support/helpers/config_helpers.rb +6 -2
  60. data/spec/support/helpers/dependency_helper.rb +9 -1
  61. data/spec/support/helpers/log_helpers.rb +2 -2
  62. metadata +7 -2
@@ -7,7 +7,7 @@ module Appsignal
7
7
  module Rack
8
8
  class GenericInstrumentation
9
9
  def initialize(app, options = {})
10
- Appsignal.logger.debug "Initializing Appsignal::Rack::GenericInstrumentation"
10
+ Appsignal.internal_logger.debug "Initializing Appsignal::Rack::GenericInstrumentation"
11
11
  @app = app
12
12
  @options = options
13
13
  end
@@ -7,7 +7,7 @@ module Appsignal
7
7
  module Rack
8
8
  class RailsInstrumentation
9
9
  def initialize(app, options = {})
10
- Appsignal.logger.debug "Initializing Appsignal::Rack::RailsInstrumentation"
10
+ Appsignal.internal_logger.debug "Initializing Appsignal::Rack::RailsInstrumentation"
11
11
  @app = app
12
12
  @options = options
13
13
  end
@@ -43,7 +43,7 @@ module Appsignal
43
43
  begin
44
44
  transaction.set_metadata("method", request.request_method)
45
45
  rescue => error
46
- Appsignal.logger.error("Unable to report HTTP request method: '#{error}'")
46
+ Appsignal.internal_logger.error("Unable to report HTTP request method: '#{error}'")
47
47
  end
48
48
  Appsignal::Transaction.complete_current!
49
49
  end
@@ -15,7 +15,7 @@ module Appsignal
15
15
  def initialize(app, options = {})
16
16
  @app = app
17
17
  @options = options
18
- Appsignal.logger.warn "Please remove Appsignal::Rack::SinatraInstrumentation " \
18
+ Appsignal.internal_logger.warn "Please remove Appsignal::Rack::SinatraInstrumentation " \
19
19
  "from your Sinatra::Base class. This is no longer needed."
20
20
  end
21
21
 
@@ -32,7 +32,7 @@ module Appsignal
32
32
  attr_reader :raise_errors_on
33
33
 
34
34
  def initialize(app, options = {})
35
- Appsignal.logger.debug "Initializing Appsignal::Rack::SinatraBaseInstrumentation"
35
+ Appsignal.internal_logger.debug "Initializing Appsignal::Rack::SinatraBaseInstrumentation"
36
36
  @app = app
37
37
  @options = options
38
38
  @raise_errors_on = raise_errors?(@app)
@@ -7,7 +7,7 @@ module Appsignal
7
7
  # @api private
8
8
  class StreamingListener
9
9
  def initialize(app, options = {})
10
- Appsignal.logger.debug "Initializing Appsignal::Rack::StreamingListener"
10
+ Appsignal.internal_logger.debug "Initializing Appsignal::Rack::StreamingListener"
11
11
  @app = app
12
12
  @options = options
13
13
  end
@@ -16,8 +16,8 @@ module Appsignal
16
16
 
17
17
  def add_error(error)
18
18
  unless error.is_a?(Exception)
19
- Appsignal.logger.error "Appsignal::Span#add_error: Cannot add error. " \
20
- "The given value is not an exception: #{error.inspect}"
19
+ Appsignal.internal_logger.error "Appsignal::Span#add_error: Cannot " \
20
+ "add error. The given value is not an exception: #{error.inspect}"
21
21
  return
22
22
  end
23
23
  return unless error
@@ -26,7 +26,7 @@ module Appsignal
26
26
  Appsignal::Transaction.new(id, namespace, request, options)
27
27
  else
28
28
  # Otherwise, log the issue about trying to start another transaction
29
- Appsignal.logger.warn_once_then_debug(
29
+ Appsignal.internal_logger.warn_once_then_debug(
30
30
  :transaction_id,
31
31
  "Trying to start new transaction with id " \
32
32
  "'#{id}', but a transaction with id '#{current.transaction_id}' " \
@@ -59,7 +59,7 @@ module Appsignal
59
59
  def complete_current!
60
60
  current.complete
61
61
  rescue => e
62
- Appsignal.logger.error(
62
+ Appsignal.internal_logger.error(
63
63
  "Failed to complete transaction ##{current.transaction_id}. #{e.message}"
64
64
  )
65
65
  ensure
@@ -114,7 +114,7 @@ module Appsignal
114
114
 
115
115
  def complete
116
116
  if discarded?
117
- Appsignal.logger.debug "Skipping transaction '#{transaction_id}' " \
117
+ Appsignal.internal_logger.debug "Skipping transaction '#{transaction_id}' " \
118
118
  "because it was manually discarded."
119
119
  return
120
120
  end
@@ -188,7 +188,7 @@ module Appsignal
188
188
  # Breadcrumb reference
189
189
  def add_breadcrumb(category, action, message = "", metadata = {}, time = Time.now.utc)
190
190
  unless metadata.is_a? Hash
191
- Appsignal.logger.error "add_breadcrumb: Cannot add breadcrumb. " \
191
+ Appsignal.internal_logger.error "add_breadcrumb: Cannot add breadcrumb. " \
192
192
  "The given metadata argument is not a Hash."
193
193
  return
194
194
  end
@@ -287,7 +287,7 @@ module Appsignal
287
287
 
288
288
  @ext.set_queue_start(start)
289
289
  rescue RangeError
290
- Appsignal.logger.warn("Queue start value #{start} is too big")
290
+ Appsignal.internal_logger.warn("Queue start value #{start} is too big")
291
291
  end
292
292
 
293
293
  # Set the queue time based on the HTTP header or `:queue_start` env key
@@ -324,7 +324,7 @@ module Appsignal
324
324
  return unless key && data
325
325
 
326
326
  if !data.is_a?(Array) && !data.is_a?(Hash)
327
- Appsignal.logger.error(
327
+ Appsignal.internal_logger.error(
328
328
  "Invalid sample data for '#{key}'. Value is not an Array or Hash: '#{data.inspect}'"
329
329
  )
330
330
  return
@@ -337,11 +337,11 @@ module Appsignal
337
337
  rescue RuntimeError => e
338
338
  begin
339
339
  inspected_data = data.inspect
340
- Appsignal.logger.error(
340
+ Appsignal.internal_logger.error(
341
341
  "Error generating data (#{e.class}: #{e.message}) for '#{inspected_data}'"
342
342
  )
343
343
  rescue => e
344
- Appsignal.logger.error(
344
+ Appsignal.internal_logger.error(
345
345
  "Error generating data (#{e.class}: #{e.message}). Can't inspect data."
346
346
  )
347
347
  end
@@ -362,7 +362,7 @@ module Appsignal
362
362
 
363
363
  def set_error(error)
364
364
  unless error.is_a?(Exception)
365
- Appsignal.logger.error "Appsignal::Transaction#set_error: Cannot set error. " \
365
+ Appsignal.internal_logger.error "Appsignal::Transaction#set_error: Cannot set error. " \
366
366
  "The given value is not an exception: #{error.inspect}"
367
367
  return
368
368
  end
@@ -385,7 +385,7 @@ module Appsignal
385
385
  break unless error
386
386
 
387
387
  if causes.length >= ERROR_CAUSES_LIMIT
388
- Appsignal.logger.debug "Appsignal::Transaction#set_error: Error has more " \
388
+ Appsignal.internal_logger.debug "Appsignal::Transaction#set_error: Error has more " \
389
389
  "than #{ERROR_CAUSES_LIMIT} error causes. Only the first #{ERROR_CAUSES_LIMIT} " \
390
390
  "will be reported."
391
391
  root_cause_missing = true
@@ -529,7 +529,7 @@ module Appsignal
529
529
  request.send options[:params_method]
530
530
  rescue => e
531
531
  # Getting params from the request has been know to fail.
532
- Appsignal.logger.debug "Exception while getting params: #{e}"
532
+ Appsignal.internal_logger.debug "Exception while getting params: #{e}"
533
533
  nil
534
534
  end
535
535
  end
@@ -3,12 +3,12 @@
3
3
  module Appsignal
4
4
  module Utils
5
5
  module DeprecationMessage
6
- def self.message(message, logger = Appsignal.logger)
6
+ def self.message(message, logger = Appsignal.internal_logger)
7
7
  Kernel.warn "appsignal WARNING: #{message}"
8
8
  logger.warn message
9
9
  end
10
10
 
11
- def deprecation_message(message, logger = Appsignal.logger)
11
+ def deprecation_message(message, logger = Appsignal.internal_logger)
12
12
  Appsignal::Utils::DeprecationMessage.message(message, logger)
13
13
  end
14
14
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Appsignal
4
- VERSION = "3.5.3"
4
+ VERSION = "3.5.5"
5
5
  end
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
@@ -253,15 +253,17 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
253
253
  it "adds the installation report to the diagnostics report" do
254
254
  run
255
255
  jruby = Appsignal::System.jruby?
256
+ language = {
257
+ "name" => "ruby",
258
+ "version" => "#{RUBY_VERSION}#{"-p#{rbconfig["PATCHLEVEL"]}" unless jruby}",
259
+ "implementation" => jruby ? "jruby" : "ruby"
260
+ }
261
+ language["implementation_version"] = JRUBY_VERSION if jruby
256
262
  expect(received_report["installation"]).to match(
257
263
  "result" => {
258
264
  "status" => "success"
259
265
  },
260
- "language" => {
261
- "name" => "ruby",
262
- "version" => "#{rbconfig["RUBY_PROGRAM_VERSION"]}-p#{rbconfig["PATCHLEVEL"]}",
263
- "implementation" => jruby ? "jruby" : "ruby"
264
- },
266
+ "language" => language,
265
267
  "download" => {
266
268
  "download_url" => kind_of(String),
267
269
  "checksum" => "verified",
@@ -1357,6 +1359,7 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
1357
1359
  shared_examples "diagnose file" do |shared_example_options|
1358
1360
  let(:parent_directory) { File.join(tmp_dir, "diagnose_files") }
1359
1361
  let(:file_path) { File.join(parent_directory, filename) }
1362
+ let(:path_key) { filename }
1360
1363
  before { FileUtils.mkdir_p File.dirname(file_path) }
1361
1364
  after { FileUtils.rm_rf parent_directory }
1362
1365
 
@@ -1387,7 +1390,7 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
1387
1390
  end
1388
1391
 
1389
1392
  it "transmits file data in report" do
1390
- expect(received_report["paths"][filename]).to match(
1393
+ expect(received_report["paths"][path_key]).to match(
1391
1394
  "path" => file_path,
1392
1395
  "exists" => true,
1393
1396
  "type" => "file",
@@ -1418,7 +1421,7 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
1418
1421
  end
1419
1422
 
1420
1423
  it "transmits file data in report" do
1421
- expect(received_report["paths"][filename]).to eq(
1424
+ expect(received_report["paths"][path_key]).to eq(
1422
1425
  "path" => file_path,
1423
1426
  "exists" => false
1424
1427
  )
@@ -1439,20 +1442,22 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
1439
1442
  end
1440
1443
 
1441
1444
  it "transmits file data in report" do
1442
- expect(received_report["paths"][filename]).to include(
1445
+ expect(received_report["paths"][path_key]).to include(
1443
1446
  "read_error" => "Errno::ESPIPE: Illegal seek"
1444
1447
  )
1445
1448
  end
1446
1449
  end
1447
1450
  end
1448
1451
 
1449
- describe "mkmf.log" do
1452
+ describe "ext/mkmf.log" do
1450
1453
  it_behaves_like "diagnose file" do
1451
- let(:filename) { File.join("ext", "mkmf.log") }
1454
+ let(:filename) { "mkmf.log" }
1455
+ let(:path_key) { "ext/mkmf.log" }
1452
1456
  before do
1453
- expect_any_instance_of(Appsignal::CLI::Diagnose::Paths).to receive(:gem_path)
1457
+ expect_any_instance_of(Appsignal::CLI::Diagnose::Paths)
1458
+ .to receive(:makefile_install_log_path)
1454
1459
  .at_least(:once)
1455
- .and_return(parent_directory)
1460
+ .and_return(File.join(parent_directory, filename))
1456
1461
  end
1457
1462
  end
1458
1463
 
@@ -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