appsignal 3.9.1-java → 3.9.3-java

Sign up to get free protection for your applications and to get access to all the features.
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