appsignal 3.9.3 → 3.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +22 -19
  3. data/.rubocop.yml +1 -1
  4. data/CHANGELOG.md +180 -0
  5. data/Gemfile +1 -0
  6. data/README.md +0 -1
  7. data/Rakefile +1 -1
  8. data/benchmark.rake +99 -42
  9. data/build_matrix.yml +10 -12
  10. data/gemfiles/webmachine1.gemfile +5 -4
  11. data/lib/appsignal/cli/demo.rb +0 -1
  12. data/lib/appsignal/config.rb +57 -97
  13. data/lib/appsignal/demo.rb +15 -20
  14. data/lib/appsignal/environment.rb +6 -1
  15. data/lib/appsignal/event_formatter/rom/sql_formatter.rb +1 -0
  16. data/lib/appsignal/event_formatter.rb +3 -2
  17. data/lib/appsignal/helpers/instrumentation.rb +490 -16
  18. data/lib/appsignal/hooks/action_cable.rb +21 -16
  19. data/lib/appsignal/hooks/active_job.rb +15 -14
  20. data/lib/appsignal/hooks/delayed_job.rb +1 -1
  21. data/lib/appsignal/hooks/shoryuken.rb +3 -63
  22. data/lib/appsignal/integrations/action_cable.rb +5 -7
  23. data/lib/appsignal/integrations/active_support_notifications.rb +1 -0
  24. data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +36 -35
  25. data/lib/appsignal/integrations/data_mapper.rb +1 -0
  26. data/lib/appsignal/integrations/delayed_job_plugin.rb +27 -33
  27. data/lib/appsignal/integrations/dry_monitor.rb +1 -0
  28. data/lib/appsignal/integrations/excon.rb +1 -0
  29. data/lib/appsignal/integrations/http.rb +1 -0
  30. data/lib/appsignal/integrations/net_http.rb +1 -0
  31. data/lib/appsignal/integrations/object.rb +6 -0
  32. data/lib/appsignal/integrations/padrino.rb +21 -25
  33. data/lib/appsignal/integrations/que.rb +13 -20
  34. data/lib/appsignal/integrations/railtie.rb +1 -1
  35. data/lib/appsignal/integrations/rake.rb +45 -15
  36. data/lib/appsignal/integrations/redis.rb +1 -0
  37. data/lib/appsignal/integrations/redis_client.rb +1 -0
  38. data/lib/appsignal/integrations/resque.rb +2 -5
  39. data/lib/appsignal/integrations/shoryuken.rb +75 -0
  40. data/lib/appsignal/integrations/sidekiq.rb +7 -25
  41. data/lib/appsignal/integrations/unicorn.rb +1 -0
  42. data/lib/appsignal/integrations/webmachine.rb +12 -9
  43. data/lib/appsignal/logger.rb +7 -3
  44. data/lib/appsignal/probes/helpers.rb +1 -0
  45. data/lib/appsignal/probes/mri.rb +1 -0
  46. data/lib/appsignal/probes/sidekiq.rb +1 -0
  47. data/lib/appsignal/probes.rb +3 -0
  48. data/lib/appsignal/rack/abstract_middleware.rb +67 -24
  49. data/lib/appsignal/rack/body_wrapper.rb +143 -0
  50. data/lib/appsignal/rack/event_handler.rb +39 -8
  51. data/lib/appsignal/rack/generic_instrumentation.rb +6 -4
  52. data/lib/appsignal/rack/grape_middleware.rb +3 -2
  53. data/lib/appsignal/rack/hanami_middleware.rb +1 -1
  54. data/lib/appsignal/rack/instrumentation_middleware.rb +62 -0
  55. data/lib/appsignal/rack/rails_instrumentation.rb +1 -3
  56. data/lib/appsignal/rack/sinatra_instrumentation.rb +1 -3
  57. data/lib/appsignal/rack/streaming_listener.rb +14 -59
  58. data/lib/appsignal/rack.rb +60 -0
  59. data/lib/appsignal/span.rb +1 -0
  60. data/lib/appsignal/transaction.rb +353 -104
  61. data/lib/appsignal/utils/data.rb +0 -1
  62. data/lib/appsignal/utils/hash_sanitizer.rb +0 -1
  63. data/lib/appsignal/utils/integration_logger.rb +0 -13
  64. data/lib/appsignal/utils/integration_memory_logger.rb +0 -13
  65. data/lib/appsignal/utils/json.rb +0 -1
  66. data/lib/appsignal/utils/query_params_sanitizer.rb +0 -1
  67. data/lib/appsignal/utils/stdout_and_logger_message.rb +0 -1
  68. data/lib/appsignal/utils.rb +6 -0
  69. data/lib/appsignal/version.rb +1 -1
  70. data/lib/appsignal.rb +9 -6
  71. data/spec/lib/appsignal/capistrano2_spec.rb +1 -1
  72. data/spec/lib/appsignal/config_spec.rb +139 -43
  73. data/spec/lib/appsignal/hooks/action_cable_spec.rb +43 -74
  74. data/spec/lib/appsignal/hooks/activejob_spec.rb +9 -0
  75. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +2 -443
  76. data/spec/lib/appsignal/hooks/rake_spec.rb +100 -17
  77. data/spec/lib/appsignal/hooks/shoryuken_spec.rb +0 -171
  78. data/spec/lib/appsignal/integrations/delayed_job_plugin_spec.rb +459 -0
  79. data/spec/lib/appsignal/integrations/padrino_spec.rb +181 -131
  80. data/spec/lib/appsignal/integrations/que_spec.rb +3 -4
  81. data/spec/lib/appsignal/integrations/shoryuken_spec.rb +167 -0
  82. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +4 -4
  83. data/spec/lib/appsignal/integrations/sinatra_spec.rb +10 -2
  84. data/spec/lib/appsignal/integrations/webmachine_spec.rb +77 -17
  85. data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +144 -11
  86. data/spec/lib/appsignal/rack/body_wrapper_spec.rb +263 -0
  87. data/spec/lib/appsignal/rack/event_handler_spec.rb +81 -10
  88. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +70 -17
  89. data/spec/lib/appsignal/rack/grape_middleware_spec.rb +1 -1
  90. data/spec/lib/appsignal/rack/instrumentation_middleware_spec.rb +38 -0
  91. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +4 -2
  92. data/spec/lib/appsignal/rack/streaming_listener_spec.rb +43 -120
  93. data/spec/lib/appsignal/rack_spec.rb +63 -0
  94. data/spec/lib/appsignal/transaction_spec.rb +1675 -953
  95. data/spec/lib/appsignal/utils/integration_logger_spec.rb +12 -16
  96. data/spec/lib/appsignal/utils/integration_memory_logger_spec.rb +0 -10
  97. data/spec/lib/appsignal_spec.rb +517 -13
  98. data/spec/support/helpers/transaction_helpers.rb +44 -20
  99. data/spec/support/matchers/transaction.rb +15 -1
  100. data/spec/support/mocks/dummy_app.rb +1 -1
  101. data/spec/support/testing.rb +1 -1
  102. metadata +12 -4
  103. data/support/check_versions +0 -22
@@ -14,13 +14,6 @@ describe Appsignal::Hooks::ActionCableHook do
14
14
  end
15
15
 
16
16
  describe ActionCable::Channel::Base do
17
- let(:transaction) do
18
- Appsignal::Transaction.new(
19
- transaction_id,
20
- Appsignal::Transaction::ACTION_CABLE,
21
- ActionDispatch::Request.new(env)
22
- )
23
- end
24
17
  let(:channel) do
25
18
  Class.new(ActionCable::Channel::Base) do
26
19
  def speak(_data)
@@ -37,21 +30,20 @@ describe Appsignal::Hooks::ActionCableHook do
37
30
  s.config.logger = ActiveSupport::Logger.new(log)
38
31
  end
39
32
  end
33
+ let(:env) do
34
+ http_request_env_with_data(
35
+ "action_dispatch.request_id" => request_id,
36
+ :params => params,
37
+ :with_queue_start => true
38
+ )
39
+ end
40
40
  let(:connection) { ActionCable::Connection::Base.new(server, env) }
41
41
  let(:identifier) { { :channel => "MyChannel" }.to_json }
42
42
  let(:params) { {} }
43
43
  let(:request_id) { SecureRandom.uuid }
44
- let(:transaction_id) { request_id }
45
- let(:env) do
46
- http_request_env_with_data("action_dispatch.request_id" => request_id, :params => params)
47
- end
48
44
  let(:instance) { channel.new(connection, identifier, params) }
49
45
  before do
50
46
  start_agent
51
- expect(Appsignal.active?).to be_truthy
52
- transaction
53
-
54
- set_current_transaction(transaction)
55
47
 
56
48
  # Stub transmit call for subscribe/unsubscribe tests
57
49
  allow(connection).to receive(:websocket)
@@ -64,7 +56,7 @@ describe Appsignal::Hooks::ActionCableHook do
64
56
  instance.perform_action("message" => "foo", "action" => "speak")
65
57
 
66
58
  transaction = last_transaction
67
- expect(transaction).to have_id(transaction_id)
59
+ expect(transaction).to have_id
68
60
  expect(transaction).to have_namespace(Appsignal::Transaction::ACTION_CABLE)
69
61
  expect(transaction).to have_action("MyChannel#speak")
70
62
  expect(transaction).to_not have_error
@@ -83,40 +75,20 @@ describe Appsignal::Hooks::ActionCableHook do
83
75
  "action" => "speak",
84
76
  "message" => "foo"
85
77
  )
78
+ expect(transaction).to include_tags("request_id" => request_id)
79
+ expect(transaction).to_not have_queue_start
80
+ expect(transaction).to be_completed
86
81
  end
87
82
 
88
83
  context "without request_id (standalone server)" do
89
84
  let(:request_id) { nil }
90
- let(:transaction_id) { SecureRandom.uuid }
91
- let(:action_transaction) do
92
- Appsignal::Transaction.new(
93
- transaction_id,
94
- Appsignal::Transaction::ACTION_CABLE,
95
- ActionDispatch::Request.new(env)
96
- )
97
- end
98
- before do
99
- # Stub future (private AppSignal) transaction id generated by the hook.
100
- expect(SecureRandom).to receive(:uuid).and_return(transaction_id)
101
- end
102
85
 
103
- it "uses its own internal request_id set by the subscribed callback" do
86
+ it "sets a generated request ID" do
104
87
  # Subscribe action, sets the request_id
105
88
  instance.subscribe_to_channel
106
- expect(transaction).to have_id(transaction_id)
107
-
108
- # Expect another transaction for the action.
109
- # This transaction will use the same request_id as the
110
- # transaction id used to subscribe to the channel.
111
- expect(Appsignal::Transaction).to receive(:create).with(
112
- transaction_id,
113
- Appsignal::Transaction::ACTION_CABLE,
114
- kind_of(ActionDispatch::Request)
115
- ).and_return(action_transaction)
116
- allow(Appsignal::Transaction).to receive(:current).and_return(action_transaction)
117
89
 
118
90
  instance.perform_action("message" => "foo", "action" => "speak")
119
- expect(action_transaction).to have_id(transaction_id)
91
+ expect(last_transaction).to include_tags("request_id" => kind_of(String))
120
92
  end
121
93
  end
122
94
 
@@ -139,7 +111,7 @@ describe Appsignal::Hooks::ActionCableHook do
139
111
  end.to raise_error(ExampleException)
140
112
 
141
113
  transaction = last_transaction
142
- expect(transaction).to have_id(transaction_id)
114
+ expect(transaction).to have_id
143
115
  expect(transaction).to have_action("MyChannel#speak")
144
116
  expect(transaction).to have_namespace(Appsignal::Transaction::ACTION_CABLE)
145
117
  expect(transaction).to have_error("ExampleException", "oh no!")
@@ -151,6 +123,8 @@ describe Appsignal::Hooks::ActionCableHook do
151
123
  "action" => "speak",
152
124
  "message" => "foo"
153
125
  )
126
+ expect(transaction).to_not have_queue_start
127
+ expect(transaction).to be_completed
154
128
  end
155
129
  end
156
130
  end
@@ -162,7 +136,7 @@ describe Appsignal::Hooks::ActionCableHook do
162
136
  instance.subscribe_to_channel
163
137
 
164
138
  transaction = last_transaction
165
- expect(transaction).to have_id(transaction_id)
139
+ expect(transaction).to have_id
166
140
  expect(transaction).to have_action("MyChannel#subscribed")
167
141
  expect(transaction).to have_namespace(Appsignal::Transaction::ACTION_CABLE)
168
142
  expect(transaction).to_not have_error
@@ -178,18 +152,17 @@ describe Appsignal::Hooks::ActionCableHook do
178
152
  "name" => "subscribed.action_cable",
179
153
  "title" => ""
180
154
  )
155
+ expect(transaction).to include_tags("request_id" => request_id)
156
+ expect(transaction).to_not have_queue_start
157
+ expect(transaction).to be_completed
181
158
  end
182
159
 
183
160
  context "without request_id (standalone server)" do
184
161
  let(:request_id) { nil }
185
- let(:transaction_id) { SecureRandom.uuid }
186
- before do
187
- allow(SecureRandom).to receive(:uuid).and_return(transaction_id)
188
- instance.subscribe_to_channel
189
- end
162
+ before { instance.subscribe_to_channel }
190
163
 
191
- it "uses its own internal request_id" do
192
- expect(last_transaction).to have_id(transaction_id)
164
+ it "sets a generated request ID" do
165
+ expect(last_transaction).to include_tags("request_id" => kind_of(String))
193
166
  end
194
167
  end
195
168
 
@@ -212,7 +185,7 @@ describe Appsignal::Hooks::ActionCableHook do
212
185
  end.to raise_error(ExampleException)
213
186
 
214
187
  transaction = last_transaction
215
- expect(transaction).to have_id(transaction_id)
188
+ expect(transaction).to have_id
216
189
  expect(transaction).to have_action("MyChannel#subscribed")
217
190
  expect(transaction).to have_namespace(Appsignal::Transaction::ACTION_CABLE)
218
191
  expect(transaction).to have_error("ExampleException", "oh no!")
@@ -221,23 +194,20 @@ describe Appsignal::Hooks::ActionCableHook do
221
194
  "path" => "/blog"
222
195
  )
223
196
  expect(transaction).to include_params("internal" => "true")
197
+ expect(transaction).to_not have_queue_start
198
+ expect(transaction).to be_completed
224
199
  end
225
200
  end
226
201
 
227
202
  if DependencyHelper.rails6_present?
228
203
  context "with ConnectionStub" do
229
204
  let(:connection) { ActionCable::Channel::ConnectionStub.new }
230
- let(:transaction_id) { "Stubbed transaction id" }
231
- before do
232
- # Stub future (private AppSignal) transaction id generated by the hook.
233
- expect(SecureRandom).to receive(:uuid).and_return(transaction_id)
234
- end
235
205
 
236
206
  it "does not fail on missing `#env` method on `ConnectionStub`" do
237
207
  instance.subscribe_to_channel
238
208
 
239
209
  transaction = last_transaction
240
- expect(transaction).to have_id(transaction_id)
210
+ expect(transaction).to have_id
241
211
  expect(transaction).to have_action("MyChannel#subscribed")
242
212
  expect(transaction).to have_namespace(Appsignal::Transaction::ACTION_CABLE)
243
213
  expect(transaction).to_not have_error
@@ -245,7 +215,7 @@ describe Appsignal::Hooks::ActionCableHook do
245
215
  "method" => "websocket",
246
216
  "path" => "" # No path as the ConnectionStub doesn't have the real request env
247
217
  )
248
- expect(transaction).to include_params("internal" => "true")
218
+ expect(transaction).to_not include_params
249
219
  expect(transaction).to include_event(
250
220
  "body" => "",
251
221
  "body_format" => Appsignal::EventFormatter::DEFAULT,
@@ -253,6 +223,8 @@ describe Appsignal::Hooks::ActionCableHook do
253
223
  "name" => "subscribed.action_cable",
254
224
  "title" => ""
255
225
  )
226
+ expect(transaction).to_not have_queue_start
227
+ expect(transaction).to be_completed
256
228
  end
257
229
  end
258
230
  end
@@ -265,7 +237,7 @@ describe Appsignal::Hooks::ActionCableHook do
265
237
  instance.unsubscribe_from_channel
266
238
 
267
239
  transaction = last_transaction
268
- expect(transaction).to have_id(transaction_id)
240
+ expect(transaction).to have_id
269
241
  expect(transaction).to have_action("MyChannel#unsubscribed")
270
242
  expect(transaction).to have_namespace(Appsignal::Transaction::ACTION_CABLE)
271
243
  expect(transaction).to_not have_error
@@ -281,18 +253,16 @@ describe Appsignal::Hooks::ActionCableHook do
281
253
  "name" => "unsubscribed.action_cable",
282
254
  "title" => ""
283
255
  )
256
+ expect(transaction).to_not have_queue_start
257
+ expect(transaction).to be_completed
284
258
  end
285
259
 
286
260
  context "without request_id (standalone server)" do
287
261
  let(:request_id) { nil }
288
- let(:transaction_id) { SecureRandom.uuid }
289
- before do
290
- allow(SecureRandom).to receive(:uuid).and_return(transaction_id)
291
- instance.unsubscribe_from_channel
292
- end
262
+ before { instance.unsubscribe_from_channel }
293
263
 
294
- it "uses its own internal request_id" do
295
- expect(transaction).to have_id(transaction_id)
264
+ it "sets a generated request ID" do
265
+ expect(last_transaction).to include_tags("request_id" => kind_of(String))
296
266
  end
297
267
  end
298
268
 
@@ -315,7 +285,7 @@ describe Appsignal::Hooks::ActionCableHook do
315
285
  end.to raise_error(ExampleException)
316
286
 
317
287
  transaction = last_transaction
318
- expect(transaction).to have_id(transaction_id)
288
+ expect(transaction).to have_id
319
289
  expect(transaction).to have_action("MyChannel#unsubscribed")
320
290
  expect(transaction).to have_namespace(Appsignal::Transaction::ACTION_CABLE)
321
291
  expect(transaction).to have_error("ExampleException", "oh no!")
@@ -324,23 +294,20 @@ describe Appsignal::Hooks::ActionCableHook do
324
294
  "path" => "/blog"
325
295
  )
326
296
  expect(transaction).to include_params("internal" => "true")
297
+ expect(transaction).to_not have_queue_start
298
+ expect(transaction).to be_completed
327
299
  end
328
300
  end
329
301
 
330
302
  if DependencyHelper.rails6_present?
331
303
  context "with ConnectionStub" do
332
304
  let(:connection) { ActionCable::Channel::ConnectionStub.new }
333
- let(:transaction_id) { "Stubbed transaction id" }
334
- before do
335
- # Stub future (private AppSignal) transaction id generated by the hook.
336
- expect(SecureRandom).to receive(:uuid).and_return(transaction_id)
337
- end
338
305
 
339
306
  it "does not fail on missing `#env` method on `ConnectionStub`" do
340
307
  instance.unsubscribe_from_channel
341
308
 
342
309
  transaction = last_transaction
343
- expect(transaction).to have_id(transaction_id)
310
+ expect(transaction).to have_id
344
311
  expect(transaction).to have_action("MyChannel#unsubscribed")
345
312
  expect(transaction).to have_namespace(Appsignal::Transaction::ACTION_CABLE)
346
313
  expect(transaction).to_not have_error
@@ -348,7 +315,7 @@ describe Appsignal::Hooks::ActionCableHook do
348
315
  "method" => "websocket",
349
316
  "path" => "" # No path as the ConnectionStub doesn't have the real request env
350
317
  )
351
- expect(transaction).to include_params("internal" => "true")
318
+ expect(transaction).to_not include_params
352
319
  expect(transaction).to include_event(
353
320
  "body" => "",
354
321
  "body_format" => Appsignal::EventFormatter::DEFAULT,
@@ -356,6 +323,8 @@ describe Appsignal::Hooks::ActionCableHook do
356
323
  "name" => "unsubscribed.action_cable",
357
324
  "title" => ""
358
325
  )
326
+ expect(transaction).to_not have_queue_start
327
+ expect(transaction).to be_completed
359
328
  end
360
329
  end
361
330
  end
@@ -126,6 +126,7 @@ if DependencyHelper.active_job_present?
126
126
  expect(transaction).to include_params([])
127
127
  expect(transaction).to include_tags(
128
128
  "active_job_id" => kind_of(String),
129
+ "request_id" => kind_of(String),
129
130
  "queue" => queue,
130
131
  "executions" => 1
131
132
  )
@@ -196,6 +197,7 @@ if DependencyHelper.active_job_present?
196
197
  expect(transaction).to include_params([])
197
198
  expect(transaction).to include_tags(
198
199
  "active_job_id" => kind_of(String),
200
+ "request_id" => kind_of(String),
199
201
  "queue" => queue,
200
202
  "executions" => 1
201
203
  )
@@ -335,6 +337,7 @@ if DependencyHelper.active_job_present?
335
337
  expect(transaction).to include_params([])
336
338
  expect(transaction).to include_tags(
337
339
  "active_job_id" => kind_of(String),
340
+ "request_id" => kind_of(String),
338
341
  "queue" => queue,
339
342
  "executions" => 1
340
343
  )
@@ -470,6 +473,7 @@ if DependencyHelper.active_job_present?
470
473
  )
471
474
  expect(transaction).to include_tags(
472
475
  "active_job_id" => kind_of(String),
476
+ "request_id" => kind_of(String),
473
477
  "queue" => "mailers",
474
478
  "executions" => 1
475
479
  )
@@ -488,6 +492,7 @@ if DependencyHelper.active_job_present?
488
492
  )
489
493
  expect(transaction).to include_tags(
490
494
  "active_job_id" => kind_of(String),
495
+ "request_id" => kind_of(String),
491
496
  "queue" => "mailers",
492
497
  "executions" => 1
493
498
  )
@@ -510,6 +515,7 @@ if DependencyHelper.active_job_present?
510
515
  )
511
516
  expect(transaction).to include_tags(
512
517
  "active_job_id" => kind_of(String),
518
+ "request_id" => kind_of(String),
513
519
  "queue" => "mailers",
514
520
  "executions" => 1
515
521
  )
@@ -549,6 +555,7 @@ if DependencyHelper.active_job_present?
549
555
  )
550
556
  expect(transaction).to include_tags(
551
557
  "active_job_id" => kind_of(String),
558
+ "request_id" => kind_of(String),
552
559
  "queue" => "mailers",
553
560
  "executions" => 1
554
561
  )
@@ -573,6 +580,7 @@ if DependencyHelper.active_job_present?
573
580
  )
574
581
  expect(transaction).to include_tags(
575
582
  "active_job_id" => kind_of(String),
583
+ "request_id" => kind_of(String),
576
584
  "queue" => "mailers",
577
585
  "executions" => 1
578
586
  )
@@ -599,6 +607,7 @@ if DependencyHelper.active_job_present?
599
607
  )
600
608
  expect(transaction).to include_tags(
601
609
  "active_job_id" => kind_of(String),
610
+ "request_id" => kind_of(String),
602
611
  "queue" => "mailers",
603
612
  "executions" => 1
604
613
  )