appsignal 3.9.1-java → 3.9.3-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +3135 -0
  3. data/.rubocop.yml +28 -20
  4. data/.rubocop_todo.yml +7 -33
  5. data/CHANGELOG.md +58 -0
  6. data/Rakefile +79 -64
  7. data/appsignal.gemspec +1 -1
  8. data/build_matrix.yml +109 -179
  9. data/ext/base.rb +1 -1
  10. data/gemfiles/hanami-2.1.gemfile +7 -0
  11. data/lib/appsignal/cli/diagnose.rb +1 -1
  12. data/lib/appsignal/config.rb +1 -1
  13. data/lib/appsignal/demo.rb +0 -1
  14. data/lib/appsignal/environment.rb +5 -1
  15. data/lib/appsignal/extension/jruby.rb +1 -1
  16. data/lib/appsignal/helpers/instrumentation.rb +3 -3
  17. data/lib/appsignal/hooks/active_job.rb +2 -1
  18. data/lib/appsignal/integrations/action_cable.rb +1 -1
  19. data/lib/appsignal/integrations/grape.rb +19 -47
  20. data/lib/appsignal/integrations/hanami.rb +27 -41
  21. data/lib/appsignal/integrations/padrino.rb +46 -43
  22. data/lib/appsignal/integrations/railtie.rb +1 -4
  23. data/lib/appsignal/integrations/resque.rb +1 -1
  24. data/lib/appsignal/integrations/sidekiq.rb +2 -4
  25. data/lib/appsignal/integrations/sinatra.rb +7 -2
  26. data/lib/appsignal/probes/gvl.rb +24 -2
  27. data/lib/appsignal/probes/sidekiq.rb +1 -1
  28. data/lib/appsignal/probes.rb +1 -1
  29. data/lib/appsignal/rack/abstract_middleware.rb +62 -28
  30. data/lib/appsignal/rack/event_handler.rb +37 -26
  31. data/lib/appsignal/rack/grape_middleware.rb +40 -0
  32. data/lib/appsignal/rack/hanami_middleware.rb +20 -0
  33. data/lib/appsignal/rack/rails_instrumentation.rb +14 -56
  34. data/lib/appsignal/utils/integration_memory_logger.rb +78 -0
  35. data/lib/appsignal/utils.rb +1 -0
  36. data/lib/appsignal/version.rb +1 -1
  37. data/lib/appsignal.rb +34 -33
  38. data/spec/.rubocop.yml +1 -1
  39. data/spec/lib/appsignal/cli/diagnose_spec.rb +1 -1
  40. data/spec/lib/appsignal/cli/install_spec.rb +3 -3
  41. data/spec/lib/appsignal/config_spec.rb +7 -5
  42. data/spec/lib/appsignal/demo_spec.rb +38 -41
  43. data/spec/lib/appsignal/hooks/action_cable_spec.rb +86 -167
  44. data/spec/lib/appsignal/hooks/active_support_notifications/finish_with_state_shared_examples.rb +8 -20
  45. data/spec/lib/appsignal/hooks/active_support_notifications/instrument_shared_examples.rb +38 -84
  46. data/spec/lib/appsignal/hooks/active_support_notifications/start_finish_shared_examples.rb +16 -37
  47. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +4 -4
  48. data/spec/lib/appsignal/hooks/activejob_spec.rb +111 -200
  49. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +54 -91
  50. data/spec/lib/appsignal/hooks/dry_monitor_spec.rb +14 -32
  51. data/spec/lib/appsignal/hooks/excon_spec.rb +8 -12
  52. data/spec/lib/appsignal/hooks/net_http_spec.rb +7 -42
  53. data/spec/lib/appsignal/hooks/rake_spec.rb +9 -19
  54. data/spec/lib/appsignal/hooks/redis_client_spec.rb +18 -30
  55. data/spec/lib/appsignal/hooks/redis_spec.rb +10 -16
  56. data/spec/lib/appsignal/hooks/resque_spec.rb +42 -62
  57. data/spec/lib/appsignal/hooks/shoryuken_spec.rb +33 -74
  58. data/spec/lib/appsignal/integrations/hanami_spec.rb +126 -64
  59. data/spec/lib/appsignal/integrations/http_spec.rb +12 -20
  60. data/spec/lib/appsignal/integrations/net_http_spec.rb +33 -0
  61. data/spec/lib/appsignal/integrations/object_spec.rb +29 -36
  62. data/spec/lib/appsignal/integrations/padrino_spec.rb +47 -70
  63. data/spec/lib/appsignal/integrations/que_spec.rb +43 -70
  64. data/spec/lib/appsignal/integrations/railtie_spec.rb +26 -67
  65. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +86 -160
  66. data/spec/lib/appsignal/integrations/sinatra_spec.rb +8 -3
  67. data/spec/lib/appsignal/integrations/webmachine_spec.rb +28 -39
  68. data/spec/lib/appsignal/probes/gvl_spec.rb +80 -3
  69. data/spec/lib/appsignal/probes_spec.rb +7 -4
  70. data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +215 -106
  71. data/spec/lib/appsignal/rack/event_handler_spec.rb +151 -69
  72. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +2 -12
  73. data/spec/lib/appsignal/rack/grape_middleware_spec.rb +234 -0
  74. data/spec/lib/appsignal/rack/hanami_middleware_spec.rb +36 -0
  75. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +67 -131
  76. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +36 -44
  77. data/spec/lib/appsignal/rack/streaming_listener_spec.rb +68 -86
  78. data/spec/lib/appsignal/transaction_spec.rb +79 -93
  79. data/spec/lib/appsignal/utils/integration_memory_logger_spec.rb +163 -0
  80. data/spec/lib/appsignal_spec.rb +363 -342
  81. data/spec/support/hanami/hanami_app.rb +1 -3
  82. data/spec/support/helpers/dependency_helper.rb +6 -1
  83. data/spec/support/helpers/std_streams_helper.rb +1 -1
  84. data/spec/support/helpers/transaction_helpers.rb +8 -0
  85. data/spec/support/matchers/transaction.rb +185 -0
  86. data/spec/support/mocks/dummy_app.rb +20 -0
  87. data/spec/support/shared_examples/instrument.rb +17 -12
  88. data/spec/support/testing.rb +18 -9
  89. metadata +17 -10
  90. data/.semaphore/semaphore.yml +0 -2347
  91. data/script/lint_git +0 -22
  92. data/spec/lib/appsignal/integrations/grape_spec.rb +0 -239
  93. data/spec/support/matchers/be_completed.rb +0 -5
  94. /data/gemfiles/{hanami.gemfile → hanami-2.0.gemfile} +0 -0
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "logger"
4
+
5
+ module Appsignal
6
+ module Utils
7
+ # @api private
8
+ class IntegrationMemoryLogger
9
+ LEVELS = {
10
+ Logger::DEBUG => :DEBUG,
11
+ Logger::INFO => :INFO,
12
+ Logger::WARN => :WARN,
13
+ Logger::ERROR => :ERROR,
14
+ Logger::FATAL => :FATAL,
15
+ Logger::UNKNOWN => :UNKNOWN
16
+ }.freeze
17
+
18
+ attr_accessor :formatter, :level
19
+
20
+ def add(severity, message, _progname = nil)
21
+ message = formatter.call(severity, Time.now, nil, message) if formatter
22
+ messages[severity] << message
23
+ end
24
+ alias log add
25
+
26
+ def debug(message)
27
+ add(:DEBUG, message)
28
+ end
29
+
30
+ def info(message)
31
+ add(:INFO, message)
32
+ end
33
+
34
+ def warn(message)
35
+ add(:WARN, message)
36
+ end
37
+
38
+ def seen_keys
39
+ @seen_keys ||= Set.new
40
+ end
41
+
42
+ def warn_once_then_debug(key, message)
43
+ if seen_keys.add?(key).nil?
44
+ debug message
45
+ else
46
+ warn message
47
+ end
48
+ end
49
+
50
+ def error(message)
51
+ add(:ERROR, message)
52
+ end
53
+
54
+ def fatal(message)
55
+ add(:FATAL, message)
56
+ end
57
+
58
+ def unknown(message)
59
+ add(:UNKNOWN, message)
60
+ end
61
+
62
+ def clear
63
+ messages.clear
64
+ end
65
+
66
+ def messages
67
+ @messages ||= Hash.new { |hash, key| hash[key] = [] }
68
+ end
69
+
70
+ def messages_for_level(level)
71
+ levels = LEVELS.select { |log_level| log_level >= level }.values
72
+ messages
73
+ .select { |log_level| levels.include?(log_level) }
74
+ .flat_map { |_level, message| message }
75
+ end
76
+ end
77
+ end
78
+ end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "appsignal/utils/integration_memory_logger"
3
4
  require "appsignal/utils/stdout_and_logger_message"
4
5
  require "appsignal/utils/data"
5
6
  require "appsignal/utils/hash_sanitizer"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Appsignal
4
- VERSION = "3.9.1"
4
+ VERSION = "3.9.3"
5
5
  end
data/lib/appsignal.rb CHANGED
@@ -55,14 +55,15 @@ module Appsignal
55
55
  # directly.
56
56
  #
57
57
  # If no logger has been set, it will return a "in memory logger", using
58
- # `in_memory_log`. Once AppSignal is started (using {.start}) the
59
- # contents of the "in memory logger" is written to the new logger.
58
+ # {Utils::IntegrationMemoryLogger}. Once AppSignal is started (using
59
+ # {.start}) the contents of the "in memory logger" is written to the new
60
+ # logger.
60
61
  #
61
62
  # @note some classes may have options to set custom loggers. Their
62
63
  # defaults are pointed to this attribute.
63
64
  # @api private
64
65
  # @return [Logger]
65
- # @see start_logger
66
+ # @see start
66
67
  attr_writer :internal_logger
67
68
 
68
69
  # @api private
@@ -84,8 +85,6 @@ module Appsignal
84
85
  # AppSignal](https://docs.appsignal.com/ruby/instrumentation/integrating-appsignal.html)
85
86
  # guide.
86
87
  #
87
- # To start the logger see {.start_logger}.
88
- #
89
88
  # @example
90
89
  # Appsignal.start
91
90
  #
@@ -108,8 +107,9 @@ module Appsignal
108
107
  ENV["APPSIGNAL_APP_ENV"] || ENV["RAILS_ENV"] || ENV.fetch("RACK_ENV", nil)
109
108
  )
110
109
 
110
+ _start_logger
111
+
111
112
  if config.valid?
112
- internal_logger.level = config.log_level
113
113
  if config.active?
114
114
  internal_logger.info "Starting AppSignal #{Appsignal::VERSION} " \
115
115
  "(#{$PROGRAM_NAME}, Ruby #{RUBY_VERSION}, #{RUBY_PLATFORM})"
@@ -160,7 +160,7 @@ module Appsignal
160
160
  def forked
161
161
  return unless active?
162
162
 
163
- Appsignal.start_logger
163
+ Appsignal._start_logger
164
164
  internal_logger.debug("Forked process, resubscribing and restarting extension")
165
165
  Appsignal::Extension.start
166
166
  end
@@ -169,27 +169,15 @@ module Appsignal
169
169
  Appsignal::Extension.get_server_state(key)
170
170
  end
171
171
 
172
- # In memory internal logger used before any internal logger is started with
173
- # {.start_logger}.
174
- #
175
- # The contents of this logger are flushed to the logger in {.start_logger}.
176
- #
177
- # @api private
178
- # @return [StringIO]
179
- def in_memory_log
180
- if defined?(@in_memory_log) && @in_memory_log
181
- @in_memory_log
182
- else
183
- @in_memory_log = StringIO.new
184
- end
172
+ def in_memory_logger
173
+ @in_memory_logger ||=
174
+ Appsignal::Utils::IntegrationMemoryLogger.new.tap do |l|
175
+ l.formatter = log_formatter("appsignal")
176
+ end
185
177
  end
186
178
 
187
179
  def internal_logger
188
- @internal_logger ||=
189
- Appsignal::Utils::IntegrationLogger.new(in_memory_log).tap do |l|
190
- l.level = ::Logger::INFO
191
- l.formatter = log_formatter("appsignal")
192
- end
180
+ @internal_logger ||= in_memory_logger
193
181
  end
194
182
 
195
183
  # @api private
@@ -201,14 +189,26 @@ module Appsignal
201
189
  end
202
190
  end
203
191
 
192
+ # @deprecated Only {.start} has to be called.
193
+ # @return [void]
194
+ # @since 0.7.0
195
+ def start_logger
196
+ callers = caller
197
+ Appsignal::Utils::StdoutAndLoggerMessage.warning \
198
+ "Callng 'Appsignal.start_logger' is deprecated. " \
199
+ "The logger will be started when calling 'Appsignal.start'. " \
200
+ "Remove the 'Appsignal.start_logger' call in the following file to " \
201
+ "remove this message.\n#{callers.first}"
202
+ end
203
+
204
204
  # Start the AppSignal internal logger.
205
205
  #
206
206
  # Sets the log level and sets the logger. Uses a file-based logger or the
207
207
  # STDOUT-based logger. See the `:log` configuration option.
208
208
  #
209
+ # @api private
209
210
  # @return [void]
210
- # @since 0.7.0
211
- def start_logger
211
+ def _start_logger
212
212
  if config && config[:log] == "file" && config.log_file_path
213
213
  start_internal_file_logger(config.log_file_path)
214
214
  else
@@ -221,10 +221,11 @@ module Appsignal
221
221
  else
222
222
  Appsignal::Config::DEFAULT_LOG_LEVEL
223
223
  end
224
- return unless @in_memory_log
224
+ return unless @in_memory_logger
225
225
 
226
- internal_logger << @in_memory_log.string
227
- @in_memory_log = nil
226
+ messages = @in_memory_logger.messages_for_level(internal_logger.level)
227
+ internal_logger << messages.join
228
+ @in_memory_logger = nil
228
229
  end
229
230
 
230
231
  # Returns if the C-extension was loaded properly.
@@ -323,11 +324,11 @@ require "appsignal/hooks"
323
324
  require "appsignal/probes"
324
325
  require "appsignal/marker"
325
326
  require "appsignal/garbage_collection"
326
- require "appsignal/integrations/railtie" if defined?(::Rails)
327
- require "appsignal/transaction"
328
- require "appsignal/version"
329
327
  require "appsignal/rack/abstract_middleware"
330
328
  require "appsignal/rack/generic_instrumentation"
331
329
  require "appsignal/rack/event_handler"
330
+ require "appsignal/integrations/railtie" if defined?(::Rails)
331
+ require "appsignal/transaction"
332
+ require "appsignal/version"
332
333
  require "appsignal/transmitter"
333
334
  require "appsignal/heartbeat"
data/spec/.rubocop.yml CHANGED
@@ -3,5 +3,5 @@ inherit_from: ../.rubocop.yml
3
3
  Metrics/BlockLength:
4
4
  Enabled: false
5
5
 
6
- # Metrics/LineLength:
6
+ # Layout/LineLength:
7
7
  # Max: 100
@@ -1320,7 +1320,7 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
1320
1320
  end
1321
1321
 
1322
1322
  it "transmits path data in report" do
1323
- mode = ENV["RUNNING_IN_CI"] ? "40775" : "40755"
1323
+ mode = "40755"
1324
1324
  expect(received_report["paths"]["root_path"]).to eq(
1325
1325
  "path" => root_path,
1326
1326
  "exists" => true,
@@ -155,7 +155,7 @@ describe Appsignal::CLI::Install do
155
155
  end
156
156
 
157
157
  it "requires an application name" do
158
- expect(output.scan(/Enter application name:/).length).to eq(2)
158
+ expect(output.scan("Enter application name:").length).to eq(2)
159
159
  end
160
160
  end
161
161
 
@@ -184,7 +184,7 @@ describe Appsignal::CLI::Install do
184
184
  run
185
185
 
186
186
  expect(output).to_not include "Adding AppSignal integration to Capfile"
187
- expect(File.read(capfile).scan(/appsignal/).count).to eq(1)
187
+ expect(File.read(capfile).scan("appsignal").count).to eq(1)
188
188
  end
189
189
  end
190
190
 
@@ -351,7 +351,7 @@ describe Appsignal::CLI::Install do
351
351
  choose_environment_config
352
352
  run
353
353
 
354
- expect(output.scan(/Choose app's display name:/).length).to eq(2)
354
+ expect(output.scan("Choose app's display name:").length).to eq(2)
355
355
  end
356
356
 
357
357
  context "with configuration using environment variables" do
@@ -385,6 +385,8 @@ describe Appsignal::Config do
385
385
 
386
386
  context "without the selected env" do
387
387
  let(:config) { project_fixture_config("nonsense") }
388
+ let(:log_stream) { std_stream }
389
+ let(:log) { log_contents(log_stream) }
388
390
 
389
391
  it "is not valid or active" do
390
392
  expect(config.valid?).to be_falsy
@@ -392,11 +394,11 @@ describe Appsignal::Config do
392
394
  end
393
395
 
394
396
  it "logs an error" do
395
- expect_any_instance_of(Logger).to receive(:error).once
396
- .with("Not loading from config file: config for 'nonsense' not found")
397
- expect_any_instance_of(Logger).to receive(:error).once
398
- .with("Push API key not set after loading config")
399
- config
397
+ use_logger_with(log_stream) { config }
398
+ expect(log)
399
+ .to contains_log(:error, "Not loading from config file: config for 'nonsense' not found")
400
+ expect(log)
401
+ .to contains_log(:error, "Push API key not set after loading config")
400
402
  end
401
403
  end
402
404
  end
@@ -32,56 +32,53 @@ describe Appsignal::Demo do
32
32
  end
33
33
 
34
34
  describe ".create_example_error_request" do
35
- let!(:error_transaction) { http_request_transaction }
36
- let(:config) { project_fixture_config("production") }
37
- before do
38
- Appsignal.config = config
39
- expect(Appsignal::Transaction).to receive(:new).with(
40
- kind_of(String),
41
- Appsignal::Transaction::HTTP_REQUEST,
42
- kind_of(::Rack::Request),
43
- kind_of(Hash)
44
- ).and_return(error_transaction)
45
- end
46
- subject { described_class.send(:create_example_error_request) }
35
+ before { start_agent }
36
+ around { |example| keep_transactions { example.run } }
47
37
 
48
38
  it "sets an error" do
49
- expect(error_transaction).to receive(:set_error).with(kind_of(described_class::TestError))
50
- expect(error_transaction).to receive(:set_metadata).with("path", "/hello")
51
- expect(error_transaction).to receive(:set_metadata).with("method", "GET")
52
- expect(error_transaction).to receive(:set_metadata).with("demo_sample", "true")
53
- expect(error_transaction).to receive(:complete)
54
- subject
39
+ described_class.send(:create_example_error_request)
40
+
41
+ transaction = last_transaction
42
+ expect(transaction).to have_id
43
+ expect(transaction).to have_namespace(Appsignal::Transaction::HTTP_REQUEST)
44
+ expect(transaction).to have_action("DemoController#hello")
45
+ expect(transaction).to have_error(
46
+ "Appsignal::Demo::TestError",
47
+ "Hello world! This is an error used for demonstration purposes."
48
+ )
49
+ expect(transaction).to include_metadata(
50
+ "path" => "/hello",
51
+ "method" => "GET",
52
+ "demo_sample" => "true"
53
+ )
54
+ expect(transaction).to be_completed
55
55
  end
56
56
  end
57
57
 
58
58
  describe ".create_example_performance_request" do
59
- let!(:performance_transaction) { http_request_transaction }
60
- let(:config) { project_fixture_config("production") }
61
- before do
62
- Appsignal.config = config
63
- expect(Appsignal::Transaction).to receive(:new).with(
64
- kind_of(String),
65
- Appsignal::Transaction::HTTP_REQUEST,
66
- kind_of(::Rack::Request),
67
- kind_of(Hash)
68
- ).and_return(performance_transaction)
69
- end
70
- subject { described_class.send(:create_example_performance_request) }
59
+ before { start_agent }
60
+ around { |example| keep_transactions { example.run } }
71
61
 
72
62
  it "sends a performance sample" do
73
- expect(performance_transaction).to receive(:start_event)
74
- expect(performance_transaction).to receive(:finish_event).with(
75
- "action_view.render",
76
- "Render hello.html.erb",
77
- "<h1>Hello world!</h1>",
78
- Appsignal::EventFormatter::DEFAULT
63
+ described_class.send(:create_example_performance_request)
64
+
65
+ transaction = last_transaction
66
+ expect(transaction).to have_id
67
+ expect(transaction).to have_namespace(Appsignal::Transaction::HTTP_REQUEST)
68
+ expect(transaction).to have_action("DemoController#hello")
69
+ expect(transaction).to_not have_error
70
+ expect(transaction).to include_metadata(
71
+ "path" => "/hello",
72
+ "method" => "GET",
73
+ "demo_sample" => "true"
74
+ )
75
+ expect(transaction).to include_event(
76
+ "name" => "action_view.render",
77
+ "title" => "Render hello.html.erb",
78
+ "body" => "<h1>Hello world!</h1>",
79
+ "body_format" => Appsignal::EventFormatter::DEFAULT
79
80
  )
80
- expect(performance_transaction).to receive(:set_metadata).with("path", "/hello")
81
- expect(performance_transaction).to receive(:set_metadata).with("method", "GET")
82
- expect(performance_transaction).to receive(:set_metadata).with("demo_sample", "true")
83
- expect(performance_transaction).to receive(:complete)
84
- subject
81
+ expect(transaction).to be_completed
85
82
  end
86
83
  end
87
84
  end