appsignal 3.10.0 → 3.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (135) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/CHANGELOG.md +197 -0
  4. data/Gemfile +1 -0
  5. data/Rakefile +1 -1
  6. data/benchmark.rake +99 -42
  7. data/lib/appsignal/cli/demo.rb +0 -1
  8. data/lib/appsignal/cli/diagnose.rb +1 -1
  9. data/lib/appsignal/config.rb +204 -130
  10. data/lib/appsignal/demo.rb +16 -26
  11. data/lib/appsignal/event_formatter/rom/sql_formatter.rb +1 -0
  12. data/lib/appsignal/event_formatter.rb +3 -2
  13. data/lib/appsignal/helpers/instrumentation.rb +331 -19
  14. data/lib/appsignal/hooks/action_cable.rb +21 -16
  15. data/lib/appsignal/hooks/active_job.rb +14 -8
  16. data/lib/appsignal/hooks/delayed_job.rb +1 -1
  17. data/lib/appsignal/hooks/shoryuken.rb +3 -63
  18. data/lib/appsignal/integrations/action_cable.rb +5 -7
  19. data/lib/appsignal/integrations/active_support_notifications.rb +1 -0
  20. data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +36 -35
  21. data/lib/appsignal/integrations/data_mapper.rb +1 -0
  22. data/lib/appsignal/integrations/delayed_job_plugin.rb +27 -33
  23. data/lib/appsignal/integrations/dry_monitor.rb +1 -0
  24. data/lib/appsignal/integrations/excon.rb +1 -0
  25. data/lib/appsignal/integrations/grape.rb +7 -0
  26. data/lib/appsignal/integrations/hanami.rb +8 -43
  27. data/lib/appsignal/integrations/http.rb +1 -0
  28. data/lib/appsignal/integrations/net_http.rb +1 -0
  29. data/lib/appsignal/integrations/object.rb +6 -0
  30. data/lib/appsignal/integrations/padrino.rb +8 -73
  31. data/lib/appsignal/integrations/que.rb +13 -20
  32. data/lib/appsignal/integrations/railtie.rb +36 -14
  33. data/lib/appsignal/integrations/rake.rb +1 -5
  34. data/lib/appsignal/integrations/redis.rb +1 -0
  35. data/lib/appsignal/integrations/redis_client.rb +1 -0
  36. data/lib/appsignal/integrations/resque.rb +2 -5
  37. data/lib/appsignal/integrations/shoryuken.rb +75 -0
  38. data/lib/appsignal/integrations/sidekiq.rb +7 -15
  39. data/lib/appsignal/integrations/sinatra.rb +8 -19
  40. data/lib/appsignal/integrations/unicorn.rb +1 -0
  41. data/lib/appsignal/integrations/webmachine.rb +2 -5
  42. data/lib/appsignal/loaders/grape.rb +13 -0
  43. data/lib/appsignal/loaders/hanami.rb +40 -0
  44. data/lib/appsignal/loaders/padrino.rb +68 -0
  45. data/lib/appsignal/loaders/sinatra.rb +24 -0
  46. data/lib/appsignal/loaders.rb +92 -0
  47. data/lib/appsignal/logger.rb +7 -3
  48. data/lib/appsignal/probes/helpers.rb +1 -0
  49. data/lib/appsignal/probes/mri.rb +1 -0
  50. data/lib/appsignal/probes/sidekiq.rb +1 -0
  51. data/lib/appsignal/probes.rb +3 -0
  52. data/lib/appsignal/rack/abstract_middleware.rb +20 -13
  53. data/lib/appsignal/rack/event_handler.rb +44 -13
  54. data/lib/appsignal/rack/generic_instrumentation.rb +1 -0
  55. data/lib/appsignal/rack/grape_middleware.rb +2 -1
  56. data/lib/appsignal/rack/streaming_listener.rb +1 -0
  57. data/lib/appsignal/rack.rb +35 -0
  58. data/lib/appsignal/span.rb +1 -0
  59. data/lib/appsignal/transaction.rb +308 -101
  60. data/lib/appsignal/utils/data.rb +0 -1
  61. data/lib/appsignal/utils/hash_sanitizer.rb +0 -1
  62. data/lib/appsignal/utils/integration_logger.rb +0 -13
  63. data/lib/appsignal/utils/integration_memory_logger.rb +0 -13
  64. data/lib/appsignal/utils/json.rb +0 -1
  65. data/lib/appsignal/utils/query_params_sanitizer.rb +0 -1
  66. data/lib/appsignal/utils/stdout_and_logger_message.rb +0 -1
  67. data/lib/appsignal/utils.rb +6 -0
  68. data/lib/appsignal/version.rb +1 -1
  69. data/lib/appsignal.rb +169 -14
  70. data/spec/lib/appsignal/capistrano2_spec.rb +1 -1
  71. data/spec/lib/appsignal/cli/demo_spec.rb +0 -1
  72. data/spec/lib/appsignal/cli/diagnose/paths_spec.rb +1 -1
  73. data/spec/lib/appsignal/cli/diagnose_spec.rb +0 -1
  74. data/spec/lib/appsignal/config_spec.rb +291 -44
  75. data/spec/lib/appsignal/demo_spec.rb +1 -2
  76. data/spec/lib/appsignal/environment_spec.rb +4 -2
  77. data/spec/lib/appsignal/hooks/action_cable_spec.rb +43 -74
  78. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +3 -6
  79. data/spec/lib/appsignal/hooks/activejob_spec.rb +12 -3
  80. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +2 -443
  81. data/spec/lib/appsignal/hooks/dry_monitor_spec.rb +4 -7
  82. data/spec/lib/appsignal/hooks/excon_spec.rb +3 -6
  83. data/spec/lib/appsignal/hooks/gvl_spec.rb +2 -2
  84. data/spec/lib/appsignal/hooks/http_spec.rb +1 -3
  85. data/spec/lib/appsignal/hooks/net_http_spec.rb +1 -1
  86. data/spec/lib/appsignal/hooks/redis_client_spec.rb +5 -8
  87. data/spec/lib/appsignal/hooks/redis_spec.rb +3 -6
  88. data/spec/lib/appsignal/hooks/resque_spec.rb +1 -1
  89. data/spec/lib/appsignal/hooks/sequel_spec.rb +3 -5
  90. data/spec/lib/appsignal/hooks/shoryuken_spec.rb +0 -171
  91. data/spec/lib/appsignal/hooks/sidekiq_spec.rb +1 -1
  92. data/spec/lib/appsignal/hooks/webmachine_spec.rb +1 -1
  93. data/spec/lib/appsignal/integrations/delayed_job_plugin_spec.rb +459 -0
  94. data/spec/lib/appsignal/integrations/grape_spec.rb +36 -0
  95. data/spec/lib/appsignal/integrations/hanami_spec.rb +9 -178
  96. data/spec/lib/appsignal/integrations/http_spec.rb +1 -5
  97. data/spec/lib/appsignal/integrations/mongo_ruby_driver_spec.rb +4 -2
  98. data/spec/lib/appsignal/integrations/net_http_spec.rb +1 -1
  99. data/spec/lib/appsignal/integrations/object_spec.rb +1 -3
  100. data/spec/lib/appsignal/integrations/padrino_spec.rb +8 -330
  101. data/spec/lib/appsignal/integrations/que_spec.rb +3 -4
  102. data/spec/lib/appsignal/integrations/railtie_spec.rb +275 -191
  103. data/spec/lib/appsignal/integrations/shoryuken_spec.rb +167 -0
  104. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +15 -13
  105. data/spec/lib/appsignal/integrations/sinatra_spec.rb +9 -104
  106. data/spec/lib/appsignal/integrations/webmachine_spec.rb +13 -1
  107. data/spec/lib/appsignal/loaders/grape_spec.rb +12 -0
  108. data/spec/lib/appsignal/loaders/hanami_spec.rb +95 -0
  109. data/spec/lib/appsignal/loaders/padrino_spec.rb +277 -0
  110. data/spec/lib/appsignal/loaders/sinatra_spec.rb +47 -0
  111. data/spec/lib/appsignal/loaders_spec.rb +137 -0
  112. data/spec/lib/appsignal/probes/sidekiq_spec.rb +1 -1
  113. data/spec/lib/appsignal/probes_spec.rb +6 -5
  114. data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +51 -5
  115. data/spec/lib/appsignal/rack/event_handler_spec.rb +114 -10
  116. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +1 -1
  117. data/spec/lib/appsignal/rack/grape_middleware_spec.rb +2 -35
  118. data/spec/lib/appsignal/rack/hanami_middleware_spec.rb +1 -1
  119. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +4 -2
  120. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +3 -3
  121. data/spec/lib/appsignal/rack_spec.rb +63 -0
  122. data/spec/lib/appsignal/span_spec.rb +1 -3
  123. data/spec/lib/appsignal/transaction_spec.rb +1640 -1075
  124. data/spec/lib/appsignal/utils/integration_logger_spec.rb +12 -16
  125. data/spec/lib/appsignal/utils/integration_memory_logger_spec.rb +0 -10
  126. data/spec/lib/appsignal_spec.rb +601 -36
  127. data/spec/lib/puma/appsignal_spec.rb +0 -3
  128. data/spec/spec_helper.rb +5 -4
  129. data/spec/support/helpers/config_helpers.rb +2 -1
  130. data/spec/support/helpers/loader_helper.rb +21 -0
  131. data/spec/support/helpers/transaction_helpers.rb +44 -20
  132. data/spec/support/matchers/transaction.rb +15 -1
  133. data/spec/support/stubs/appsignal/loaders/loader_stub.rb +7 -0
  134. data/spec/support/testing.rb +47 -1
  135. metadata +19 -2
@@ -3,8 +3,11 @@ describe Appsignal::Rack::EventHandler do
3
3
  let(:env) do
4
4
  {
5
5
  "HTTP_X_REQUEST_START" => "t=#{queue_start_time.to_i}", # in milliseconds
6
- "REQUEST_METHOD" => "GET",
7
- "PATH_INFO" => "/path"
6
+ "REQUEST_METHOD" => "POST",
7
+ "PATH_INFO" => "/path",
8
+ "QUERY_STRING" => "query_param1=value1&query_param2=value2",
9
+ "rack.session" => { "session1" => "value1", "session2" => "value2" },
10
+ "rack.input" => StringIO.new("post_param1=value1&post_param2=value2")
8
11
  }
9
12
  end
10
13
  let(:request) { Rack::Request.new(env) }
@@ -37,6 +40,14 @@ describe Appsignal::Rack::EventHandler do
37
40
  expect(Appsignal::Transaction.current).to eq(transaction)
38
41
  end
39
42
 
43
+ context "when not active" do
44
+ it "does not create a new transaction" do
45
+ allow(Appsignal).to receive(:active?).and_return(false)
46
+
47
+ expect { on_start }.to_not(change { created_transactions.length })
48
+ end
49
+ end
50
+
40
51
  context "when the handler is nested in another EventHandler" do
41
52
  it "does not create a new transaction in the nested EventHandler" do
42
53
  on_start
@@ -128,6 +139,17 @@ describe Appsignal::Rack::EventHandler do
128
139
  expect(last_transaction).to have_error("ExampleStandardError", "the error")
129
140
  end
130
141
 
142
+ context "when not active" do
143
+ it "does not report the transaction" do
144
+ allow(Appsignal).to receive(:active?).and_return(false)
145
+
146
+ on_start
147
+ on_error(ExampleStandardError.new("the error"))
148
+
149
+ expect(last_transaction).to_not have_error
150
+ end
151
+ end
152
+
131
153
  context "when the handler is nested in another EventHandler" do
132
154
  it "does not report the error on the transaction" do
133
155
  on_start
@@ -172,20 +194,107 @@ describe Appsignal::Rack::EventHandler do
172
194
  expect(last_transaction).to_not be_completed
173
195
  end
174
196
 
175
- it "completes the transaction" do
197
+ context "when not active" do
198
+ it "doesn't do anything" do
199
+ allow(Appsignal).to receive(:active?).and_return(false)
200
+
201
+ request.env[Appsignal::Rack::APPSIGNAL_TRANSACTION] = http_request_transaction
202
+ on_finish
203
+
204
+ expect(last_transaction).to_not have_action
205
+ expect(last_transaction).to_not include_events
206
+ expect(last_transaction).to include("sample_data" => {})
207
+ expect(last_transaction).to_not be_completed
208
+ end
209
+ end
210
+
211
+ it "sets params on the transaction" do
212
+ on_start
213
+ on_finish
214
+
215
+ expect(last_transaction).to include_params(
216
+ "query_param1" => "value1",
217
+ "query_param2" => "value2",
218
+ "post_param1" => "value1",
219
+ "post_param2" => "value2"
220
+ )
221
+ end
222
+
223
+ it "sets headers on the transaction" do
176
224
  on_start
177
225
  on_finish
178
226
 
179
- expect(last_transaction).to_not have_action
180
227
  expect(last_transaction).to include_environment(
181
- "REQUEST_METHOD" => "GET",
228
+ "REQUEST_METHOD" => "POST",
182
229
  "PATH_INFO" => "/path"
183
230
  )
231
+ end
232
+
233
+ it "sets session data on the transaction" do
234
+ on_start
235
+ on_finish
236
+
237
+ expect(last_transaction).to include_session_data(
238
+ "session1" => "value1",
239
+ "session2" => "value2"
240
+ )
241
+ end
242
+
243
+ it "sets the queue start time on the transaction" do
244
+ on_start
245
+ on_finish
246
+
184
247
  expect(last_transaction).to have_queue_start(queue_start_time)
248
+ end
249
+
250
+ it "completes the transaction" do
251
+ on_start
252
+ on_finish
253
+
254
+ expect(last_transaction).to_not have_action
185
255
  expect(last_transaction).to be_completed
186
256
  end
187
257
 
188
258
  context "without a response" do
259
+ it "sets params on the transaction" do
260
+ on_start
261
+ on_finish
262
+
263
+ expect(last_transaction).to include_params(
264
+ "query_param1" => "value1",
265
+ "query_param2" => "value2",
266
+ "post_param1" => "value1",
267
+ "post_param2" => "value2"
268
+ )
269
+ end
270
+
271
+ it "sets headers on the transaction" do
272
+ on_start
273
+ on_finish
274
+
275
+ expect(last_transaction).to include_environment(
276
+ "REQUEST_METHOD" => "POST",
277
+ "PATH_INFO" => "/path"
278
+ )
279
+ end
280
+
281
+ it "sets session data on the transaction" do
282
+ on_start
283
+ on_finish
284
+
285
+ expect(last_transaction).to include_session_data(
286
+ "session1" => "value1",
287
+ "session2" => "value2"
288
+ )
289
+ end
290
+
291
+ it "sets the queue start time on the transaction" do
292
+ on_start
293
+ on_finish
294
+
295
+ expect(last_transaction).to have_queue_start(queue_start_time)
296
+ end
297
+
189
298
  it "completes the transaction" do
190
299
  on_start
191
300
  on_finish(request, nil)
@@ -193,11 +302,6 @@ describe Appsignal::Rack::EventHandler do
193
302
  # The action is not set on purpose, as we can't set a normalized route
194
303
  # It requires the app to set an action name
195
304
  expect(last_transaction).to_not have_action
196
- expect(last_transaction).to include_environment(
197
- "REQUEST_METHOD" => "GET",
198
- "PATH_INFO" => "/path"
199
- )
200
- expect(last_transaction).to have_queue_start(queue_start_time)
201
305
  expect(last_transaction).to be_completed
202
306
  end
203
307
 
@@ -46,7 +46,7 @@ describe "Appsignal::Rack::GenericInstrumentation" do
46
46
  let(:env) { Rack::MockRequest.env_for("/some/path") }
47
47
  let(:middleware) { Appsignal::Rack::GenericInstrumentation.new(app, {}) }
48
48
 
49
- before(:context) { start_agent }
49
+ before { start_agent }
50
50
  around { |example| keep_transactions { example.run } }
51
51
 
52
52
  def make_request(env)
@@ -1,38 +1,5 @@
1
1
  if DependencyHelper.grape_present?
2
- require "appsignal/integrations/grape"
3
-
4
- context "Appsignal::Grape::Middleware constant" do
5
- let(:err_stream) { std_stream }
6
- let(:stderr) { err_stream.read }
7
-
8
- it "returns the Rack::GrapeMiddleware constant calling the Grape::Middleware constant" do
9
- silence { expect(Appsignal::Grape::Middleware).to be(Appsignal::Rack::GrapeMiddleware) }
10
- end
11
-
12
- it "prints a deprecation warning to STDERR" do
13
- capture_std_streams(std_stream, err_stream) do
14
- expect(Appsignal::Grape::Middleware).to be(Appsignal::Rack::GrapeMiddleware)
15
- end
16
-
17
- expect(stderr).to include(
18
- "appsignal WARNING: The constant Appsignal::Grape::Middleware has been deprecated."
19
- )
20
- end
21
-
22
- it "logs a warning" do
23
- logs =
24
- capture_logs do
25
- silence do
26
- expect(Appsignal::Grape::Middleware).to be(Appsignal::Rack::GrapeMiddleware)
27
- end
28
- end
29
-
30
- expect(logs).to contains_log(
31
- :warn,
32
- "The constant Appsignal::Grape::Middleware has been deprecated."
33
- )
34
- end
35
- end
2
+ require "appsignal/rack/grape_middleware"
36
3
 
37
4
  describe Appsignal::Rack::GrapeMiddleware do
38
5
  let(:app) do
@@ -52,7 +19,7 @@ if DependencyHelper.grape_present?
52
19
  end
53
20
  let(:middleware) { Appsignal::Rack::GrapeMiddleware.new(api_endpoint) }
54
21
  let(:transaction) { http_request_transaction }
55
- before(:context) { start_agent }
22
+ before { start_agent }
56
23
  around do |example|
57
24
  GrapeExample = Module.new
58
25
  GrapeExample.send(:const_set, :Api, app)
@@ -12,7 +12,7 @@ if DependencyHelper.hanami2_present?
12
12
  end
13
13
  let(:middleware) { Appsignal::Rack::HanamiMiddleware.new(app, {}) }
14
14
 
15
- before(:context) { start_agent }
15
+ before { start_agent }
16
16
  around { |example| keep_transactions { example.run } }
17
17
 
18
18
  def make_request(env)
@@ -114,8 +114,10 @@ if DependencyHelper.rails_present?
114
114
  make_request
115
115
 
116
116
  expect(last_transaction).to_not include_metadata("method" => anything)
117
- expect(log_contents(log))
118
- .to contains_log(:error, "Unable to report HTTP request method: '")
117
+ expect(log_contents(log)).to contains_log(
118
+ :error,
119
+ "Exception while fetching the HTTP request method: "
120
+ )
119
121
  end
120
122
  end
121
123
 
@@ -1,5 +1,5 @@
1
1
  if DependencyHelper.sinatra_present?
2
- require "appsignal/integrations/sinatra"
2
+ require "appsignal/rack/sinatra_instrumentation"
3
3
 
4
4
  module SinatraRequestHelpers
5
5
  def make_request
@@ -21,7 +21,7 @@ if DependencyHelper.sinatra_present?
21
21
  end
22
22
  let(:middleware) { Appsignal::Rack::SinatraInstrumentation.new(app) }
23
23
 
24
- before(:context) { start_agent }
24
+ before { start_agent }
25
25
  around do |example|
26
26
  keep_transactions { example.run }
27
27
  end
@@ -54,7 +54,7 @@ if DependencyHelper.sinatra_present?
54
54
  let(:options) { {} }
55
55
  let(:middleware) { Appsignal::Rack::SinatraBaseInstrumentation.new(app, options) }
56
56
 
57
- before(:context) { start_agent }
57
+ before { start_agent }
58
58
  around do |example|
59
59
  keep_transactions { example.run }
60
60
  end
@@ -0,0 +1,63 @@
1
+ describe Appsignal::Rack::Utils do
2
+ describe ".queue_start_from" do
3
+ let(:header_time) { fixed_time - 0.4 }
4
+ let(:header_time_value) { (header_time * factor).to_i }
5
+ subject { described_class.queue_start_from(env) }
6
+
7
+ shared_examples "HTTP queue start" do
8
+ context "when env is nil" do
9
+ let(:env) { nil }
10
+
11
+ it { is_expected.to be_nil }
12
+ end
13
+
14
+ context "with no relevant header set" do
15
+ let(:env) { {} }
16
+
17
+ it { is_expected.to be_nil }
18
+ end
19
+
20
+ context "with the HTTP_X_REQUEST_START header set" do
21
+ let(:env) { { "HTTP_X_REQUEST_START" => "t=#{header_time_value}" } }
22
+
23
+ it { is_expected.to eq 1_389_783_599_600 }
24
+
25
+ context "with unparsable content" do
26
+ let(:env) { { "HTTP_X_REQUEST_START" => "something" } }
27
+
28
+ it { is_expected.to be_nil }
29
+ end
30
+
31
+ context "with unparsable content at the end" do
32
+ let(:env) { { "HTTP_X_REQUEST_START" => "t=#{header_time_value}aaaa" } }
33
+
34
+ it { is_expected.to eq 1_389_783_599_600 }
35
+ end
36
+
37
+ context "with a really low number" do
38
+ let(:env) { { "HTTP_X_REQUEST_START" => "t=100" } }
39
+
40
+ it { is_expected.to be_nil }
41
+ end
42
+
43
+ context "with the alternate HTTP_X_QUEUE_START header set" do
44
+ let(:env) { { "HTTP_X_QUEUE_START" => "t=#{header_time_value}" } }
45
+
46
+ it { is_expected.to eq 1_389_783_599_600 }
47
+ end
48
+ end
49
+ end
50
+
51
+ context "time in milliseconds" do
52
+ let(:factor) { 1_000 }
53
+
54
+ it_should_behave_like "HTTP queue start"
55
+ end
56
+
57
+ context "time in microseconds" do
58
+ let(:factor) { 1_000_000 }
59
+
60
+ it_should_behave_like "HTTP queue start"
61
+ end
62
+ end
63
+ end
@@ -1,9 +1,7 @@
1
1
  require "appsignal/span"
2
2
 
3
3
  describe Appsignal::Span do
4
- before :context do
5
- start_agent
6
- end
4
+ before { start_agent }
7
5
 
8
6
  let(:namespace) { "web" }
9
7
  let(:root) { Appsignal::Span.new(namespace) }