appsignal 2.11.1-java → 3.0.0.beta.1-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/.rubocop.yml +6 -1
- data/.semaphore/semaphore.yml +197 -23
- data/CHANGELOG.md +25 -0
- data/README.md +9 -0
- data/Rakefile +9 -6
- data/build_matrix.yml +13 -4
- data/ext/agent.yml +17 -17
- data/ext/base.rb +12 -9
- data/gemfiles/no_dependencies.gemfile +7 -0
- data/gemfiles/resque-2.gemfile +0 -1
- data/gemfiles/webmachine.gemfile +1 -0
- data/lib/appsignal.rb +1 -27
- data/lib/appsignal/auth_check.rb +2 -8
- data/lib/appsignal/cli.rb +1 -23
- data/lib/appsignal/cli/diagnose/utils.rb +8 -11
- data/lib/appsignal/cli/install.rb +5 -8
- data/lib/appsignal/config.rb +0 -24
- data/lib/appsignal/event_formatter.rb +0 -25
- data/lib/appsignal/helpers/instrumentation.rb +32 -0
- data/lib/appsignal/hooks.rb +0 -23
- data/lib/appsignal/hooks/action_cable.rb +3 -34
- data/lib/appsignal/hooks/active_support_notifications.rb +7 -86
- data/lib/appsignal/hooks/celluloid.rb +5 -9
- data/lib/appsignal/hooks/net_http.rb +2 -12
- data/lib/appsignal/hooks/puma.rb +3 -5
- data/lib/appsignal/hooks/que.rb +1 -1
- data/lib/appsignal/hooks/rake.rb +2 -24
- data/lib/appsignal/hooks/redis.rb +2 -13
- data/lib/appsignal/hooks/resque.rb +2 -43
- data/lib/appsignal/hooks/shoryuken.rb +43 -4
- data/lib/appsignal/hooks/unicorn.rb +3 -24
- data/lib/appsignal/hooks/webmachine.rb +1 -7
- data/lib/appsignal/integrations/action_cable.rb +34 -0
- data/lib/appsignal/integrations/active_support_notifications.rb +77 -0
- data/lib/appsignal/integrations/net_http.rb +16 -0
- data/lib/appsignal/integrations/object.rb +44 -17
- data/lib/appsignal/integrations/padrino.rb +5 -7
- data/lib/appsignal/integrations/que.rb +26 -33
- data/lib/appsignal/integrations/railtie.rb +1 -4
- data/lib/appsignal/integrations/rake.rb +26 -2
- data/lib/appsignal/integrations/redis.rb +17 -0
- data/lib/appsignal/integrations/resque.rb +39 -10
- data/lib/appsignal/integrations/unicorn.rb +28 -0
- data/lib/appsignal/integrations/webmachine.rb +22 -24
- data/lib/appsignal/minutely.rb +0 -12
- data/lib/appsignal/system.rb +4 -0
- data/lib/appsignal/transaction.rb +30 -2
- data/lib/appsignal/version.rb +1 -1
- data/spec/lib/appsignal/auth_check_spec.rb +1 -24
- data/spec/lib/appsignal/cli_spec.rb +1 -1
- data/spec/lib/appsignal/config_spec.rb +0 -66
- data/spec/lib/appsignal/event_formatter_spec.rb +0 -37
- data/spec/lib/appsignal/hooks/celluloid_spec.rb +6 -1
- data/spec/lib/appsignal/hooks/rake_spec.rb +1 -2
- data/spec/lib/appsignal/hooks/redis_spec.rb +50 -15
- data/spec/lib/appsignal/hooks/resque_spec.rb +10 -2
- data/spec/lib/appsignal/hooks/shoryuken_spec.rb +151 -104
- data/spec/lib/appsignal/hooks/sidekiq_spec.rb +4 -2
- data/spec/lib/appsignal/hooks/unicorn_spec.rb +14 -3
- data/spec/lib/appsignal/hooks/webmachine_spec.rb +2 -13
- data/spec/lib/appsignal/hooks_spec.rb +0 -57
- data/spec/lib/appsignal/integrations/object_spec.rb +25 -10
- data/spec/lib/appsignal/integrations/padrino_spec.rb +2 -3
- data/spec/lib/appsignal/integrations/railtie_spec.rb +0 -45
- data/spec/lib/appsignal/integrations/webmachine_spec.rb +26 -8
- data/spec/lib/appsignal/minutely_spec.rb +0 -19
- data/spec/lib/appsignal/transaction_spec.rb +56 -14
- data/spec/lib/appsignal/transmitter_spec.rb +1 -1
- data/spec/lib/appsignal_spec.rb +30 -69
- data/spec/spec_helper.rb +1 -15
- metadata +13 -22
- data/lib/appsignal/cli/notify_of_deploy.rb +0 -131
- data/lib/appsignal/integrations/resque_active_job.rb +0 -19
- data/lib/appsignal/js_exception_transaction.rb +0 -56
- data/lib/appsignal/rack/js_exception_catcher.rb +0 -80
- data/spec/lib/appsignal/cli/notify_of_deploy_spec.rb +0 -180
- data/spec/lib/appsignal/integrations/resque_active_job_spec.rb +0 -28
- data/spec/lib/appsignal/integrations/resque_spec.rb +0 -28
- data/spec/lib/appsignal/js_exception_transaction_spec.rb +0 -128
- data/spec/lib/appsignal/rack/js_exception_catcher_spec.rb +0 -170
data/lib/appsignal/minutely.rb
CHANGED
@@ -3,8 +3,6 @@
|
|
3
3
|
module Appsignal
|
4
4
|
class Minutely
|
5
5
|
class ProbeCollection
|
6
|
-
include Appsignal::Utils::DeprecationMessage
|
7
|
-
|
8
6
|
def initialize
|
9
7
|
@probes = {}
|
10
8
|
end
|
@@ -27,16 +25,6 @@ module Appsignal
|
|
27
25
|
probes[key]
|
28
26
|
end
|
29
27
|
|
30
|
-
# @param probe [Object] Any object that listens to the `call` method will
|
31
|
-
# be used as a probe.
|
32
|
-
# @deprecated Use {#register} instead.
|
33
|
-
# @return [void]
|
34
|
-
def <<(probe)
|
35
|
-
deprecation_message "Deprecated `Appsignal::Minute.probes <<` " \
|
36
|
-
"call. Please use `Appsignal::Minutely.probes.register` instead."
|
37
|
-
register probe.object_id, probe
|
38
|
-
end
|
39
|
-
|
40
28
|
# Register a new minutely probe.
|
41
29
|
#
|
42
30
|
# Supported probe types are:
|
data/lib/appsignal/system.rb
CHANGED
@@ -11,6 +11,7 @@ module Appsignal
|
|
11
11
|
BLANK = "".freeze
|
12
12
|
ALLOWED_TAG_KEY_TYPES = [Symbol, String].freeze
|
13
13
|
ALLOWED_TAG_VALUE_TYPES = [Symbol, String, Integer].freeze
|
14
|
+
BREADCRUMB_LIMIT = 20
|
14
15
|
|
15
16
|
class << self
|
16
17
|
def create(id, namespace, request, options = {})
|
@@ -58,7 +59,7 @@ module Appsignal
|
|
58
59
|
end
|
59
60
|
end
|
60
61
|
|
61
|
-
attr_reader :ext, :transaction_id, :action, :namespace, :request, :paused, :tags, :options, :discarded
|
62
|
+
attr_reader :ext, :transaction_id, :action, :namespace, :request, :paused, :tags, :options, :discarded, :breadcrumbs
|
62
63
|
|
63
64
|
# @!attribute params
|
64
65
|
# Attribute for parameters of the transaction.
|
@@ -80,6 +81,7 @@ module Appsignal
|
|
80
81
|
@paused = false
|
81
82
|
@discarded = false
|
82
83
|
@tags = {}
|
84
|
+
@breadcrumbs = []
|
83
85
|
@store = Hash.new({})
|
84
86
|
@options = options
|
85
87
|
@options[:params_method] ||= :params
|
@@ -156,6 +158,31 @@ module Appsignal
|
|
156
158
|
@tags.merge!(given_tags)
|
157
159
|
end
|
158
160
|
|
161
|
+
# Add breadcrumbs to the transaction.
|
162
|
+
#
|
163
|
+
# @param category [String] category of breadcrumb
|
164
|
+
# e.g. "UI", "Network", "Navigation", "Console".
|
165
|
+
# @param action [String] name of breadcrumb
|
166
|
+
# e.g "The user clicked a button", "HTTP 500 from http://blablabla.com"
|
167
|
+
# @option message [String] optional message in string format
|
168
|
+
# @option metadata [Hash<String,String>] key/value metadata in <string, string> format
|
169
|
+
# @option time [Time] time of breadcrumb, should respond to `.to_i` defaults to `Time.now.utc`
|
170
|
+
# @return [void]
|
171
|
+
#
|
172
|
+
# @see Appsignal.add_breadcrumb
|
173
|
+
# @see http://docs.appsignal.com/ruby/instrumentation/breadcrumbs.html
|
174
|
+
# Breadcrumb reference
|
175
|
+
def add_breadcrumb(category, action, message = "", metadata = {}, time = Time.now.utc)
|
176
|
+
@breadcrumbs.push(
|
177
|
+
:time => time.to_i,
|
178
|
+
:category => category,
|
179
|
+
:action => action,
|
180
|
+
:message => message,
|
181
|
+
:metadata => metadata
|
182
|
+
)
|
183
|
+
@breadcrumbs = @breadcrumbs.last(BREADCRUMB_LIMIT)
|
184
|
+
end
|
185
|
+
|
159
186
|
# Set an action name for the transaction.
|
160
187
|
#
|
161
188
|
# An action name is used to identify the location of a certain sample;
|
@@ -287,7 +314,8 @@ module Appsignal
|
|
287
314
|
:environment => sanitized_environment,
|
288
315
|
:session_data => sanitized_session_data,
|
289
316
|
:metadata => metadata,
|
290
|
-
:tags => sanitized_tags
|
317
|
+
:tags => sanitized_tags,
|
318
|
+
:breadcrumbs => breadcrumbs
|
291
319
|
}.each do |key, data|
|
292
320
|
set_sample_data(key, data)
|
293
321
|
end
|
data/lib/appsignal/version.rb
CHANGED
@@ -28,29 +28,6 @@ describe Appsignal::AuthCheck do
|
|
28
28
|
end.join("&")
|
29
29
|
end
|
30
30
|
|
31
|
-
describe ".new" do
|
32
|
-
describe "with logger argument" do
|
33
|
-
let(:err_stream) { std_stream }
|
34
|
-
let(:stderr) { err_stream.read }
|
35
|
-
let(:log_stream) { std_stream }
|
36
|
-
let(:log) { log_contents(log_stream) }
|
37
|
-
|
38
|
-
it "logs and prints a deprecation message" do
|
39
|
-
Appsignal.logger = test_logger(log_stream)
|
40
|
-
|
41
|
-
capture_std_streams(std_stream, err_stream) do
|
42
|
-
Appsignal::AuthCheck.new(config, Appsignal.logger)
|
43
|
-
end
|
44
|
-
|
45
|
-
deprecation_message =
|
46
|
-
"`Appsignal::AuthCheck.new`'s `logger` argument " \
|
47
|
-
"will be removed in the next major version."
|
48
|
-
expect(stderr).to include "appsignal WARNING: #{deprecation_message}"
|
49
|
-
expect(log).to contains_log :warn, deprecation_message
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
31
|
describe "#perform" do
|
55
32
|
subject { auth_check.perform }
|
56
33
|
|
@@ -62,7 +39,7 @@ describe Appsignal::AuthCheck do
|
|
62
39
|
end
|
63
40
|
end
|
64
41
|
|
65
|
-
context "when encountering an exception"
|
42
|
+
context "when encountering an exception" do
|
66
43
|
before { stubbed_request.to_timeout }
|
67
44
|
|
68
45
|
it "raises an error" do
|
@@ -168,8 +168,6 @@ describe Appsignal::Config do
|
|
168
168
|
:push_api_key => "abc",
|
169
169
|
:name => "TestApp",
|
170
170
|
:active => true,
|
171
|
-
:enable_frontend_error_catching => false,
|
172
|
-
:frontend_error_catching_path => "/appsignal_error_catcher",
|
173
171
|
:enable_allocation_tracking => true,
|
174
172
|
:enable_gc_instrumentation => false,
|
175
173
|
:enable_host_metrics => true,
|
@@ -357,70 +355,6 @@ describe Appsignal::Config do
|
|
357
355
|
config
|
358
356
|
end
|
359
357
|
end
|
360
|
-
|
361
|
-
describe "support for old config keys" do
|
362
|
-
let(:err_stream) { std_stream }
|
363
|
-
let(:stderr) { err_stream.read }
|
364
|
-
let(:config) { project_fixture_config(env, {}, test_logger(log)) }
|
365
|
-
let(:log) { StringIO.new }
|
366
|
-
before { capture_std_streams(std_stream, err_stream) { config } }
|
367
|
-
|
368
|
-
describe ":api_key" do
|
369
|
-
context "without :push_api_key" do
|
370
|
-
let(:env) { "old_config" }
|
371
|
-
|
372
|
-
it "sets the :push_api_key with the old :api_key value" do
|
373
|
-
expect(config[:push_api_key]).to eq "def"
|
374
|
-
expect(config.config_hash).to_not have_key :api_key
|
375
|
-
|
376
|
-
message = "Old configuration key found. Please update the 'api_key' to 'push_api_key'"
|
377
|
-
expect(stderr).to include "appsignal WARNING: #{message}"
|
378
|
-
expect(log_contents(log)).to contains_log :warn, message
|
379
|
-
end
|
380
|
-
end
|
381
|
-
|
382
|
-
context "with :push_api_key" do
|
383
|
-
let(:env) { "old_config_mixed_with_new_config" }
|
384
|
-
|
385
|
-
it "ignores the :api_key config and deletes it" do
|
386
|
-
expect(config[:push_api_key]).to eq "ghi"
|
387
|
-
expect(config.config_hash).to_not have_key :api_key
|
388
|
-
|
389
|
-
message = "Old configuration key found. Please update the 'api_key' to 'push_api_key'"
|
390
|
-
expect(stderr).to include "appsignal WARNING: #{message}"
|
391
|
-
expect(log_contents(log)).to contains_log :warn, message
|
392
|
-
end
|
393
|
-
end
|
394
|
-
end
|
395
|
-
|
396
|
-
describe ":ignore_exceptions" do
|
397
|
-
context "without :ignore_errors" do
|
398
|
-
let(:env) { "old_config" }
|
399
|
-
|
400
|
-
it "sets :ignore_errors with the old :ignore_exceptions value" do
|
401
|
-
expect(config[:ignore_errors]).to eq ["StandardError"]
|
402
|
-
expect(config.config_hash).to_not have_key :ignore_exceptions
|
403
|
-
|
404
|
-
message = "Old configuration key found. Please update the 'ignore_exceptions' to 'ignore_errors'"
|
405
|
-
expect(stderr).to include "appsignal WARNING: #{message}"
|
406
|
-
expect(log_contents(log)).to contains_log :warn, message
|
407
|
-
end
|
408
|
-
end
|
409
|
-
|
410
|
-
context "with :ignore_errors" do
|
411
|
-
let(:env) { "old_config_mixed_with_new_config" }
|
412
|
-
|
413
|
-
it "ignores the :ignore_exceptions config" do
|
414
|
-
expect(config[:ignore_errors]).to eq ["NoMethodError"]
|
415
|
-
expect(config.config_hash).to_not have_key :ignore_exceptions
|
416
|
-
|
417
|
-
message = "Old configuration key found. Please update the 'ignore_exceptions' to 'ignore_errors'"
|
418
|
-
expect(stderr).to include "appsignal WARNING: #{message}"
|
419
|
-
expect(log_contents(log)).to contains_log :warn, message
|
420
|
-
end
|
421
|
-
end
|
422
|
-
end
|
423
|
-
end
|
424
358
|
end
|
425
359
|
|
426
360
|
context "with config in the environment" do
|
@@ -114,43 +114,6 @@ describe Appsignal::EventFormatter do
|
|
114
114
|
end
|
115
115
|
end
|
116
116
|
end
|
117
|
-
|
118
|
-
context "when registering deprecated formatters" do
|
119
|
-
let(:err_stream) { std_stream }
|
120
|
-
let(:stderr) { err_stream.read }
|
121
|
-
let(:deprecated_formatter) do
|
122
|
-
Class.new(Appsignal::EventFormatter) do
|
123
|
-
register "mock.deprecated"
|
124
|
-
|
125
|
-
def format(_payload)
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
it "registers deprecated formatters and logs & prints a warning" do
|
131
|
-
message = "Formatter for 'mock.deprecated' is using a deprecated registration method. " \
|
132
|
-
"This event formatter will not be loaded. " \
|
133
|
-
"Please update the formatter according to the documentation at: " \
|
134
|
-
"https://docs.appsignal.com/ruby/instrumentation/event-formatters.html"
|
135
|
-
|
136
|
-
logs = capture_logs do
|
137
|
-
capture_std_streams(std_stream, err_stream) { deprecated_formatter }
|
138
|
-
end
|
139
|
-
expect(logs).to contains_log :warn, message
|
140
|
-
expect(stderr).to include "appsignal WARNING: #{message}"
|
141
|
-
|
142
|
-
expect(klass.deprecated_formatter_classes.keys).to include("mock.deprecated")
|
143
|
-
end
|
144
|
-
|
145
|
-
it "initializes deprecated formatters" do
|
146
|
-
capture_std_streams(std_stream, err_stream) { deprecated_formatter }
|
147
|
-
klass.initialize_deprecated_formatters
|
148
|
-
|
149
|
-
expect(klass.registered?("mock.deprecated")).to be_truthy
|
150
|
-
expect(klass.formatters["mock.deprecated"]).to be_instance_of(deprecated_formatter)
|
151
|
-
expect(klass.deprecated_formatter_classes["mock.deprecated"]).to eq(deprecated_formatter)
|
152
|
-
end
|
153
|
-
end
|
154
117
|
end
|
155
118
|
|
156
119
|
describe ".registered?" do
|
@@ -3,6 +3,11 @@ describe Appsignal::Hooks::CelluloidHook do
|
|
3
3
|
before :context do
|
4
4
|
module Celluloid
|
5
5
|
def self.shutdown
|
6
|
+
@shut_down = true
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.shut_down?
|
10
|
+
@shut_down == true
|
6
11
|
end
|
7
12
|
end
|
8
13
|
Appsignal::Hooks::CelluloidHook.new.install
|
@@ -18,7 +23,7 @@ describe Appsignal::Hooks::CelluloidHook do
|
|
18
23
|
end
|
19
24
|
|
20
25
|
specify { expect(Appsignal).to receive(:stop) }
|
21
|
-
specify { expect(Celluloid).to
|
26
|
+
specify { expect(Celluloid.shut_down?).to be true }
|
22
27
|
|
23
28
|
after do
|
24
29
|
Celluloid.shutdown
|
@@ -1,33 +1,68 @@
|
|
1
1
|
describe Appsignal::Hooks::RedisHook do
|
2
2
|
before do
|
3
3
|
Appsignal.config = project_fixture_config
|
4
|
-
Appsignal::Hooks.load_hooks
|
5
4
|
end
|
6
5
|
|
7
6
|
if DependencyHelper.redis_present?
|
8
7
|
context "with redis" do
|
9
8
|
context "with instrumentation enabled" do
|
10
|
-
before do
|
11
|
-
Appsignal.config.config_hash[:instrument_redis] = true
|
12
|
-
allow_any_instance_of(Redis::Client).to receive(:process_without_appsignal).and_return(1)
|
13
|
-
end
|
14
|
-
|
15
9
|
describe "#dependencies_present?" do
|
16
10
|
subject { described_class.new.dependencies_present? }
|
17
11
|
|
18
12
|
it { is_expected.to be_truthy }
|
19
13
|
end
|
20
14
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
15
|
+
describe "integration" do
|
16
|
+
before do
|
17
|
+
Appsignal.config.config_hash[:instrument_redis] = true
|
18
|
+
end
|
19
|
+
|
20
|
+
context "install" do
|
21
|
+
before do
|
22
|
+
Appsignal::Hooks.load_hooks
|
23
|
+
end
|
24
|
+
|
25
|
+
it "does something" do
|
26
|
+
# Test if the last included module (prepended module) was our
|
27
|
+
# integration. That's not certain with the assertions below
|
28
|
+
# because we have to overwrite the `process` method for the test.
|
29
|
+
expect(Redis::Client.included_modules.first)
|
30
|
+
.to eql(Appsignal::Integrations::RedisIntegration)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "instrumentation" do
|
35
|
+
before do
|
36
|
+
# Stub Redis::Client class so that it doesn't perform an actual
|
37
|
+
# Redis query. This class will be included (prepended) with the
|
38
|
+
# AppSignal Redis integration.
|
39
|
+
stub_const("Redis::Client", Class.new do
|
40
|
+
def id
|
41
|
+
:stub_id
|
42
|
+
end
|
43
|
+
|
44
|
+
def process(_commands)
|
45
|
+
:stub_process
|
46
|
+
end
|
47
|
+
end)
|
48
|
+
# Load the integration again for the stubbed Redis::Client class.
|
49
|
+
# Call it directly because {Appsignal::Hooks.load_hooks} keeps
|
50
|
+
# track if it was installed already or not.
|
51
|
+
Appsignal::Hooks::RedisHook.new.install
|
52
|
+
end
|
53
|
+
|
54
|
+
it "instrument a redis call" do
|
55
|
+
Appsignal::Transaction.create("uuid", Appsignal::Transaction::HTTP_REQUEST, "test")
|
56
|
+
expect(Appsignal::Transaction.current).to receive(:start_event)
|
57
|
+
.at_least(:once)
|
58
|
+
expect(Appsignal::Transaction.current).to receive(:finish_event)
|
59
|
+
.at_least(:once)
|
60
|
+
.with("query.redis", :stub_id, "get ?", 0)
|
28
61
|
|
29
|
-
|
30
|
-
|
62
|
+
client = Redis::Client.new
|
63
|
+
expect(client.process([[:get, "key"]])).to eql(:stub_process)
|
64
|
+
end
|
65
|
+
end
|
31
66
|
end
|
32
67
|
end
|
33
68
|
|
@@ -60,7 +60,10 @@ describe Appsignal::Hooks::ResqueHook do
|
|
60
60
|
"error" => nil,
|
61
61
|
"namespace" => namespace,
|
62
62
|
"metadata" => {},
|
63
|
-
"sample_data" => {
|
63
|
+
"sample_data" => {
|
64
|
+
"breadcrumbs" => [],
|
65
|
+
"tags" => { "queue" => queue }
|
66
|
+
}
|
64
67
|
)
|
65
68
|
expect(transaction_hash["events"].map { |e| e["name"] })
|
66
69
|
.to eql(["perform.resque"])
|
@@ -84,7 +87,10 @@ describe Appsignal::Hooks::ResqueHook do
|
|
84
87
|
},
|
85
88
|
"namespace" => namespace,
|
86
89
|
"metadata" => {},
|
87
|
-
"sample_data" => {
|
90
|
+
"sample_data" => {
|
91
|
+
"breadcrumbs" => [],
|
92
|
+
"tags" => { "queue" => queue }
|
93
|
+
}
|
88
94
|
)
|
89
95
|
end
|
90
96
|
end
|
@@ -118,6 +124,7 @@ describe Appsignal::Hooks::ResqueHook do
|
|
118
124
|
"metadata" => {},
|
119
125
|
"sample_data" => {
|
120
126
|
"tags" => { "queue" => queue },
|
127
|
+
"breadcrumbs" => [],
|
121
128
|
"params" => [
|
122
129
|
"foo",
|
123
130
|
{
|
@@ -174,6 +181,7 @@ describe Appsignal::Hooks::ResqueHook do
|
|
174
181
|
"namespace" => namespace,
|
175
182
|
"metadata" => {},
|
176
183
|
"sample_data" => {
|
184
|
+
"breadcrumbs" => [],
|
177
185
|
"tags" => { "queue" => queue }
|
178
186
|
# Params will be set by the ActiveJob integration
|
179
187
|
}
|
@@ -1,55 +1,73 @@
|
|
1
1
|
describe Appsignal::Hooks::ShoryukenMiddleware do
|
2
|
-
let(:current_transaction) { background_job_transaction }
|
3
|
-
|
4
2
|
class DemoShoryukenWorker
|
5
3
|
end
|
6
4
|
|
5
|
+
let(:time) { "2010-01-01 10:01:00UTC" }
|
7
6
|
let(:worker_instance) { DemoShoryukenWorker.new }
|
8
|
-
let(:queue) {
|
9
|
-
let(:sqs_msg) { double(:attributes => {}) }
|
7
|
+
let(:queue) { "some-funky-queue-name" }
|
8
|
+
let(:sqs_msg) { double(:message_id => "msg1", :attributes => {}) }
|
10
9
|
let(:body) { {} }
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
before(:context) { start_agent }
|
11
|
+
around { |example| keep_transactions { example.run } }
|
12
|
+
|
13
|
+
def perform_job(&block)
|
14
|
+
block ||= lambda {}
|
15
|
+
Timecop.freeze(Time.parse(time)) do
|
16
|
+
Appsignal::Hooks::ShoryukenMiddleware.new.call(
|
17
|
+
worker_instance,
|
18
|
+
queue,
|
19
|
+
sqs_msg,
|
20
|
+
body,
|
21
|
+
&block
|
22
|
+
)
|
23
|
+
end
|
15
24
|
end
|
16
25
|
|
17
26
|
context "with a performance call" do
|
18
|
-
let(:
|
27
|
+
let(:sent_timestamp) { Time.parse("1976-11-18 0:00:00UTC").to_i * 1000 }
|
19
28
|
let(:sqs_msg) do
|
20
|
-
double(:attributes => { "SentTimestamp" =>
|
29
|
+
double(:message_id => "msg1", :attributes => { "SentTimestamp" => sent_timestamp })
|
21
30
|
end
|
22
31
|
|
23
32
|
context "with complex argument" do
|
24
|
-
let(:body)
|
25
|
-
{
|
26
|
-
:foo => "Foo",
|
27
|
-
:bar => "Bar"
|
28
|
-
}
|
29
|
-
end
|
30
|
-
after do
|
31
|
-
Timecop.freeze(Time.parse("01-01-2001 10:01:00UTC")) do
|
32
|
-
Appsignal::Hooks::ShoryukenMiddleware.new.call(worker_instance, queue, sqs_msg, body) do
|
33
|
-
# nothing
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
33
|
+
let(:body) { { :foo => "Foo", :bar => "Bar" } }
|
37
34
|
|
38
35
|
it "wraps the job in a transaction with the correct params" do
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
},
|
51
|
-
:queue_start => Time.parse("1976-11-18 0:00:00UTC").utc
|
36
|
+
allow_any_instance_of(Appsignal::Transaction).to receive(:set_queue_start).and_call_original
|
37
|
+
expect { perform_job }.to change { created_transactions.length }.by(1)
|
38
|
+
|
39
|
+
transaction = last_transaction
|
40
|
+
expect(transaction).to be_completed
|
41
|
+
transaction_hash = transaction.to_h
|
42
|
+
expect(transaction_hash).to include(
|
43
|
+
"action" => "DemoShoryukenWorker#perform",
|
44
|
+
"id" => kind_of(String), # AppSignal generated id
|
45
|
+
"namespace" => Appsignal::Transaction::BACKGROUND_JOB,
|
46
|
+
"error" => nil
|
52
47
|
)
|
48
|
+
expect(transaction_hash["events"].first).to include(
|
49
|
+
"allocation_count" => kind_of(Integer),
|
50
|
+
"body" => "",
|
51
|
+
"body_format" => Appsignal::EventFormatter::DEFAULT,
|
52
|
+
"child_allocation_count" => kind_of(Integer),
|
53
|
+
"child_duration" => kind_of(Float),
|
54
|
+
"child_gc_duration" => kind_of(Float),
|
55
|
+
"count" => 1,
|
56
|
+
"gc_duration" => kind_of(Float),
|
57
|
+
"start" => kind_of(Float),
|
58
|
+
"duration" => kind_of(Float),
|
59
|
+
"name" => "perform_job.shoryuken",
|
60
|
+
"title" => ""
|
61
|
+
)
|
62
|
+
expect(transaction_hash["sample_data"]).to include(
|
63
|
+
"params" => { "foo" => "Foo", "bar" => "Bar" },
|
64
|
+
"metadata" => {
|
65
|
+
"message_id" => "msg1",
|
66
|
+
"queue" => queue,
|
67
|
+
"SentTimestamp" => sent_timestamp
|
68
|
+
}
|
69
|
+
)
|
70
|
+
expect(transaction).to have_received(:set_queue_start).with(sent_timestamp)
|
53
71
|
end
|
54
72
|
|
55
73
|
context "with parameter filtering" do
|
@@ -57,21 +75,16 @@ describe Appsignal::Hooks::ShoryukenMiddleware do
|
|
57
75
|
Appsignal.config = project_fixture_config("production")
|
58
76
|
Appsignal.config[:filter_parameters] = ["foo"]
|
59
77
|
end
|
78
|
+
after do
|
79
|
+
Appsignal.config[:filter_parameters] = []
|
80
|
+
end
|
60
81
|
|
61
82
|
it "filters selected arguments" do
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
:queue => "some-funky-queue-name",
|
68
|
-
"SentTimestamp" => 217_123_200_000
|
69
|
-
},
|
70
|
-
:params => {
|
71
|
-
:foo => "[FILTERED]",
|
72
|
-
:bar => "Bar"
|
73
|
-
},
|
74
|
-
:queue_start => Time.parse("1976-11-18 0:00:00UTC").utc
|
83
|
+
perform_job
|
84
|
+
|
85
|
+
transaction_hash = last_transaction.to_h
|
86
|
+
expect(transaction_hash["sample_data"]).to include(
|
87
|
+
"params" => { "foo" => "[FILTERED]", "bar" => "Bar" }
|
75
88
|
)
|
76
89
|
end
|
77
90
|
end
|
@@ -81,23 +94,12 @@ describe Appsignal::Hooks::ShoryukenMiddleware do
|
|
81
94
|
let(:body) { "foo bar" }
|
82
95
|
|
83
96
|
it "handles string arguments" do
|
84
|
-
|
85
|
-
"perform_job.shoryuken",
|
86
|
-
:class => "DemoShoryukenWorker",
|
87
|
-
:method => "perform",
|
88
|
-
:metadata => {
|
89
|
-
:queue => "some-funky-queue-name",
|
90
|
-
"SentTimestamp" => 217_123_200_000
|
91
|
-
},
|
92
|
-
:params => { :params => body },
|
93
|
-
:queue_start => Time.parse("1976-11-18 0:00:00UTC").utc
|
94
|
-
)
|
97
|
+
perform_job
|
95
98
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
end
|
99
|
+
transaction_hash = last_transaction.to_h
|
100
|
+
expect(transaction_hash["sample_data"]).to include(
|
101
|
+
"params" => { "params" => body }
|
102
|
+
)
|
101
103
|
end
|
102
104
|
end
|
103
105
|
|
@@ -105,58 +107,103 @@ describe Appsignal::Hooks::ShoryukenMiddleware do
|
|
105
107
|
let(:body) { 1 }
|
106
108
|
|
107
109
|
it "handles primitive types as arguments" do
|
108
|
-
|
109
|
-
"perform_job.shoryuken",
|
110
|
-
:class => "DemoShoryukenWorker",
|
111
|
-
:method => "perform",
|
112
|
-
:metadata => {
|
113
|
-
:queue => "some-funky-queue-name",
|
114
|
-
"SentTimestamp" => 217_123_200_000
|
115
|
-
},
|
116
|
-
:params => { :params => body },
|
117
|
-
:queue_start => Time.parse("1976-11-18 0:00:00UTC").utc
|
118
|
-
)
|
110
|
+
perform_job
|
119
111
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
end
|
112
|
+
transaction_hash = last_transaction.to_h
|
113
|
+
expect(transaction_hash["sample_data"]).to include(
|
114
|
+
"params" => { "params" => body }
|
115
|
+
)
|
125
116
|
end
|
126
117
|
end
|
127
118
|
end
|
128
119
|
|
129
120
|
context "with exception" do
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
121
|
+
it "sets the exception on the transaction" do
|
122
|
+
expect do
|
123
|
+
expect do
|
124
|
+
perform_job { raise ExampleException, "error message" }
|
125
|
+
end.to raise_error(ExampleException)
|
126
|
+
end.to change { created_transactions.length }.by(1)
|
127
|
+
|
128
|
+
transaction = last_transaction
|
129
|
+
expect(transaction).to be_completed
|
130
|
+
transaction_hash = transaction.to_h
|
131
|
+
expect(transaction_hash).to include(
|
132
|
+
"action" => "DemoShoryukenWorker#perform",
|
133
|
+
"id" => kind_of(String), # AppSignal generated id
|
134
|
+
"namespace" => Appsignal::Transaction::BACKGROUND_JOB,
|
135
|
+
"error" => {
|
136
|
+
"name" => "ExampleException",
|
137
|
+
"message" => "error message",
|
138
|
+
"backtrace" => kind_of(String)
|
139
|
+
}
|
135
140
|
)
|
136
141
|
end
|
142
|
+
end
|
137
143
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
144
|
+
context "with batched jobs" do
|
145
|
+
let(:sqs_msg) do
|
146
|
+
[
|
147
|
+
double(
|
148
|
+
:message_id => "msg2",
|
149
|
+
:attributes => { "SentTimestamp" => (Time.parse("1976-11-18 01:00:00UTC").to_i * 1000).to_s }
|
150
|
+
),
|
151
|
+
double(
|
152
|
+
:message_id => "msg1",
|
153
|
+
:attributes => { "SentTimestamp" => sent_timestamp.to_s }
|
154
|
+
)
|
155
|
+
]
|
146
156
|
end
|
147
|
-
|
148
|
-
|
149
|
-
|
157
|
+
let(:body) do
|
158
|
+
[
|
159
|
+
"foo bar",
|
160
|
+
{ :id => "123", :foo => "Foo", :bar => "Bar" }
|
161
|
+
]
|
150
162
|
end
|
163
|
+
let(:sent_timestamp) { Time.parse("1976-11-18 01:00:00UTC").to_i * 1000 }
|
151
164
|
|
152
|
-
|
165
|
+
it "creates a transaction for the batch" do
|
166
|
+
allow_any_instance_of(Appsignal::Transaction).to receive(:set_queue_start).and_call_original
|
153
167
|
expect do
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
168
|
+
perform_job {}
|
169
|
+
end.to change { created_transactions.length }.by(1)
|
170
|
+
|
171
|
+
transaction = last_transaction
|
172
|
+
expect(transaction).to be_completed
|
173
|
+
transaction_hash = transaction.to_h
|
174
|
+
expect(transaction_hash).to include(
|
175
|
+
"action" => "DemoShoryukenWorker#perform",
|
176
|
+
"id" => kind_of(String), # AppSignal generated id
|
177
|
+
"namespace" => Appsignal::Transaction::BACKGROUND_JOB,
|
178
|
+
"error" => nil
|
179
|
+
)
|
180
|
+
expect(transaction_hash["events"].first).to include(
|
181
|
+
"allocation_count" => kind_of(Integer),
|
182
|
+
"body" => "",
|
183
|
+
"body_format" => Appsignal::EventFormatter::DEFAULT,
|
184
|
+
"child_allocation_count" => kind_of(Integer),
|
185
|
+
"child_duration" => kind_of(Float),
|
186
|
+
"child_gc_duration" => kind_of(Float),
|
187
|
+
"count" => 1,
|
188
|
+
"gc_duration" => kind_of(Float),
|
189
|
+
"start" => kind_of(Float),
|
190
|
+
"duration" => kind_of(Float),
|
191
|
+
"name" => "perform_job.shoryuken",
|
192
|
+
"title" => ""
|
193
|
+
)
|
194
|
+
expect(transaction_hash["sample_data"]).to include(
|
195
|
+
"params" => {
|
196
|
+
"msg2" => "foo bar",
|
197
|
+
"msg1" => { "id" => "123", "foo" => "Foo", "bar" => "Bar" }
|
198
|
+
},
|
199
|
+
"metadata" => {
|
200
|
+
"batch" => true,
|
201
|
+
"queue" => "some-funky-queue-name",
|
202
|
+
"SentTimestamp" => sent_timestamp.to_s # Earliest/oldest timestamp from messages
|
203
|
+
}
|
204
|
+
)
|
205
|
+
# Queue time based on earliest/oldest timestamp from messages
|
206
|
+
expect(transaction).to have_received(:set_queue_start).with(sent_timestamp)
|
160
207
|
end
|
161
208
|
end
|
162
209
|
end
|