appsignal 2.11.4-java → 2.11.9-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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -0
- data/ext/agent.yml +17 -17
- data/lib/appsignal/hooks/action_cable.rb +10 -2
- data/lib/appsignal/hooks/sidekiq.rb +5 -1
- data/lib/appsignal/integrations/object_ruby_modern.rb +20 -43
- data/lib/appsignal/minutely.rb +6 -0
- data/lib/appsignal/version.rb +1 -1
- data/spec/lib/appsignal/hooks/action_cable_spec.rb +88 -0
- data/spec/lib/appsignal/hooks/sidekiq_spec.rb +61 -7
- data/spec/lib/appsignal/integrations/object_spec.rb +91 -4
- data/spec/lib/puma/appsignal_spec.rb +28 -0
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: df7fae0d072de1948a84fc6c546b15da9e76bfde32f70e28d4242ba2dbc98be2
|
|
4
|
+
data.tar.gz: '092acba4f404fafd21333649bdd65c190da7b31507172f7da91c9a56debe2c5a'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e6f79d7c05a1504874bb7b86816d8c2c405e1499ff765839984db085d3b3bb26da03af7749c78e6a7013bf3afe52fc95badd66bc8787c5b7c0587f4d12b1ca70
|
|
7
|
+
data.tar.gz: 843ccd65902958efcd641d09d8c65e9ec55ac0a908ac16651a4016fb99329bfa6b1c903472a59182e21f56f83ac738e7dd0eb03d957bbaed4bba550b8a8ce76b
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
# 2.11.9
|
|
4
|
+
- Fix and simplify Ruby method delegation for object method instrumentation in
|
|
5
|
+
the different Ruby versions. PR #706
|
|
6
|
+
|
|
7
|
+
# 2.11.8
|
|
8
|
+
- Mark minutely probe thread as fork-safe by @pixeltrix. PR #704
|
|
9
|
+
|
|
10
|
+
# 2.11.7
|
|
11
|
+
- Fix ActionCable integration in test environment using `stub_connection`.
|
|
12
|
+
PR #705
|
|
13
|
+
|
|
14
|
+
# 2.11.6
|
|
15
|
+
- Prepend Sidekiq middleware to wrap all Sidekiq middleware. Catches more
|
|
16
|
+
errors and provide more complete performance measurements. PR #698
|
|
17
|
+
|
|
18
|
+
# 2.11.5
|
|
19
|
+
- Add more detailed logging to finish_event calls when the event is unknown, so
|
|
20
|
+
we know what event is being tried to finish. Commit
|
|
21
|
+
c888a04d1b9ac947652b29c111c650fb5a5cf71c
|
|
22
|
+
|
|
3
23
|
# 2.11.4
|
|
4
24
|
- Support Ruby 3.0 for Object method instrumentation with keyword arguments
|
|
5
25
|
(https://docs.appsignal.com/ruby/instrumentation/method-instrumentation.html)
|
data/ext/agent.yml
CHANGED
|
@@ -1,62 +1,62 @@
|
|
|
1
1
|
---
|
|
2
|
-
version:
|
|
2
|
+
version: d98461b
|
|
3
3
|
mirrors:
|
|
4
4
|
- https://appsignal-agent-releases.global.ssl.fastly.net
|
|
5
5
|
- https://d135dj0rjqvssy.cloudfront.net
|
|
6
6
|
triples:
|
|
7
7
|
x86_64-darwin:
|
|
8
8
|
static:
|
|
9
|
-
checksum:
|
|
9
|
+
checksum: 178ab2329c7b29cf45140e4707e75c20379fa0c7dfd7f39266a7a95aea510780
|
|
10
10
|
filename: appsignal-x86_64-darwin-all-static.tar.gz
|
|
11
11
|
dynamic:
|
|
12
|
-
checksum:
|
|
12
|
+
checksum: '0923985cc78c5cf278f45d530679954b94b1a91c87453369116fc05525e29864'
|
|
13
13
|
filename: appsignal-x86_64-darwin-all-dynamic.tar.gz
|
|
14
14
|
universal-darwin:
|
|
15
15
|
static:
|
|
16
|
-
checksum:
|
|
16
|
+
checksum: 178ab2329c7b29cf45140e4707e75c20379fa0c7dfd7f39266a7a95aea510780
|
|
17
17
|
filename: appsignal-x86_64-darwin-all-static.tar.gz
|
|
18
18
|
dynamic:
|
|
19
|
-
checksum:
|
|
19
|
+
checksum: '0923985cc78c5cf278f45d530679954b94b1a91c87453369116fc05525e29864'
|
|
20
20
|
filename: appsignal-x86_64-darwin-all-dynamic.tar.gz
|
|
21
21
|
i686-linux:
|
|
22
22
|
static:
|
|
23
|
-
checksum:
|
|
23
|
+
checksum: cb772a8a178edb25d666b650efda80149c98e80e4264435d6176f8a6104f959a
|
|
24
24
|
filename: appsignal-i686-linux-all-static.tar.gz
|
|
25
25
|
dynamic:
|
|
26
|
-
checksum:
|
|
26
|
+
checksum: c9ac51f4d1b3cc13773d8fa8ea5cfad6af7909144d85186cef9324ec0531bdac
|
|
27
27
|
filename: appsignal-i686-linux-all-dynamic.tar.gz
|
|
28
28
|
x86-linux:
|
|
29
29
|
static:
|
|
30
|
-
checksum:
|
|
30
|
+
checksum: cb772a8a178edb25d666b650efda80149c98e80e4264435d6176f8a6104f959a
|
|
31
31
|
filename: appsignal-i686-linux-all-static.tar.gz
|
|
32
32
|
dynamic:
|
|
33
|
-
checksum:
|
|
33
|
+
checksum: c9ac51f4d1b3cc13773d8fa8ea5cfad6af7909144d85186cef9324ec0531bdac
|
|
34
34
|
filename: appsignal-i686-linux-all-dynamic.tar.gz
|
|
35
35
|
x86_64-linux:
|
|
36
36
|
static:
|
|
37
|
-
checksum:
|
|
37
|
+
checksum: d6c280e992d74f97d59da9827ec5707ca4f6776b0568cde1c083c1113e4b7104
|
|
38
38
|
filename: appsignal-x86_64-linux-all-static.tar.gz
|
|
39
39
|
dynamic:
|
|
40
|
-
checksum:
|
|
40
|
+
checksum: ef1a3f5d4b2ed61ea2ae4d5cb1a261a0e685fb9d3e7ea9efe455498aad386e59
|
|
41
41
|
filename: appsignal-x86_64-linux-all-dynamic.tar.gz
|
|
42
42
|
x86_64-linux-musl:
|
|
43
43
|
static:
|
|
44
|
-
checksum:
|
|
44
|
+
checksum: 9cf8ad34392662746a45cfce18113ad19cc29954789e2058f30e527163f2e98a
|
|
45
45
|
filename: appsignal-x86_64-linux-musl-all-static.tar.gz
|
|
46
46
|
dynamic:
|
|
47
|
-
checksum:
|
|
47
|
+
checksum: 01bd76983227648d9bc41d035e1552fcf18d62f0d6818bf7bb7fc2e7c166513d
|
|
48
48
|
filename: appsignal-x86_64-linux-musl-all-dynamic.tar.gz
|
|
49
49
|
x86_64-freebsd:
|
|
50
50
|
static:
|
|
51
|
-
checksum:
|
|
51
|
+
checksum: 403a597cbdbdba08460c5c9e93347ed9ad1d24333204e6d72db342deb266a296
|
|
52
52
|
filename: appsignal-x86_64-freebsd-all-static.tar.gz
|
|
53
53
|
dynamic:
|
|
54
|
-
checksum:
|
|
54
|
+
checksum: a1faae80ae09a6588c4cd35cb91dfa4b2176fc3cb17fbf79db80194c21e75bf9
|
|
55
55
|
filename: appsignal-x86_64-freebsd-all-dynamic.tar.gz
|
|
56
56
|
amd64-freebsd:
|
|
57
57
|
static:
|
|
58
|
-
checksum:
|
|
58
|
+
checksum: 403a597cbdbdba08460c5c9e93347ed9ad1d24333204e6d72db342deb266a296
|
|
59
59
|
filename: appsignal-x86_64-freebsd-all-static.tar.gz
|
|
60
60
|
dynamic:
|
|
61
|
-
checksum:
|
|
61
|
+
checksum: a1faae80ae09a6588c4cd35cb91dfa4b2176fc3cb17fbf79db80194c21e75bf9
|
|
62
62
|
filename: appsignal-x86_64-freebsd-all-dynamic.tar.gz
|
|
@@ -56,7 +56,11 @@ module Appsignal
|
|
|
56
56
|
def install_callbacks
|
|
57
57
|
ActionCable::Channel::Base.set_callback :subscribe, :around, :prepend => true do |channel, inner|
|
|
58
58
|
# The request is only the original websocket request
|
|
59
|
-
|
|
59
|
+
connection = channel.connection
|
|
60
|
+
# #env is not available on the Rails ConnectionStub class used in the
|
|
61
|
+
# Rails app test suite. If we call `#env` it causes an error to occur
|
|
62
|
+
# in apps' test suites.
|
|
63
|
+
env = connection.respond_to?(:env) ? connection.env : {}
|
|
60
64
|
request = ActionDispatch::Request.new(env)
|
|
61
65
|
env[Appsignal::Hooks::ActionCableHook::REQUEST_ID] ||=
|
|
62
66
|
request.request_id || SecureRandom.uuid
|
|
@@ -84,7 +88,11 @@ module Appsignal
|
|
|
84
88
|
|
|
85
89
|
ActionCable::Channel::Base.set_callback :unsubscribe, :around, :prepend => true do |channel, inner|
|
|
86
90
|
# The request is only the original websocket request
|
|
87
|
-
|
|
91
|
+
connection = channel.connection
|
|
92
|
+
# #env is not available on the Rails ConnectionStub class used in the
|
|
93
|
+
# Rails app test suite. If we call `#env` it causes an error to occur
|
|
94
|
+
# in apps' test suites.
|
|
95
|
+
env = connection.respond_to?(:env) ? connection.env : {}
|
|
88
96
|
request = ActionDispatch::Request.new(env)
|
|
89
97
|
env[Appsignal::Hooks::ActionCableHook::REQUEST_ID] ||=
|
|
90
98
|
request.request_id || SecureRandom.uuid
|
|
@@ -16,7 +16,11 @@ module Appsignal
|
|
|
16
16
|
|
|
17
17
|
::Sidekiq.configure_server do |config|
|
|
18
18
|
config.server_middleware do |chain|
|
|
19
|
-
chain.
|
|
19
|
+
if chain.respond_to? :prepend
|
|
20
|
+
chain.prepend Appsignal::Hooks::SidekiqPlugin
|
|
21
|
+
else
|
|
22
|
+
chain.add Appsignal::Hooks::SidekiqPlugin
|
|
23
|
+
end
|
|
20
24
|
end
|
|
21
25
|
end
|
|
22
26
|
end
|
|
@@ -1,56 +1,33 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class Object
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"#{method_name}.class_method.#{appsignal_reverse_class_name}.other"
|
|
11
|
-
end
|
|
12
|
-
Appsignal.instrument name do
|
|
13
|
-
send "appsignal_uninstrumented_#{method_name}", *args, **kwargs, &block
|
|
14
|
-
end
|
|
4
|
+
def self.appsignal_instrument_class_method(method_name, options = {})
|
|
5
|
+
singleton_class.send \
|
|
6
|
+
:alias_method, "appsignal_uninstrumented_#{method_name}", method_name
|
|
7
|
+
singleton_class.send(:define_method, method_name) do |*args, &block|
|
|
8
|
+
name = options.fetch(:name) do
|
|
9
|
+
"#{method_name}.class_method.#{appsignal_reverse_class_name}.other"
|
|
15
10
|
end
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def self.appsignal_instrument_method(method_name, options = {})
|
|
19
|
-
alias_method "appsignal_uninstrumented_#{method_name}", method_name
|
|
20
|
-
define_method method_name do |*args, **kwargs, &block|
|
|
21
|
-
name = options.fetch(:name) do
|
|
22
|
-
"#{method_name}.#{appsignal_reverse_class_name}.other"
|
|
23
|
-
end
|
|
24
|
-
Appsignal.instrument name do
|
|
25
|
-
send "appsignal_uninstrumented_#{method_name}", *args, **kwargs, &block
|
|
26
|
-
end
|
|
11
|
+
Appsignal.instrument name do
|
|
12
|
+
send "appsignal_uninstrumented_#{method_name}", *args, &block
|
|
27
13
|
end
|
|
28
14
|
end
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
singleton_class.send \
|
|
32
|
-
:alias_method, "appsignal_uninstrumented_#{method_name}", method_name
|
|
33
|
-
singleton_class.send(:define_method, method_name) do |*args, &block|
|
|
34
|
-
name = options.fetch(:name) do
|
|
35
|
-
"#{method_name}.class_method.#{appsignal_reverse_class_name}.other"
|
|
36
|
-
end
|
|
37
|
-
Appsignal.instrument name do
|
|
38
|
-
send "appsignal_uninstrumented_#{method_name}", *args, &block
|
|
39
|
-
end
|
|
40
|
-
end
|
|
15
|
+
if singleton_class.respond_to?(:ruby2_keywords, true)
|
|
16
|
+
singleton_class.send(:ruby2_keywords, method_name)
|
|
41
17
|
end
|
|
18
|
+
end
|
|
42
19
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
end
|
|
20
|
+
def self.appsignal_instrument_method(method_name, options = {})
|
|
21
|
+
alias_method "appsignal_uninstrumented_#{method_name}", method_name
|
|
22
|
+
define_method method_name do |*args, &block|
|
|
23
|
+
name = options.fetch(:name) do
|
|
24
|
+
"#{method_name}.#{appsignal_reverse_class_name}.other"
|
|
25
|
+
end
|
|
26
|
+
Appsignal.instrument name do
|
|
27
|
+
send "appsignal_uninstrumented_#{method_name}", *args, &block
|
|
52
28
|
end
|
|
53
29
|
end
|
|
30
|
+
ruby2_keywords method_name if respond_to?(:ruby2_keywords, true)
|
|
54
31
|
end
|
|
55
32
|
|
|
56
33
|
def self.appsignal_reverse_class_name
|
data/lib/appsignal/minutely.rb
CHANGED
|
@@ -135,6 +135,12 @@ module Appsignal
|
|
|
135
135
|
def start
|
|
136
136
|
stop
|
|
137
137
|
@thread = Thread.new do
|
|
138
|
+
# Advise multi-threaded app servers to ignore this thread
|
|
139
|
+
# for the purposes of fork safety warnings
|
|
140
|
+
if Thread.current.respond_to?(:thread_variable_set)
|
|
141
|
+
Thread.current.thread_variable_set(:fork_safe, true)
|
|
142
|
+
end
|
|
143
|
+
|
|
138
144
|
sleep initial_wait_time
|
|
139
145
|
initialize_probes
|
|
140
146
|
loop do
|
data/lib/appsignal/version.rb
CHANGED
|
@@ -2,6 +2,8 @@ describe Appsignal::Hooks::ActionCableHook do
|
|
|
2
2
|
if DependencyHelper.action_cable_present?
|
|
3
3
|
context "with ActionCable" do
|
|
4
4
|
require "action_cable/engine"
|
|
5
|
+
# Require test helper to test with ConnectionStub
|
|
6
|
+
require "action_cable/channel/test_case" if DependencyHelper.rails6_present?
|
|
5
7
|
|
|
6
8
|
describe ".dependencies_present?" do
|
|
7
9
|
subject { described_class.new.dependencies_present? }
|
|
@@ -262,6 +264,49 @@ describe Appsignal::Hooks::ActionCableHook do
|
|
|
262
264
|
)
|
|
263
265
|
end
|
|
264
266
|
end
|
|
267
|
+
|
|
268
|
+
if DependencyHelper.rails6_present?
|
|
269
|
+
context "with ConnectionStub" do
|
|
270
|
+
let(:connection) { ActionCable::Channel::ConnectionStub.new }
|
|
271
|
+
let(:transaction_id) { "Stubbed transaction id" }
|
|
272
|
+
before do
|
|
273
|
+
# Stub future (private AppSignal) transaction id generated by the hook.
|
|
274
|
+
expect(SecureRandom).to receive(:uuid).and_return(transaction_id)
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
it "does not fail on missing `#env` method on `ConnectionStub`" do
|
|
278
|
+
instance.subscribe_to_channel
|
|
279
|
+
|
|
280
|
+
expect(subject).to include(
|
|
281
|
+
"action" => "MyChannel#subscribed",
|
|
282
|
+
"error" => nil,
|
|
283
|
+
"id" => transaction_id,
|
|
284
|
+
"namespace" => Appsignal::Transaction::ACTION_CABLE,
|
|
285
|
+
"metadata" => {
|
|
286
|
+
"method" => "websocket",
|
|
287
|
+
"path" => "" # No path as the ConnectionStub doesn't have the real request env
|
|
288
|
+
}
|
|
289
|
+
)
|
|
290
|
+
expect(subject["events"].first).to include(
|
|
291
|
+
"allocation_count" => kind_of(Integer),
|
|
292
|
+
"body" => "",
|
|
293
|
+
"body_format" => Appsignal::EventFormatter::DEFAULT,
|
|
294
|
+
"child_allocation_count" => kind_of(Integer),
|
|
295
|
+
"child_duration" => kind_of(Float),
|
|
296
|
+
"child_gc_duration" => kind_of(Float),
|
|
297
|
+
"count" => 1,
|
|
298
|
+
"gc_duration" => kind_of(Float),
|
|
299
|
+
"start" => kind_of(Float),
|
|
300
|
+
"duration" => kind_of(Float),
|
|
301
|
+
"name" => "subscribed.action_cable",
|
|
302
|
+
"title" => ""
|
|
303
|
+
)
|
|
304
|
+
expect(subject["sample_data"]).to include(
|
|
305
|
+
"params" => { "internal" => "true" }
|
|
306
|
+
)
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
end
|
|
265
310
|
end
|
|
266
311
|
|
|
267
312
|
describe "unsubscribe callback" do
|
|
@@ -349,6 +394,49 @@ describe Appsignal::Hooks::ActionCableHook do
|
|
|
349
394
|
)
|
|
350
395
|
end
|
|
351
396
|
end
|
|
397
|
+
|
|
398
|
+
if DependencyHelper.rails6_present?
|
|
399
|
+
context "with ConnectionStub" do
|
|
400
|
+
let(:connection) { ActionCable::Channel::ConnectionStub.new }
|
|
401
|
+
let(:transaction_id) { "Stubbed transaction id" }
|
|
402
|
+
before do
|
|
403
|
+
# Stub future (private AppSignal) transaction id generated by the hook.
|
|
404
|
+
expect(SecureRandom).to receive(:uuid).and_return(transaction_id)
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
it "does not fail on missing `#env` method on `ConnectionStub`" do
|
|
408
|
+
instance.unsubscribe_from_channel
|
|
409
|
+
|
|
410
|
+
expect(subject).to include(
|
|
411
|
+
"action" => "MyChannel#unsubscribed",
|
|
412
|
+
"error" => nil,
|
|
413
|
+
"id" => transaction_id,
|
|
414
|
+
"namespace" => Appsignal::Transaction::ACTION_CABLE,
|
|
415
|
+
"metadata" => {
|
|
416
|
+
"method" => "websocket",
|
|
417
|
+
"path" => "" # No path as the ConnectionStub doesn't have the real request env
|
|
418
|
+
}
|
|
419
|
+
)
|
|
420
|
+
expect(subject["events"].first).to include(
|
|
421
|
+
"allocation_count" => kind_of(Integer),
|
|
422
|
+
"body" => "",
|
|
423
|
+
"body_format" => Appsignal::EventFormatter::DEFAULT,
|
|
424
|
+
"child_allocation_count" => kind_of(Integer),
|
|
425
|
+
"child_duration" => kind_of(Float),
|
|
426
|
+
"child_gc_duration" => kind_of(Float),
|
|
427
|
+
"count" => 1,
|
|
428
|
+
"gc_duration" => kind_of(Float),
|
|
429
|
+
"start" => kind_of(Float),
|
|
430
|
+
"duration" => kind_of(Float),
|
|
431
|
+
"name" => "unsubscribed.action_cable",
|
|
432
|
+
"title" => ""
|
|
433
|
+
)
|
|
434
|
+
expect(subject["sample_data"]).to include(
|
|
435
|
+
"params" => { "internal" => "true" }
|
|
436
|
+
)
|
|
437
|
+
end
|
|
438
|
+
end
|
|
439
|
+
end
|
|
352
440
|
end
|
|
353
441
|
end
|
|
354
442
|
end
|
|
@@ -16,14 +16,31 @@ describe Appsignal::Hooks::SidekiqHook do
|
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
describe "#install" do
|
|
19
|
-
class
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
class SidekiqMiddlewareMockWithPrepend < Array
|
|
20
|
+
alias add <<
|
|
21
|
+
alias exists? include?
|
|
22
|
+
|
|
23
|
+
unless method_defined? :prepend
|
|
24
|
+
def prepend(middleware) # For Ruby < 2.5
|
|
25
|
+
insert(0, middleware)
|
|
26
|
+
end
|
|
22
27
|
end
|
|
23
28
|
end
|
|
29
|
+
|
|
30
|
+
class SidekiqMiddlewareMockWithoutPrepend < Array
|
|
31
|
+
alias add <<
|
|
32
|
+
alias exists? include?
|
|
33
|
+
|
|
34
|
+
undef_method :prepend if method_defined? :prepend # For Ruby >= 2.5
|
|
35
|
+
end
|
|
36
|
+
|
|
24
37
|
module SidekiqMock
|
|
38
|
+
def self.middleware_mock=(mock)
|
|
39
|
+
@middlewares = mock.new
|
|
40
|
+
end
|
|
41
|
+
|
|
25
42
|
def self.middlewares
|
|
26
|
-
@middlewares
|
|
43
|
+
@middlewares
|
|
27
44
|
end
|
|
28
45
|
|
|
29
46
|
def self.configure_server
|
|
@@ -36,15 +53,52 @@ describe Appsignal::Hooks::SidekiqHook do
|
|
|
36
53
|
end
|
|
37
54
|
end
|
|
38
55
|
|
|
56
|
+
def add_middleware(middleware)
|
|
57
|
+
Sidekiq.configure_server do |sidekiq_config|
|
|
58
|
+
sidekiq_config.middlewares.add(middleware)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
39
62
|
before do
|
|
40
63
|
Appsignal.config = project_fixture_config
|
|
41
64
|
stub_const "Sidekiq", SidekiqMock
|
|
42
65
|
end
|
|
43
66
|
|
|
44
|
-
|
|
45
|
-
|
|
67
|
+
context "when Sidekiq middleware responds to prepend method" do # Sidekiq 3.3.0 and newer
|
|
68
|
+
before { Sidekiq.middleware_mock = SidekiqMiddlewareMockWithPrepend }
|
|
69
|
+
|
|
70
|
+
it "adds the AppSignal SidekiqPlugin to the Sidekiq middleware chain in the first position" do
|
|
71
|
+
user_middleware1 = proc {}
|
|
72
|
+
add_middleware(user_middleware1)
|
|
73
|
+
described_class.new.install
|
|
74
|
+
user_middleware2 = proc {}
|
|
75
|
+
add_middleware(user_middleware2)
|
|
46
76
|
|
|
47
|
-
|
|
77
|
+
expect(Sidekiq.server_middleware).to eql([
|
|
78
|
+
Appsignal::Hooks::SidekiqPlugin, # Prepend makes it the first entry
|
|
79
|
+
user_middleware1,
|
|
80
|
+
user_middleware2
|
|
81
|
+
])
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
context "when Sidekiq middleware does not respond to prepend method" do
|
|
86
|
+
before { Sidekiq.middleware_mock = SidekiqMiddlewareMockWithoutPrepend }
|
|
87
|
+
|
|
88
|
+
it "adds the AppSignal SidekiqPlugin to the Sidekiq middleware chain" do
|
|
89
|
+
user_middleware1 = proc {}
|
|
90
|
+
add_middleware(user_middleware1)
|
|
91
|
+
described_class.new.install
|
|
92
|
+
user_middleware2 = proc {}
|
|
93
|
+
add_middleware(user_middleware2)
|
|
94
|
+
|
|
95
|
+
# Add middlewares in whatever order they were added
|
|
96
|
+
expect(Sidekiq.server_middleware).to eql([
|
|
97
|
+
user_middleware1,
|
|
98
|
+
Appsignal::Hooks::SidekiqPlugin,
|
|
99
|
+
user_middleware2
|
|
100
|
+
])
|
|
101
|
+
end
|
|
48
102
|
end
|
|
49
103
|
end
|
|
50
104
|
end
|
|
@@ -30,12 +30,57 @@ describe Object do
|
|
|
30
30
|
before do
|
|
31
31
|
Appsignal.config = project_fixture_config
|
|
32
32
|
expect(Appsignal::Transaction).to receive(:current).at_least(:once).and_return(transaction)
|
|
33
|
+
expect(Appsignal.active?).to be_truthy
|
|
33
34
|
end
|
|
34
35
|
after { Appsignal.config = nil }
|
|
35
36
|
|
|
37
|
+
context "with different kind of arguments" do
|
|
38
|
+
let(:klass) do
|
|
39
|
+
Class.new do
|
|
40
|
+
def positional_arguments(param1, param2)
|
|
41
|
+
[param1, param2]
|
|
42
|
+
end
|
|
43
|
+
appsignal_instrument_method :positional_arguments
|
|
44
|
+
|
|
45
|
+
def positional_arguments_splat(*params)
|
|
46
|
+
params
|
|
47
|
+
end
|
|
48
|
+
appsignal_instrument_method :positional_arguments_splat
|
|
49
|
+
|
|
50
|
+
def keyword_arguments(a: nil, b: nil)
|
|
51
|
+
[a, b]
|
|
52
|
+
end
|
|
53
|
+
appsignal_instrument_method :keyword_arguments
|
|
54
|
+
|
|
55
|
+
def keyword_arguments_splat(**kwargs)
|
|
56
|
+
kwargs
|
|
57
|
+
end
|
|
58
|
+
appsignal_instrument_method :keyword_arguments_splat
|
|
59
|
+
|
|
60
|
+
def splat(*args, **kwargs)
|
|
61
|
+
[args, kwargs]
|
|
62
|
+
end
|
|
63
|
+
appsignal_instrument_method :splat
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "instruments the method and calls it" do
|
|
68
|
+
expect(instance.positional_arguments("abc", "def")).to eq(["abc", "def"])
|
|
69
|
+
expect(instance.positional_arguments_splat("abc", "def")).to eq(["abc", "def"])
|
|
70
|
+
expect(instance.keyword_arguments(:a => "a", :b => "b")).to eq(["a", "b"])
|
|
71
|
+
expect(instance.keyword_arguments_splat(:a => "a", :b => "b"))
|
|
72
|
+
.to eq(:a => "a", :b => "b")
|
|
73
|
+
|
|
74
|
+
expect(instance.splat).to eq([[], {}])
|
|
75
|
+
expect(instance.splat(:a => "a", :b => "b")).to eq([[], { :a => "a", :b => "b" }])
|
|
76
|
+
expect(instance.splat("abc", "def")).to eq([["abc", "def"], {}])
|
|
77
|
+
expect(instance.splat("abc", "def", :a => "a", :b => "b"))
|
|
78
|
+
.to eq([["abc", "def"], { :a => "a", :b => "b" }])
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
36
82
|
context "with anonymous class" do
|
|
37
83
|
it "instruments the method and calls it" do
|
|
38
|
-
expect(Appsignal.active?).to be_truthy
|
|
39
84
|
expect(transaction).to receive(:start_event)
|
|
40
85
|
expect(transaction).to receive(:finish_event).with \
|
|
41
86
|
"foo.AnonymousClass.other", nil, nil, Appsignal::EventFormatter::DEFAULT
|
|
@@ -56,7 +101,6 @@ describe Object do
|
|
|
56
101
|
let(:klass) { NamedClass }
|
|
57
102
|
|
|
58
103
|
it "instruments the method and calls it" do
|
|
59
|
-
expect(Appsignal.active?).to be_truthy
|
|
60
104
|
expect(transaction).to receive(:start_event)
|
|
61
105
|
expect(transaction).to receive(:finish_event).with \
|
|
62
106
|
"foo.NamedClass.other", nil, nil, Appsignal::EventFormatter::DEFAULT
|
|
@@ -81,7 +125,6 @@ describe Object do
|
|
|
81
125
|
let(:klass) { MyModule::NestedModule::NamedClass }
|
|
82
126
|
|
|
83
127
|
it "instruments the method and calls it" do
|
|
84
|
-
expect(Appsignal.active?).to be_truthy
|
|
85
128
|
expect(transaction).to receive(:start_event)
|
|
86
129
|
expect(transaction).to receive(:finish_event).with \
|
|
87
130
|
"bar.NamedClass.NestedModule.MyModule.other", nil, nil,
|
|
@@ -101,7 +144,6 @@ describe Object do
|
|
|
101
144
|
end
|
|
102
145
|
|
|
103
146
|
it "instruments with custom name" do
|
|
104
|
-
expect(Appsignal.active?).to be_truthy
|
|
105
147
|
expect(transaction).to receive(:start_event)
|
|
106
148
|
expect(transaction).to receive(:finish_event).with \
|
|
107
149
|
"my_method.group", nil, nil, Appsignal::EventFormatter::DEFAULT
|
|
@@ -162,6 +204,51 @@ describe Object do
|
|
|
162
204
|
end
|
|
163
205
|
after { Appsignal.config = nil }
|
|
164
206
|
|
|
207
|
+
context "with different kind of arguments" do
|
|
208
|
+
let(:klass) do
|
|
209
|
+
Class.new do
|
|
210
|
+
def self.positional_arguments(param1, param2)
|
|
211
|
+
[param1, param2]
|
|
212
|
+
end
|
|
213
|
+
appsignal_instrument_class_method :positional_arguments
|
|
214
|
+
|
|
215
|
+
def self.positional_arguments_splat(*params)
|
|
216
|
+
params
|
|
217
|
+
end
|
|
218
|
+
appsignal_instrument_class_method :positional_arguments_splat
|
|
219
|
+
|
|
220
|
+
def self.keyword_arguments(a: nil, b: nil)
|
|
221
|
+
[a, b]
|
|
222
|
+
end
|
|
223
|
+
appsignal_instrument_class_method :keyword_arguments
|
|
224
|
+
|
|
225
|
+
def self.keyword_arguments_splat(**kwargs)
|
|
226
|
+
kwargs
|
|
227
|
+
end
|
|
228
|
+
appsignal_instrument_class_method :keyword_arguments_splat
|
|
229
|
+
|
|
230
|
+
def self.splat(*args, **kwargs)
|
|
231
|
+
[args, kwargs]
|
|
232
|
+
end
|
|
233
|
+
appsignal_instrument_class_method :splat
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
it "instruments the method and calls it" do
|
|
238
|
+
expect(klass.positional_arguments("abc", "def")).to eq(["abc", "def"])
|
|
239
|
+
expect(klass.positional_arguments_splat("abc", "def")).to eq(["abc", "def"])
|
|
240
|
+
expect(klass.keyword_arguments(:a => "a", :b => "b")).to eq(["a", "b"])
|
|
241
|
+
expect(klass.keyword_arguments_splat(:a => "a", :b => "b"))
|
|
242
|
+
.to eq(:a => "a", :b => "b")
|
|
243
|
+
|
|
244
|
+
expect(klass.splat).to eq([[], {}])
|
|
245
|
+
expect(klass.splat(:a => "a", :b => "b")).to eq([[], { :a => "a", :b => "b" }])
|
|
246
|
+
expect(klass.splat("abc", "def")).to eq([["abc", "def"], {}])
|
|
247
|
+
expect(klass.splat("abc", "def", :a => "a", :b => "b"))
|
|
248
|
+
.to eq([["abc", "def"], { :a => "a", :b => "b" }])
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
|
|
165
252
|
context "with anonymous class" do
|
|
166
253
|
it "instruments the method and calls it" do
|
|
167
254
|
expect(Appsignal.active?).to be_truthy
|
|
@@ -23,6 +23,27 @@ RSpec.describe "Puma plugin" do
|
|
|
23
23
|
def self.stats
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
def self.run
|
|
27
|
+
# Capture threads running before application is preloaded
|
|
28
|
+
before = Thread.list.reject { |t| t.thread_variable_get(:fork_safe) }
|
|
29
|
+
|
|
30
|
+
# An abbreviated version of what happens in Puma::Cluster#run
|
|
31
|
+
launcher = MockPumaLauncher.new
|
|
32
|
+
plugin = Plugin.plugin.new
|
|
33
|
+
plugin.start(launcher)
|
|
34
|
+
launcher.events.on_booted.call
|
|
35
|
+
|
|
36
|
+
# Wait for minutely probe thread to finish starting
|
|
37
|
+
sleep 0.005
|
|
38
|
+
|
|
39
|
+
# Capture any new threads running after application is preloaded.
|
|
40
|
+
# Any threads created during the preloading phase will not be
|
|
41
|
+
# carried over into the forked workers. Puma warns about these
|
|
42
|
+
# but the minutely probe thread should only exist in the main process.
|
|
43
|
+
after = Thread.list.reject { |t| t.thread_variable_get(:fork_safe) }
|
|
44
|
+
$stdout.puts "! WARNING: Detected #{after.size - before.size} Thread(s) started in app boot" if after.size > before.size
|
|
45
|
+
end
|
|
46
|
+
|
|
26
47
|
class Plugin
|
|
27
48
|
class << self
|
|
28
49
|
attr_reader :plugin
|
|
@@ -68,6 +89,13 @@ RSpec.describe "Puma plugin" do
|
|
|
68
89
|
wait_for("enough probe calls") { probe.calls >= 2 }
|
|
69
90
|
end
|
|
70
91
|
|
|
92
|
+
it "marks the PumaProbe thread as fork-safe", :not_ruby19 do
|
|
93
|
+
out_stream = std_stream
|
|
94
|
+
capture_stdout(out_stream) { Puma.run }
|
|
95
|
+
|
|
96
|
+
expect(out_stream.read).not_to include("WARNING: Detected 1 Thread")
|
|
97
|
+
end
|
|
98
|
+
|
|
71
99
|
context "without Puma.stats" do
|
|
72
100
|
before { Puma.singleton_class.send(:remove_method, :stats) }
|
|
73
101
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: appsignal
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.11.
|
|
4
|
+
version: 2.11.9
|
|
5
5
|
platform: java
|
|
6
6
|
authors:
|
|
7
7
|
- Robert Beekman
|
|
@@ -10,7 +10,7 @@ authors:
|
|
|
10
10
|
autorequire:
|
|
11
11
|
bindir: bin
|
|
12
12
|
cert_chain: []
|
|
13
|
-
date: 2021-
|
|
13
|
+
date: 2021-02-23 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: rack
|
|
@@ -432,7 +432,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
432
432
|
- !ruby/object:Gem::Version
|
|
433
433
|
version: '0'
|
|
434
434
|
requirements: []
|
|
435
|
-
rubygems_version: 3.2.
|
|
435
|
+
rubygems_version: 3.2.8
|
|
436
436
|
signing_key:
|
|
437
437
|
specification_version: 4
|
|
438
438
|
summary: Logs performance and exception data from your app to appsignal.com
|