appsignal 3.4.0-java → 3.4.2-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 (142) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +63 -21
  3. data/.rubocop_todo.yml +68 -54
  4. data/.semaphore/semaphore.yml +11 -11
  5. data/CHANGELOG.md +51 -0
  6. data/Rakefile +15 -99
  7. data/appsignal.gemspec +3 -4
  8. data/bin/appsignal +4 -2
  9. data/build_matrix.yml +4 -4
  10. data/ext/._appsignal-agent +0 -0
  11. data/ext/Rakefile +22 -21
  12. data/ext/agent.rb +29 -27
  13. data/ext/base.rb +14 -17
  14. data/ext/extconf.rb +4 -1
  15. data/lib/appsignal/auth_check.rb +3 -3
  16. data/lib/appsignal/capistrano.rb +1 -1
  17. data/lib/appsignal/cli/demo.rb +5 -2
  18. data/lib/appsignal/cli/diagnose/paths.rb +4 -1
  19. data/lib/appsignal/cli/diagnose/utils.rb +7 -3
  20. data/lib/appsignal/cli/diagnose.rb +7 -5
  21. data/lib/appsignal/cli/helpers.rb +1 -4
  22. data/lib/appsignal/cli/install.rb +4 -10
  23. data/lib/appsignal/cli.rb +3 -2
  24. data/lib/appsignal/config.rb +106 -103
  25. data/lib/appsignal/demo.rb +2 -1
  26. data/lib/appsignal/environment.rb +2 -0
  27. data/lib/appsignal/event_formatter/action_view/render_formatter.rb +2 -1
  28. data/lib/appsignal/event_formatter/mongo_ruby_driver/query_formatter.rb +13 -13
  29. data/lib/appsignal/event_formatter.rb +5 -4
  30. data/lib/appsignal/extension/jruby.rb +11 -9
  31. data/lib/appsignal/extension.rb +1 -1
  32. data/lib/appsignal/helpers/instrumentation.rb +50 -35
  33. data/lib/appsignal/hooks/action_cable.rb +6 -4
  34. data/lib/appsignal/hooks/action_mailer.rb +2 -0
  35. data/lib/appsignal/hooks/active_job.rb +11 -10
  36. data/lib/appsignal/hooks/active_support_notifications.rb +3 -4
  37. data/lib/appsignal/hooks/data_mapper.rb +1 -1
  38. data/lib/appsignal/hooks/gvl.rb +3 -0
  39. data/lib/appsignal/hooks/http.rb +1 -1
  40. data/lib/appsignal/hooks/mri.rb +2 -0
  41. data/lib/appsignal/hooks/net_http.rb +1 -1
  42. data/lib/appsignal/hooks/que.rb +1 -1
  43. data/lib/appsignal/hooks/rake.rb +1 -1
  44. data/lib/appsignal/hooks/redis.rb +1 -1
  45. data/lib/appsignal/hooks/resque.rb +1 -1
  46. data/lib/appsignal/hooks/shoryuken.rb +2 -4
  47. data/lib/appsignal/hooks/sidekiq.rb +1 -1
  48. data/lib/appsignal/hooks/unicorn.rb +2 -2
  49. data/lib/appsignal/hooks/webmachine.rb +1 -1
  50. data/lib/appsignal/hooks.rb +2 -2
  51. data/lib/appsignal/integrations/active_support_notifications.rb +1 -1
  52. data/lib/appsignal/integrations/capistrano/appsignal.cap +6 -3
  53. data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +5 -4
  54. data/lib/appsignal/integrations/delayed_job_plugin.rb +3 -5
  55. data/lib/appsignal/integrations/grape.rb +1 -1
  56. data/lib/appsignal/integrations/hanami.rb +1 -1
  57. data/lib/appsignal/integrations/object.rb +2 -3
  58. data/lib/appsignal/integrations/padrino.rb +2 -4
  59. data/lib/appsignal/integrations/que.rb +6 -6
  60. data/lib/appsignal/integrations/railtie.rb +76 -0
  61. data/lib/appsignal/integrations/sidekiq.rb +9 -11
  62. data/lib/appsignal/integrations/sinatra.rb +1 -3
  63. data/lib/appsignal/integrations/webmachine.rb +4 -6
  64. data/lib/appsignal/logger.rb +31 -6
  65. data/lib/appsignal/marker.rb +4 -5
  66. data/lib/appsignal/minutely.rb +7 -7
  67. data/lib/appsignal/probes/gvl.rb +9 -4
  68. data/lib/appsignal/probes/helpers.rb +4 -6
  69. data/lib/appsignal/probes/mri.rb +7 -5
  70. data/lib/appsignal/probes/sidekiq.rb +3 -0
  71. data/lib/appsignal/probes.rb +2 -0
  72. data/lib/appsignal/rack/generic_instrumentation.rb +1 -5
  73. data/lib/appsignal/rack/sinatra_instrumentation.rb +3 -5
  74. data/lib/appsignal/rack/streaming_listener.rb +11 -13
  75. data/lib/appsignal/span.rb +5 -5
  76. data/lib/appsignal/system.rb +10 -11
  77. data/lib/appsignal/transaction.rb +49 -25
  78. data/lib/appsignal/transmitter.rb +4 -2
  79. data/lib/appsignal/utils/deprecation_message.rb +2 -0
  80. data/lib/appsignal/utils/hash_sanitizer.rb +1 -1
  81. data/lib/appsignal/utils/integration_logger.rb +5 -3
  82. data/lib/appsignal/utils/json.rb +1 -1
  83. data/lib/appsignal/utils/query_params_sanitizer.rb +1 -1
  84. data/lib/appsignal/version.rb +1 -1
  85. data/lib/appsignal.rb +5 -4
  86. data/lib/puma/plugin/appsignal.rb +16 -18
  87. data/script/lint_git +1 -1
  88. data/spec/lib/appsignal/capistrano2_spec.rb +6 -3
  89. data/spec/lib/appsignal/capistrano3_spec.rb +6 -3
  90. data/spec/lib/appsignal/cli/diagnose/utils_spec.rb +1 -3
  91. data/spec/lib/appsignal/cli/diagnose_spec.rb +33 -30
  92. data/spec/lib/appsignal/cli/install_spec.rb +5 -6
  93. data/spec/lib/appsignal/cli_spec.rb +1 -1
  94. data/spec/lib/appsignal/config_spec.rb +43 -37
  95. data/spec/lib/appsignal/event_formatter/action_view/render_formatter_spec.rb +11 -5
  96. data/spec/lib/appsignal/event_formatter/elastic_search/search_formatter_spec.rb +4 -4
  97. data/spec/lib/appsignal/event_formatter/mongo_ruby_driver/query_formatter_spec.rb +1 -4
  98. data/spec/lib/appsignal/event_formatter_spec.rb +11 -9
  99. data/spec/lib/appsignal/hooks/action_cable_spec.rb +5 -2
  100. data/spec/lib/appsignal/hooks/action_mailer_spec.rb +2 -1
  101. data/spec/lib/appsignal/hooks/active_support_notifications/instrument_shared_examples.rb +1 -1
  102. data/spec/lib/appsignal/hooks/active_support_notifications/start_finish_shared_examples.rb +1 -1
  103. data/spec/lib/appsignal/hooks/activejob_spec.rb +21 -12
  104. data/spec/lib/appsignal/hooks/data_mapper_spec.rb +1 -0
  105. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +12 -12
  106. data/spec/lib/appsignal/hooks/excon_spec.rb +2 -2
  107. data/spec/lib/appsignal/hooks/mongo_ruby_driver_spec.rb +3 -1
  108. data/spec/lib/appsignal/hooks/shoryuken_spec.rb +4 -2
  109. data/spec/lib/appsignal/hooks/sidekiq_spec.rb +2 -1
  110. data/spec/lib/appsignal/hooks_spec.rb +5 -4
  111. data/spec/lib/appsignal/integrations/grape_spec.rb +8 -4
  112. data/spec/lib/appsignal/integrations/hanami_spec.rb +16 -8
  113. data/spec/lib/appsignal/integrations/mongo_ruby_driver_spec.rb +2 -4
  114. data/spec/lib/appsignal/integrations/object_spec.rb +6 -1
  115. data/spec/lib/appsignal/integrations/padrino_spec.rb +4 -2
  116. data/spec/lib/appsignal/integrations/railtie_spec.rb +213 -6
  117. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +54 -41
  118. data/spec/lib/appsignal/logger_spec.rb +20 -4
  119. data/spec/lib/appsignal/marker_spec.rb +2 -2
  120. data/spec/lib/appsignal/minutely_spec.rb +3 -3
  121. data/spec/lib/appsignal/probes/gvl_spec.rb +60 -12
  122. data/spec/lib/appsignal/probes/mri_spec.rb +7 -4
  123. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +2 -1
  124. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +2 -1
  125. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +10 -5
  126. data/spec/lib/appsignal/rack/streaming_listener_spec.rb +7 -5
  127. data/spec/lib/appsignal/transaction_spec.rb +20 -13
  128. data/spec/lib/appsignal/utils/data_spec.rb +10 -1
  129. data/spec/lib/appsignal/utils/hash_sanitizer_spec.rb +11 -11
  130. data/spec/lib/appsignal/utils/json_spec.rb +4 -2
  131. data/spec/lib/appsignal_spec.rb +49 -35
  132. data/spec/lib/puma/appsignal_spec.rb +9 -11
  133. data/spec/spec_helper.rb +14 -2
  134. data/spec/support/fixtures/projects/valid/config/appsignal.yml +1 -1
  135. data/spec/support/helpers/config_helpers.rb +2 -1
  136. data/spec/support/helpers/dependency_helper.rb +1 -9
  137. data/spec/support/helpers/std_streams_helper.rb +1 -3
  138. data/spec/support/helpers/wait_for_helper.rb +2 -3
  139. data/spec/support/mocks/appsignal_mock.rb +1 -1
  140. data/spec/support/mocks/fake_gvl_tools.rb +2 -10
  141. data/spec/support/testing.rb +4 -3
  142. metadata +9 -135
@@ -153,7 +153,8 @@ if DependencyHelper.grape_present?
153
153
  end
154
154
 
155
155
  it "sets non-unique route_param path" do
156
- expect(transaction).to receive(:set_action_if_nil).with("GET::GrapeExample::Api#/users/:id/")
156
+ expect(transaction).to receive(:set_action_if_nil)
157
+ .with("GET::GrapeExample::Api#/users/:id/")
157
158
  expect(transaction).to receive(:set_metadata).with("path", "/users/:id/")
158
159
  expect(transaction).to receive(:set_metadata).with("method", "GET")
159
160
  end
@@ -177,7 +178,8 @@ if DependencyHelper.grape_present?
177
178
  end
178
179
 
179
180
  it "sets namespaced path" do
180
- expect(transaction).to receive(:set_action_if_nil).with("POST::GrapeExample::Api#/v1/beta/ping")
181
+ expect(transaction).to receive(:set_action_if_nil)
182
+ .with("POST::GrapeExample::Api#/v1/beta/ping")
181
183
  expect(transaction).to receive(:set_metadata).with("path", "/v1/beta/ping")
182
184
  expect(transaction).to receive(:set_metadata).with("method", "POST")
183
185
  end
@@ -199,7 +201,8 @@ if DependencyHelper.grape_present?
199
201
  end
200
202
 
201
203
  it "sets namespaced path" do
202
- expect(transaction).to receive(:set_action_if_nil).with("POST::GrapeExample::Api#/v1/beta/ping")
204
+ expect(transaction).to receive(:set_action_if_nil)
205
+ .with("POST::GrapeExample::Api#/v1/beta/ping")
203
206
  expect(transaction).to receive(:set_metadata).with("path", "/v1/beta/ping")
204
207
  expect(transaction).to receive(:set_metadata).with("method", "POST")
205
208
  end
@@ -220,7 +223,8 @@ if DependencyHelper.grape_present?
220
223
  end
221
224
 
222
225
  it "sets namespaced path" do
223
- expect(transaction).to receive(:set_action_if_nil).with("POST::GrapeExample::Api#/v1/beta/ping")
226
+ expect(transaction).to receive(:set_action_if_nil)
227
+ .with("POST::GrapeExample::Api#/v1/beta/ping")
224
228
  expect(transaction).to receive(:set_metadata).with("path", "/v1/beta/ping")
225
229
  expect(transaction).to receive(:set_metadata).with("method", "POST")
226
230
  end
@@ -20,14 +20,16 @@ if DependencyHelper.hanami2_present?
20
20
  end
21
21
 
22
22
  it "prepends the integration to Hanami" do
23
- expect(::Hanami::Action).to receive(:send).with(:prepend, Appsignal::Integrations::HanamiIntegration)
23
+ expect(::Hanami::Action).to receive(:prepend)
24
+ .with(Appsignal::Integrations::HanamiIntegration)
24
25
  end
25
26
 
26
27
  context "when not active" do
27
28
  before { allow(Appsignal).to receive(:active?).and_return(false) }
28
29
 
29
30
  it "does not prepend the integration" do
30
- expect(::Hanami::Action).to_not receive(:send).with(:prepend, Appsignal::Integrations::HanamiIntegration)
31
+ expect(::Hanami::Action).to_not receive(:prepend)
32
+ .with(Appsignal::Integrations::HanamiIntegration)
31
33
  end
32
34
  end
33
35
 
@@ -71,17 +73,22 @@ if DependencyHelper.hanami2_present?
71
73
  end
72
74
 
73
75
  it "sets the action name" do
74
- expect_any_instance_of(Appsignal::Transaction).to receive(:set_action_if_nil).with("HanamiApp::Actions::Books::Index")
76
+ expect_any_instance_of(Appsignal::Transaction).to receive(:set_action_if_nil)
77
+ .with("HanamiApp::Actions::Books::Index")
75
78
  end
76
79
 
77
80
  it "sets the metadata" do
78
- expect_any_instance_of(Appsignal::Transaction).to receive(:set_metadata).with("status", "200")
79
- expect_any_instance_of(Appsignal::Transaction).to receive(:set_metadata).with("path", "/books")
80
- expect_any_instance_of(Appsignal::Transaction).to receive(:set_metadata).with("method", "GET")
81
+ expect_any_instance_of(Appsignal::Transaction).to receive(:set_metadata)
82
+ .with("status", "200")
83
+ expect_any_instance_of(Appsignal::Transaction).to receive(:set_metadata)
84
+ .with("path", "/books")
85
+ expect_any_instance_of(Appsignal::Transaction).to receive(:set_metadata)
86
+ .with("method", "GET")
81
87
  end
82
88
 
83
89
  it "sets the queue start" do
84
- expect_any_instance_of(Appsignal::Transaction).to receive(:set_http_or_background_queue_start)
90
+ expect_any_instance_of(Appsignal::Transaction)
91
+ .to receive(:set_http_or_background_queue_start)
85
92
  end
86
93
 
87
94
  context "with error", :error => true do
@@ -92,7 +99,8 @@ if DependencyHelper.hanami2_present?
92
99
  end
93
100
 
94
101
  it "sets the status to 500" do
95
- expect_any_instance_of(Appsignal::Transaction).to receive(:set_metadata).with("status", "500")
102
+ expect_any_instance_of(Appsignal::Transaction).to receive(:set_metadata)
103
+ .with("status", "500")
96
104
  expect_any_instance_of(Appsignal::Transaction).to receive(:set_metadata).twice
97
105
  end
98
106
  end
@@ -19,11 +19,8 @@ describe Appsignal::Hooks::MongoMonitorSubscriber do
19
19
  it "should sanitize command" do
20
20
  # TODO: additional curly brackets required for issue
21
21
  # https://github.com/rspec/rspec-mocks/issues/1460
22
- # rubocop:disable Style/BracesAroundHashParameters
23
22
  expect(Appsignal::EventFormatter::MongoRubyDriver::QueryFormatter)
24
23
  .to receive(:format).with("find", { "foo" => "bar" })
25
- # rubocop:enable Style/BracesAroundHashParameters
26
-
27
24
  subscriber.started(event)
28
25
  end
29
26
 
@@ -107,7 +104,8 @@ describe Appsignal::Hooks::MongoMonitorSubscriber do
107
104
 
108
105
  context "without transaction" do
109
106
  before do
110
- allow(Appsignal::Transaction).to receive(:current).and_return(Appsignal::Transaction::NilTransaction.new)
107
+ allow(Appsignal::Transaction).to receive(:current)
108
+ .and_return(Appsignal::Transaction::NilTransaction.new)
111
109
  end
112
110
 
113
111
  it "should not attempt to start an event" do
@@ -25,7 +25,8 @@ describe Object do
25
25
  let(:transaction) { http_request_transaction }
26
26
  before do
27
27
  Appsignal.config = project_fixture_config
28
- expect(Appsignal::Transaction).to receive(:current).at_least(:once).and_return(transaction)
28
+ expect(Appsignal::Transaction).to receive(:current)
29
+ .at_least(:once).and_return(transaction)
29
30
  expect(Appsignal.active?).to be_truthy
30
31
  end
31
32
  after { Appsignal.config = nil }
@@ -43,9 +44,11 @@ describe Object do
43
44
  end
44
45
  appsignal_instrument_method :positional_arguments_splat
45
46
 
47
+ # rubocop:disable Naming/MethodParameterName
46
48
  def keyword_arguments(a: nil, b: nil)
47
49
  [a, b]
48
50
  end
51
+ # rubocop:enable Naming/MethodParameterName
49
52
  appsignal_instrument_method :keyword_arguments
50
53
 
51
54
  def keyword_arguments_splat(**kwargs)
@@ -213,9 +216,11 @@ describe Object do
213
216
  end
214
217
  appsignal_instrument_class_method :positional_arguments_splat
215
218
 
219
+ # rubocop:disable Naming/MethodParameterName
216
220
  def self.keyword_arguments(a: nil, b: nil)
217
221
  [a, b]
218
222
  end
223
+ # rubocop:enable Naming/MethodParameterName
219
224
  appsignal_instrument_class_method :keyword_arguments
220
225
 
221
226
  def self.keyword_arguments_splat(**kwargs)
@@ -283,7 +283,8 @@ if DependencyHelper.padrino_present?
283
283
 
284
284
  it "sets the action with the app name, controller name and action name" do
285
285
  expect_a_transaction_to_be_created
286
- expect(transaction).to receive(:set_action_if_nil).with("PadrinoTestApp:my_controller#index")
286
+ expect(transaction).to receive(:set_action_if_nil)
287
+ .with("PadrinoTestApp:my_controller#index")
287
288
  end
288
289
  end
289
290
 
@@ -295,7 +296,8 @@ if DependencyHelper.padrino_present?
295
296
 
296
297
  it "sets the action with the app name, controller name and action path" do
297
298
  expect_a_transaction_to_be_created
298
- expect(transaction).to receive(:set_action_if_nil).with("PadrinoTestApp:/my_controller#index")
299
+ expect(transaction).to receive(:set_action_if_nil)
300
+ .with("PadrinoTestApp:/my_controller#index")
299
301
  end
300
302
  end
301
303
  end
@@ -1,4 +1,6 @@
1
1
  if DependencyHelper.rails_present?
2
+ require "action_mailer"
3
+
2
4
  describe Appsignal::Integrations::Railtie do
3
5
  context "after initializing the app" do
4
6
  it "should call initialize_appsignal" do
@@ -10,11 +12,7 @@ if DependencyHelper.rails_present?
10
12
  end
11
13
 
12
14
  describe "#initialize_appsignal" do
13
- let(:app) { MyApp::Application }
14
- before do
15
- allow(app.middleware).to receive(:insert_before)
16
- allow(app.middleware).to receive(:insert_after)
17
- end
15
+ let(:app) { MyApp::Application.new }
18
16
 
19
17
  describe ".logger" do
20
18
  before { Appsignal::Integrations::Railtie.initialize_appsignal(app) }
@@ -58,6 +56,52 @@ if DependencyHelper.rails_present?
58
56
  expect(config.env).to eq "env_test"
59
57
  end
60
58
  end
59
+
60
+ if Rails.respond_to?(:error)
61
+ context "when Rails listens to `error`" do
62
+ class ErrorReporterMock
63
+ attr_reader :subscribers
64
+
65
+ def initialize
66
+ @subscribers = []
67
+ end
68
+
69
+ def subscribe(subscriber)
70
+ @subscribers << subscriber
71
+ end
72
+ end
73
+
74
+ let(:error_reporter) { ErrorReporterMock.new }
75
+ before do
76
+ allow(Rails).to receive(:error).and_return(error_reporter)
77
+ end
78
+
79
+ context "when enable_rails_error_reporter is enabled" do
80
+ it "subscribes to the error reporter" do
81
+ Appsignal::Integrations::Railtie.initialize_appsignal(app)
82
+
83
+ expect(error_reporter.subscribers)
84
+ .to eq([Appsignal::Integrations::RailsErrorReporterSubscriber])
85
+ end
86
+ end
87
+
88
+ context "when enable_rails_error_reporter is disabled" do
89
+ it "does not subscribe to the error reporter" do
90
+ ENV["APPSIGNAL_ENABLE_RAILS_ERROR_REPORTER"] = "false"
91
+ Appsignal::Integrations::Railtie.initialize_appsignal(app)
92
+
93
+ expect(error_reporter.subscribers)
94
+ .to_not eq([Appsignal::Integrations::RailsErrorReporterSubscriber])
95
+ end
96
+ end
97
+ end
98
+ else
99
+ context "when Rails does not listen to `error`" do
100
+ it "does not error trying to subscribe to the error reporter" do
101
+ Appsignal::Integrations::Railtie.initialize_appsignal(app)
102
+ end
103
+ end
104
+ end
61
105
  end
62
106
 
63
107
  describe ".initial_config" do
@@ -75,9 +119,172 @@ if DependencyHelper.rails_present?
75
119
  ActionDispatch::DebugExceptions,
76
120
  Appsignal::Rack::RailsInstrumentation
77
121
  )
122
+ Appsignal::Integrations::Railtie.initialize_appsignal(app)
78
123
  end
124
+ end
125
+
126
+ if Rails.respond_to?(:error)
127
+ describe "Rails error reporter" do
128
+ before do
129
+ Appsignal::Integrations::Railtie.initialize_appsignal(app)
130
+ start_agent
131
+ end
132
+ around { |example| keep_transactions { example.run } }
133
+
134
+ context "when error is not handled (reraises the error)" do
135
+ it "does nothing" do
136
+ expect do
137
+ Rails.error.record { raise ExampleStandardError }
138
+ end.to raise_error(ExampleStandardError)
139
+
140
+ expect(created_transactions).to be_empty
141
+ end
142
+ end
79
143
 
80
- after { Appsignal::Integrations::Railtie.initialize_appsignal(app) }
144
+ context "when error is handled (not reraised)" do
145
+ context "when a transaction is active" do
146
+ it "duplicates the transaction namespace, action and tags" do
147
+ current_transaction = http_request_transaction
148
+ current_transaction.set_namespace "custom"
149
+ current_transaction.set_action "CustomAction"
150
+ current_transaction.set_tags(
151
+ :duplicated_tag => "duplicated value"
152
+ )
153
+
154
+ with_current_transaction current_transaction do
155
+ Rails.error.handle { raise ExampleStandardError }
156
+
157
+ transaction = last_transaction
158
+ transaction_hash = transaction.to_h
159
+ expect(transaction_hash).to include(
160
+ "action" => "CustomAction",
161
+ "namespace" => "custom",
162
+ "error" => {
163
+ "name" => "ExampleStandardError",
164
+ "message" => "ExampleStandardError",
165
+ "backtrace" => kind_of(String)
166
+ },
167
+ "sample_data" => hash_including(
168
+ "tags" => {
169
+ "duplicated_tag" => "duplicated value",
170
+ "severity" => "warning"
171
+ }
172
+ )
173
+ )
174
+ end
175
+ end
176
+
177
+ it "overwrites duplicated tags with tags from context" do
178
+ current_transaction = http_request_transaction
179
+ current_transaction.set_tags(:tag1 => "duplicated value")
180
+
181
+ with_current_transaction current_transaction do
182
+ given_context = { :tag1 => "value1", :tag2 => "value2" }
183
+ Rails.error.handle(:context => given_context) { raise ExampleStandardError }
184
+
185
+ transaction = last_transaction
186
+ transaction_hash = transaction.to_h
187
+ expect(transaction_hash).to include(
188
+ "sample_data" => hash_including(
189
+ "tags" => {
190
+ "tag1" => "value1",
191
+ "tag2" => "value2",
192
+ "severity" => "warning"
193
+ }
194
+ )
195
+ )
196
+ end
197
+ end
198
+
199
+ it "overwrites duplicated namespace and action with custom from context" do
200
+ current_transaction = http_request_transaction
201
+ current_transaction.set_namespace "custom"
202
+ current_transaction.set_action "CustomAction"
203
+
204
+ with_current_transaction current_transaction do
205
+ given_context = {
206
+ :appsignal => { :namespace => "context", :action => "ContextAction" }
207
+ }
208
+ Rails.error.handle(:context => given_context) { raise ExampleStandardError }
209
+
210
+ transaction = last_transaction
211
+ transaction_hash = transaction.to_h
212
+ expect(transaction_hash).to include(
213
+ "namespace" => "context",
214
+ "action" => "ContextAction"
215
+ )
216
+ end
217
+ end
218
+ end
219
+
220
+ context "when no transaction is active" do
221
+ class ExampleRailsControllerMock
222
+ def action_name
223
+ "index"
224
+ end
225
+ end
226
+
227
+ class ExampleRailsJobMock
228
+ end
229
+
230
+ class ExampleRailsMailerMock < ActionMailer::MailDeliveryJob
231
+ def arguments
232
+ ["ExampleRailsMailerMock", "send_mail"]
233
+ end
234
+ end
235
+
236
+ before do
237
+ clear_current_transaction!
238
+ end
239
+
240
+ it "fetches the action from the controller in the context" do
241
+ # The controller key is set by Rails when raised in a controller
242
+ given_context = { :controller => ExampleRailsControllerMock.new }
243
+ Rails.error.handle(:context => given_context) { raise ExampleStandardError }
244
+
245
+ transaction = last_transaction
246
+ transaction_hash = transaction.to_h
247
+ expect(transaction_hash).to include(
248
+ "action" => "ExampleRailsControllerMock#index"
249
+ )
250
+ end
251
+
252
+ it "sets no action if no execution context is present" do
253
+ # The controller key is set by Rails when raised in a controller
254
+ Rails.error.handle { raise ExampleStandardError }
255
+
256
+ transaction = last_transaction
257
+ transaction_hash = transaction.to_h
258
+ expect(transaction_hash).to include(
259
+ "action" => nil
260
+ )
261
+ end
262
+ end
263
+
264
+ it "sets the error context as tags" do
265
+ given_context = {
266
+ :controller => ExampleRailsControllerMock.new, # Not set as tag
267
+ :job => ExampleRailsJobMock.new, # Not set as tag
268
+ :appsignal => { :something => "not used" }, # Not set as tag
269
+ :tag1 => "value1",
270
+ :tag2 => "value2"
271
+ }
272
+ Rails.error.handle(:context => given_context) { raise ExampleStandardError }
273
+
274
+ transaction = last_transaction
275
+ transaction_hash = transaction.to_h
276
+ expect(transaction_hash).to include(
277
+ "sample_data" => hash_including(
278
+ "tags" => {
279
+ "tag1" => "value1",
280
+ "tag2" => "value2",
281
+ "severity" => "warning"
282
+ }
283
+ )
284
+ )
285
+ end
286
+ end
287
+ end
81
288
  end
82
289
  end
83
290
  end
@@ -10,11 +10,9 @@ describe Appsignal::Integrations::SidekiqErrorHandler do
10
10
 
11
11
  context "without a current transction" do
12
12
  let(:exception) do
13
- begin
14
- raise ExampleStandardError, "uh oh"
15
- rescue => error
16
- error
17
- end
13
+ raise ExampleStandardError, "uh oh"
14
+ rescue => error
15
+ error
18
16
  end
19
17
  let(:job_context) do
20
18
  {
@@ -74,14 +72,14 @@ describe Appsignal::Integrations::SidekiqMiddleware, :with_yaml_parse_error => f
74
72
  let(:jid) { "b4a577edbccf1d805744efa9" }
75
73
  let(:item) do
76
74
  {
77
- "jid" => jid,
78
- "class" => job_class,
75
+ "jid" => jid,
76
+ "class" => job_class,
79
77
  "retry_count" => 0,
80
- "queue" => "default",
81
- "created_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
78
+ "queue" => "default",
79
+ "created_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
82
80
  "enqueued_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
83
- "args" => given_args,
84
- "extra" => "data"
81
+ "args" => given_args,
82
+ "extra" => "data"
85
83
  }
86
84
  end
87
85
  let(:plugin) { Appsignal::Integrations::SidekiqMiddleware.new }
@@ -230,13 +228,10 @@ describe Appsignal::Integrations::SidekiqMiddleware, :with_yaml_parse_error => f
230
228
  it "creates a transaction and adds the error" do
231
229
  # TODO: additional curly brackets required for issue
232
230
  # https://github.com/rspec/rspec-mocks/issues/1460
233
- # rubocop:disable Style/BracesAroundHashParameters
234
231
  expect(Appsignal).to receive(:increment_counter)
235
232
  .with("sidekiq_queue_job_count", 1, { :queue => "default", :status => :failed })
236
233
  expect(Appsignal).to receive(:increment_counter)
237
234
  .with("sidekiq_queue_job_count", 1, { :queue => "default", :status => :processed })
238
- # rubocop:enable Style/BracesAroundHashParameters
239
-
240
235
  expect do
241
236
  perform_job { raise error, "uh oh" }
242
237
  end.to raise_error(error)
@@ -269,15 +264,40 @@ describe Appsignal::Integrations::SidekiqMiddleware, :with_yaml_parse_error => f
269
264
  end
270
265
  end
271
266
 
267
+ if DependencyHelper.rails7_present?
268
+ context "with Rails error reporter" do
269
+ it "reports the worker name as the action, copies the namespace and tags" do
270
+ Appsignal::Integrations::Railtie.initialize_appsignal(MyApp::Application.new)
271
+ Appsignal.config = project_fixture_config("production")
272
+ perform_job do
273
+ Appsignal.tag_job("test_tag" => "value")
274
+ Rails.error.handle do
275
+ raise error, "uh oh"
276
+ end
277
+ end
278
+
279
+ expect(created_transactions.count).to eq(2)
280
+ expected_transaction = {
281
+ "namespace" => "background_job",
282
+ "action" => "TestClass#perform",
283
+ "sample_data" => hash_including(
284
+ "tags" => hash_including("test_tag" => "value")
285
+ )
286
+ }
287
+ sidekiq_transaction = created_transactions.first.to_h
288
+ error_reporter_transaction = created_transactions.last.to_h
289
+ expect(sidekiq_transaction).to include(expected_transaction)
290
+ expect(error_reporter_transaction).to include(expected_transaction)
291
+ end
292
+ end
293
+ end
294
+
272
295
  context "without an error" do
273
296
  it "creates a transaction with events" do
274
297
  # TODO: additional curly brackets required for issue
275
298
  # https://github.com/rspec/rspec-mocks/issues/1460
276
- # rubocop:disable Style/BracesAroundHashParameters
277
299
  expect(Appsignal).to receive(:increment_counter)
278
300
  .with("sidekiq_queue_job_count", 1, { :queue => "default", :status => :processed })
279
- # rubocop:enable Style/BracesAroundHashParameters
280
-
281
301
  perform_job
282
302
 
283
303
  transaction_hash = transaction.to_h
@@ -309,18 +329,14 @@ describe Appsignal::Integrations::SidekiqMiddleware, :with_yaml_parse_error => f
309
329
 
310
330
  def perform_job
311
331
  Timecop.freeze(Time.parse("2001-01-01 10:01:00UTC")) do
312
- begin
313
- exception = nil
314
- plugin.call(worker, item, queue) do
315
- yield if block_given?
316
- end
317
- rescue Exception => exception # rubocop:disable Lint/RescueException
318
- raise exception
319
- ensure
320
- if exception
321
- Appsignal::Integrations::SidekiqErrorHandler.new.call(exception, :job => item)
322
- end
332
+ exception = nil
333
+ plugin.call(worker, item, queue) do
334
+ yield if block_given?
323
335
  end
336
+ rescue Exception => exception # rubocop:disable Lint/RescueException
337
+ raise exception
338
+ ensure
339
+ Appsignal::Integrations::SidekiqErrorHandler.new.call(exception, :job => item) if exception
324
340
  end
325
341
  end
326
342
 
@@ -516,7 +532,8 @@ if DependencyHelper.active_job_present?
516
532
  expect(transaction_hash).to include(
517
533
  "action" => "ActionMailerSidekiqTestJob#welcome",
518
534
  "sample_data" => hash_including(
519
- "params" => ["ActionMailerSidekiqTestJob", "welcome", "deliver_now"] + expected_wrapped_args
535
+ "params" => ["ActionMailerSidekiqTestJob", "welcome",
536
+ "deliver_now"] + expected_wrapped_args
520
537
  )
521
538
  )
522
539
  end
@@ -524,18 +541,14 @@ if DependencyHelper.active_job_present?
524
541
 
525
542
  def perform_sidekiq
526
543
  Timecop.freeze(time) do
527
- begin
528
- yield
529
- # Combined with Sidekiq::Testing.fake! and drain_all we get a
530
- # enqueue_at in the job data.
531
- Sidekiq::Worker.drain_all
532
- rescue Exception => exception # rubocop:disable Lint/RescueException
533
- raise exception
534
- ensure
535
- if exception
536
- Appsignal::Integrations::SidekiqErrorHandler.new.call(exception, {})
537
- end
538
- end
544
+ yield
545
+ # Combined with Sidekiq::Testing.fake! and drain_all we get a
546
+ # enqueue_at in the job data.
547
+ Sidekiq::Worker.drain_all
548
+ rescue Exception => exception # rubocop:disable Lint/RescueException
549
+ raise exception
550
+ ensure
551
+ Appsignal::Integrations::SidekiqErrorHandler.new.call(exception, {}) if exception
539
552
  end
540
553
  end
541
554
 
@@ -60,13 +60,31 @@ describe Appsignal::Logger do
60
60
  end
61
61
 
62
62
  it "should log with a level, message and group" do
63
- expect(Appsignal::Extension).to receive(:log)
64
- .with("other_group", 3, 0, "formatted: 'Log message'", instance_of(Appsignal::Extension::Data))
63
+ expect(Appsignal::Extension).to receive(:log).with(
64
+ "other_group",
65
+ 3,
66
+ 0,
67
+ "formatted: 'Log message'",
68
+ instance_of(Appsignal::Extension::Data)
69
+ )
65
70
  logger.add(::Logger::INFO, "Log message", "other_group")
66
71
  end
67
72
  end
68
73
  end
69
74
 
75
+ describe "#silence" do
76
+ it "calls the given block" do
77
+ num = 1
78
+
79
+ logger.silence do
80
+ num += 1
81
+ end
82
+
83
+ expect(num).to eq(2)
84
+ expect(Appsignal::Extension).not_to receive(:log)
85
+ end
86
+ end
87
+
70
88
  [
71
89
  ["debug", 2, ::Logger::INFO],
72
90
  ["info", 3, ::Logger::WARN],
@@ -76,11 +94,9 @@ describe Appsignal::Logger do
76
94
  ].each do |method|
77
95
  describe "##{method[0]}" do
78
96
  it "should log with a message" do
79
- # rubocop:disable Style/BracesAroundHashParameters
80
97
  expect(Appsignal::Utils::Data).to receive(:generate)
81
98
  .with({ :attribute => "value" })
82
99
  .and_call_original
83
- # rubocop:enable Style/BracesAroundHashParameters
84
100
  expect(Appsignal::Extension).to receive(:log)
85
101
  .with("group", method[1], 0, "Log message", instance_of(Appsignal::Extension::Data))
86
102
 
@@ -41,8 +41,8 @@ describe Appsignal::Marker do
41
41
  run
42
42
  expect(output).to include \
43
43
  "Notifying AppSignal of deploy with: revision: 503ce0923ed177a3ce000005, user: batman",
44
- "Something went wrong while trying to notify AppSignal: 500 at "\
45
- "#{config[:endpoint]}/1/markers"
44
+ "Something went wrong while trying to notify AppSignal: 500 at " \
45
+ "#{config[:endpoint]}/1/markers"
46
46
  expect(output).to_not include \
47
47
  "AppSignal has been notified of this deploy!"
48
48
  end
@@ -133,7 +133,7 @@ describe Appsignal::Minutely do
133
133
  "oh no initialize!"
134
134
  )
135
135
  # Start of the error backtrace as debug log
136
- expect(log).to contains_log :debug, File.expand_path("../../../../", __FILE__)
136
+ expect(log).to contains_log :debug, File.expand_path("../../..", __dir__)
137
137
  end
138
138
  end
139
139
  end
@@ -166,7 +166,7 @@ describe Appsignal::Minutely do
166
166
  expect(log).to contains_log(:debug, "Gathering minutely metrics with 'my_probe' probe")
167
167
  expect(log).to contains_log(:debug, "Gathering minutely metrics with 'broken_probe' probe")
168
168
  expect(log).to contains_log(:error, "Error in minutely probe 'broken_probe': oh no!")
169
- gem_path = File.expand_path("../../../../", __FILE__) # Start of backtrace
169
+ gem_path = File.expand_path("../../..", __dir__) # Start of backtrace
170
170
  expect(log).to contains_log(:debug, gem_path)
171
171
  end
172
172
  end
@@ -191,7 +191,7 @@ describe Appsignal::Minutely do
191
191
  # Fetch old thread
192
192
  thread = Appsignal::Minutely.instance_variable_get(:@thread)
193
193
  Appsignal::Minutely.start
194
- thread && thread.join # Wait for old thread to exit
194
+ thread&.join # Wait for old thread to exit
195
195
  end.to_not(change { alive_thread_counter.call })
196
196
  end
197
197
  end