appsignal 2.9.17 → 2.10.0
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_todo.yml +0 -6
- data/CHANGELOG.md +24 -0
- data/Rakefile +16 -2
- data/ext/agent.yml +19 -19
- data/lib/appsignal/cli.rb +9 -2
- data/lib/appsignal/cli/diagnose.rb +20 -19
- data/lib/appsignal/cli/helpers.rb +22 -10
- data/lib/appsignal/cli/install.rb +2 -1
- data/lib/appsignal/config.rb +23 -9
- data/lib/appsignal/event_formatter.rb +4 -4
- data/lib/appsignal/minutely.rb +4 -4
- data/lib/appsignal/rack/js_exception_catcher.rb +6 -0
- data/lib/appsignal/transaction.rb +1 -1
- data/lib/appsignal/version.rb +1 -1
- data/spec/lib/appsignal/cli/diagnose_spec.rb +54 -11
- data/spec/lib/appsignal/cli/helpers_spec.rb +11 -3
- data/spec/lib/appsignal/cli/install_spec.rb +30 -1
- data/spec/lib/appsignal/config_spec.rb +78 -7
- data/spec/lib/appsignal/hooks/action_cable_spec.rb +1 -5
- data/spec/lib/appsignal/hooks/rake_spec.rb +41 -39
- data/spec/lib/appsignal/hooks/sidekiq_spec.rb +2 -15
- data/spec/lib/appsignal/integrations/object_spec.rb +2 -2
- data/spec/lib/appsignal/integrations/que_spec.rb +26 -39
- data/spec/lib/appsignal/integrations/resque_active_job_spec.rb +108 -46
- data/spec/lib/appsignal/integrations/resque_spec.rb +40 -39
- data/spec/lib/appsignal/minutely_spec.rb +3 -3
- data/spec/lib/appsignal/rack/js_exception_catcher_spec.rb +19 -5
- data/spec/lib/appsignal/transaction_spec.rb +4 -12
- data/spec/lib/appsignal_spec.rb +7 -8
- data/spec/spec_helper.rb +11 -11
- data/spec/support/fixtures/projects/broken/config/appsignal.yml +1 -0
- data/spec/support/helpers/cli_helpers.rb +15 -1
- data/spec/support/helpers/transaction_helpers.rb +53 -0
- data/spec/support/matchers/be_completed.rb +5 -0
- data/spec/support/matchers/have_colorized_text.rb +28 -0
- data/spec/support/testing.rb +113 -0
- metadata +10 -2
@@ -38,28 +38,15 @@ describe Appsignal::Hooks::SidekiqPlugin, :with_yaml_parse_error => false do
|
|
38
38
|
}
|
39
39
|
end
|
40
40
|
let(:plugin) { Appsignal::Hooks::SidekiqPlugin.new }
|
41
|
-
let(:test_store) { {} }
|
42
41
|
let(:log) { StringIO.new }
|
43
42
|
before do
|
44
43
|
start_agent
|
45
44
|
Appsignal.logger = test_logger(log)
|
46
|
-
|
47
|
-
# Stub calls to extension, because that would remove the transaction
|
48
|
-
# from the extension.
|
49
|
-
allow_any_instance_of(Appsignal::Extension::Transaction).to receive(:finish).and_return(true)
|
50
|
-
allow_any_instance_of(Appsignal::Extension::Transaction).to receive(:complete)
|
51
|
-
|
52
|
-
# Stub removal of current transaction from current thread so we can fetch
|
53
|
-
# it later.
|
54
|
-
expect(Appsignal::Transaction).to receive(:clear_current_transaction!) do
|
55
|
-
transaction = Thread.current[:appsignal_transaction]
|
56
|
-
test_store[:transaction] = transaction if transaction
|
57
|
-
end
|
58
45
|
end
|
46
|
+
around { |example| keep_transactions { example.run } }
|
59
47
|
after :with_yaml_parse_error => false do
|
60
48
|
expect(log_contents(log)).to_not contains_log(:warn, "Unable to load YAML")
|
61
49
|
end
|
62
|
-
after { clear_current_transaction! }
|
63
50
|
|
64
51
|
shared_examples "sidekiq metadata" do
|
65
52
|
describe "internal Sidekiq job values" do
|
@@ -513,7 +500,7 @@ describe Appsignal::Hooks::SidekiqPlugin, :with_yaml_parse_error => false do
|
|
513
500
|
end
|
514
501
|
|
515
502
|
def transaction
|
516
|
-
|
503
|
+
last_transaction
|
517
504
|
end
|
518
505
|
|
519
506
|
def expect_transaction_to_have_sidekiq_event(transaction_hash)
|
@@ -16,8 +16,8 @@ describe Object do
|
|
16
16
|
context "when active" do
|
17
17
|
let(:transaction) { http_request_transaction }
|
18
18
|
before do
|
19
|
-
expect(Appsignal::Transaction).to receive(:current).at_least(:once).and_return(transaction)
|
20
19
|
Appsignal.config = project_fixture_config
|
20
|
+
expect(Appsignal::Transaction).to receive(:current).at_least(:once).and_return(transaction)
|
21
21
|
end
|
22
22
|
after { Appsignal.config = nil }
|
23
23
|
|
@@ -137,9 +137,9 @@ describe Object do
|
|
137
137
|
context "when active" do
|
138
138
|
let(:transaction) { http_request_transaction }
|
139
139
|
before do
|
140
|
+
Appsignal.config = project_fixture_config
|
140
141
|
expect(Appsignal::Transaction).to receive(:current).at_least(:once)
|
141
142
|
.and_return(transaction)
|
142
|
-
Appsignal.config = project_fixture_config
|
143
143
|
end
|
144
144
|
after { Appsignal.config = nil }
|
145
145
|
|
@@ -37,47 +37,30 @@ if DependencyHelper.que_present?
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
let(:instance) { job.new(job_attrs) }
|
40
|
-
let(:transaction) do
|
41
|
-
Appsignal::Transaction.new(
|
42
|
-
SecureRandom.uuid,
|
43
|
-
Appsignal::Transaction::BACKGROUND_JOB,
|
44
|
-
Appsignal::Transaction::GenericRequest.new(env)
|
45
|
-
)
|
46
|
-
end
|
47
40
|
|
48
41
|
before do
|
49
42
|
allow(Que).to receive(:execute)
|
50
43
|
|
51
44
|
start_agent
|
52
45
|
expect(Appsignal.active?).to be_truthy
|
53
|
-
transaction
|
54
|
-
|
55
|
-
expect(Appsignal::Transaction).to receive(:create)
|
56
|
-
.with(
|
57
|
-
kind_of(String),
|
58
|
-
Appsignal::Transaction::BACKGROUND_JOB,
|
59
|
-
kind_of(Appsignal::Transaction::GenericRequest)
|
60
|
-
).and_return(transaction)
|
61
|
-
allow(Appsignal::Transaction).to receive(:current).and_return(transaction)
|
62
|
-
expect(transaction.ext).to receive(:finish).and_return(true)
|
63
|
-
expect(transaction.ext).to receive(:complete)
|
64
46
|
end
|
65
|
-
|
66
|
-
subject { transaction.to_h }
|
47
|
+
around { |example| keep_transactions { example.run } }
|
67
48
|
|
68
49
|
context "success" do
|
69
50
|
it "creates a transaction for a job" do
|
70
51
|
expect do
|
71
52
|
instance._run
|
72
|
-
end.
|
53
|
+
end.to change { created_transactions.length }.by(1)
|
73
54
|
|
74
|
-
expect(
|
55
|
+
expect(last_transaction).to be_completed
|
56
|
+
transaction_hash = last_transaction.to_h
|
57
|
+
expect(transaction_hash).to include(
|
75
58
|
"action" => "MyQueJob#run",
|
76
59
|
"id" => instance_of(String),
|
77
60
|
"namespace" => Appsignal::Transaction::BACKGROUND_JOB
|
78
61
|
)
|
79
|
-
expect(
|
80
|
-
expect(
|
62
|
+
expect(transaction_hash["error"]).to be_nil
|
63
|
+
expect(transaction_hash["events"].first).to include(
|
81
64
|
"allocation_count" => kind_of(Integer),
|
82
65
|
"body" => "",
|
83
66
|
"body_format" => Appsignal::EventFormatter::DEFAULT,
|
@@ -91,7 +74,7 @@ if DependencyHelper.que_present?
|
|
91
74
|
"name" => "perform_job.que",
|
92
75
|
"title" => ""
|
93
76
|
)
|
94
|
-
expect(
|
77
|
+
expect(transaction_hash["sample_data"]).to include(
|
95
78
|
"params" => %w[1 birds],
|
96
79
|
"metadata" => {
|
97
80
|
"attempts" => 0,
|
@@ -107,24 +90,28 @@ if DependencyHelper.que_present?
|
|
107
90
|
context "with exception" do
|
108
91
|
let(:error) { ExampleException.new("oh no!") }
|
109
92
|
|
110
|
-
it "
|
93
|
+
it "reports exceptions and re-raise them" do
|
111
94
|
allow(instance).to receive(:run).and_raise(error)
|
112
95
|
|
113
96
|
expect do
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
97
|
+
expect do
|
98
|
+
instance._run
|
99
|
+
end.to raise_error(ExampleException)
|
100
|
+
end.to change { created_transactions.length }.by(1)
|
101
|
+
|
102
|
+
expect(last_transaction).to be_completed
|
103
|
+
transaction_hash = last_transaction.to_h
|
104
|
+
expect(transaction_hash).to include(
|
118
105
|
"action" => "MyQueJob#run",
|
119
106
|
"id" => instance_of(String),
|
120
107
|
"namespace" => Appsignal::Transaction::BACKGROUND_JOB
|
121
108
|
)
|
122
|
-
expect(
|
109
|
+
expect(transaction_hash["error"]).to include(
|
123
110
|
"backtrace" => kind_of(String),
|
124
111
|
"name" => error.class.name,
|
125
112
|
"message" => error.message
|
126
113
|
)
|
127
|
-
expect(
|
114
|
+
expect(transaction_hash["sample_data"]).to include(
|
128
115
|
"params" => %w[1 birds],
|
129
116
|
"metadata" => {
|
130
117
|
"attempts" => 0,
|
@@ -140,24 +127,24 @@ if DependencyHelper.que_present?
|
|
140
127
|
context "with error" do
|
141
128
|
let(:error) { ExampleStandardError.new("oh no!") }
|
142
129
|
|
143
|
-
it "
|
130
|
+
it "reports errors and not re-raise them" do
|
144
131
|
allow(instance).to receive(:run).and_raise(error)
|
145
132
|
|
146
|
-
expect
|
147
|
-
instance._run
|
148
|
-
end.to_not raise_error
|
133
|
+
expect { instance._run }.to change { created_transactions.length }.by(1)
|
149
134
|
|
150
|
-
expect(
|
135
|
+
expect(last_transaction).to be_completed
|
136
|
+
transaction_hash = last_transaction.to_h
|
137
|
+
expect(transaction_hash).to include(
|
151
138
|
"action" => "MyQueJob#run",
|
152
139
|
"id" => instance_of(String),
|
153
140
|
"namespace" => Appsignal::Transaction::BACKGROUND_JOB
|
154
141
|
)
|
155
|
-
expect(
|
142
|
+
expect(transaction_hash["error"]).to include(
|
156
143
|
"backtrace" => kind_of(String),
|
157
144
|
"name" => error.class.name,
|
158
145
|
"message" => error.message
|
159
146
|
)
|
160
|
-
expect(
|
147
|
+
expect(transaction_hash["sample_data"]).to include(
|
161
148
|
"params" => %w[1 birds],
|
162
149
|
"metadata" => {
|
163
150
|
"attempts" => 0,
|
@@ -17,67 +17,129 @@ if DependencyHelper.resque_present? && DependencyHelper.active_job_present?
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
:method => "perform",
|
25
|
-
:params => ["argument"],
|
26
|
-
:metadata => {
|
27
|
-
:id => kind_of(String),
|
28
|
-
:queue => "default"
|
29
|
-
}
|
30
|
-
)
|
20
|
+
def perform
|
21
|
+
keep_transactions do
|
22
|
+
job.perform_now
|
23
|
+
end
|
31
24
|
end
|
32
25
|
|
33
|
-
context "
|
34
|
-
|
35
|
-
{
|
36
|
-
|
37
|
-
|
38
|
-
|
26
|
+
context "without error" do
|
27
|
+
it "creates a new transaction" do
|
28
|
+
expect { perform }.to change { created_transactions.length }.by(1)
|
29
|
+
|
30
|
+
expect(last_transaction.to_h).to include(
|
31
|
+
"namespace" => Appsignal::Transaction::BACKGROUND_JOB,
|
32
|
+
"action" => "TestActiveJob#perform",
|
33
|
+
"error" => nil,
|
34
|
+
"events" => [
|
35
|
+
hash_including(
|
36
|
+
"name" => "perform_job.resque",
|
37
|
+
"title" => "",
|
38
|
+
"body" => "",
|
39
|
+
"body_format" => Appsignal::EventFormatter::DEFAULT,
|
40
|
+
"count" => 1,
|
41
|
+
"duration" => kind_of(Float)
|
42
|
+
)
|
43
|
+
],
|
44
|
+
"sample_data" => hash_including(
|
45
|
+
"params" => ["argument"],
|
46
|
+
"metadata" => {
|
47
|
+
"id" => kind_of(String),
|
48
|
+
"queue" => "default"
|
49
|
+
}
|
50
|
+
)
|
51
|
+
)
|
39
52
|
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "with error" do
|
56
|
+
let(:job) do
|
57
|
+
class BrokenTestActiveJob < ActiveJob::Base
|
58
|
+
include Appsignal::Integrations::ResqueActiveJobPlugin
|
40
59
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
60
|
+
def perform(_)
|
61
|
+
raise ExampleException, "my error message"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
BrokenTestActiveJob.new(args)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "creates a new transaction with an error" do
|
69
|
+
expect do
|
70
|
+
expect { perform }.to raise_error(ExampleException, "my error message")
|
71
|
+
end.to change { created_transactions.length }.by(1)
|
72
|
+
|
73
|
+
expect(last_transaction.to_h).to include(
|
74
|
+
"namespace" => Appsignal::Transaction::BACKGROUND_JOB,
|
75
|
+
"action" => "BrokenTestActiveJob#perform",
|
76
|
+
"error" => {
|
77
|
+
"name" => "ExampleException",
|
78
|
+
"message" => "my error message",
|
79
|
+
"backtrace" => kind_of(String)
|
80
|
+
},
|
81
|
+
"sample_data" => hash_including(
|
82
|
+
"params" => ["argument"],
|
83
|
+
"metadata" => {
|
84
|
+
"id" => kind_of(String),
|
85
|
+
"queue" => "default"
|
86
|
+
}
|
87
|
+
)
|
88
|
+
)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "with complex arguments" do
|
93
|
+
context "with too long values" do
|
94
|
+
let(:args) do
|
95
|
+
{
|
47
96
|
:foo => "Foo",
|
48
|
-
:bar => "
|
49
|
-
],
|
50
|
-
:metadata => {
|
51
|
-
:id => kind_of(String),
|
52
|
-
:queue => "default"
|
97
|
+
:bar => "a" * 2001
|
53
98
|
}
|
54
|
-
|
99
|
+
end
|
100
|
+
|
101
|
+
it "truncates large argument values" do
|
102
|
+
perform
|
103
|
+
expect(last_transaction.to_h).to include(
|
104
|
+
"namespace" => Appsignal::Transaction::BACKGROUND_JOB,
|
105
|
+
"action" => "TestActiveJob#perform",
|
106
|
+
"error" => nil,
|
107
|
+
"sample_data" => hash_including(
|
108
|
+
"params" => ["foo" => "Foo", "bar" => "#{"a" * 2000}..."],
|
109
|
+
"metadata" => {
|
110
|
+
"id" => kind_of(String),
|
111
|
+
"queue" => "default"
|
112
|
+
}
|
113
|
+
)
|
114
|
+
)
|
115
|
+
end
|
55
116
|
end
|
56
117
|
|
57
118
|
context "with parameter filtering" do
|
58
|
-
|
59
|
-
|
60
|
-
|
119
|
+
let(:args) do
|
120
|
+
{
|
121
|
+
:foo => "Foo",
|
122
|
+
:bar => "Bar"
|
123
|
+
}
|
61
124
|
end
|
125
|
+
before { Appsignal.config[:filter_parameters] = ["foo"] }
|
62
126
|
|
63
127
|
it "filters selected arguments" do
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
128
|
+
perform
|
129
|
+
expect(last_transaction.to_h).to include(
|
130
|
+
"namespace" => Appsignal::Transaction::BACKGROUND_JOB,
|
131
|
+
"action" => "TestActiveJob#perform",
|
132
|
+
"error" => nil,
|
133
|
+
"sample_data" => hash_including(
|
134
|
+
"params" => ["foo" => "[FILTERED]", "bar" => "Bar"],
|
135
|
+
"metadata" => {
|
136
|
+
"id" => kind_of(String),
|
137
|
+
"queue" => "default"
|
138
|
+
}
|
139
|
+
)
|
76
140
|
)
|
77
141
|
end
|
78
142
|
end
|
79
143
|
end
|
80
|
-
|
81
|
-
after { job.perform_now }
|
82
144
|
end
|
83
145
|
end
|
@@ -18,65 +18,66 @@ if DependencyHelper.resque_present?
|
|
18
18
|
extend Appsignal::Integrations::ResquePlugin
|
19
19
|
|
20
20
|
def self.perform
|
21
|
-
raise ExampleException
|
21
|
+
raise ExampleException, "my error message"
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
26
|
describe :around_perform_resque_plugin do
|
27
|
-
let(:transaction) { Appsignal::Transaction.new("1", "background", {}, {}) }
|
28
27
|
let(:job) { ::Resque::Job.new("default", "class" => "TestJob") }
|
29
|
-
before
|
30
|
-
allow(transaction).to receive(:complete).and_return(true)
|
31
|
-
allow(Appsignal::Transaction).to receive(:current).and_return(transaction)
|
32
|
-
expect(Appsignal).to receive(:stop)
|
33
|
-
end
|
28
|
+
before { expect(Appsignal).to receive(:stop) }
|
34
29
|
|
35
30
|
context "without exception" do
|
36
31
|
it "creates a new transaction" do
|
37
|
-
expect
|
38
|
-
|
32
|
+
expect do
|
33
|
+
keep_transactions { job.perform }
|
34
|
+
end.to change { created_transactions.length }.by(1)
|
39
35
|
|
40
|
-
|
41
|
-
expect(
|
42
|
-
"
|
43
|
-
|
44
|
-
|
36
|
+
expect(last_transaction).to be_completed
|
37
|
+
expect(last_transaction.to_h).to include(
|
38
|
+
"namespace" => Appsignal::Transaction::BACKGROUND_JOB,
|
39
|
+
"action" => "TestJob#perform",
|
40
|
+
"error" => nil,
|
41
|
+
"events" => [
|
42
|
+
hash_including(
|
43
|
+
"name" => "perform_job.resque",
|
44
|
+
"title" => "",
|
45
|
+
"body" => "",
|
46
|
+
"body_format" => Appsignal::EventFormatter::DEFAULT,
|
47
|
+
"count" => 1,
|
48
|
+
"duration" => kind_of(Float)
|
49
|
+
)
|
50
|
+
]
|
45
51
|
)
|
46
52
|
end
|
47
|
-
|
48
|
-
it "closes the transaction" do
|
49
|
-
expect(transaction).to receive(:complete)
|
50
|
-
end
|
51
|
-
|
52
|
-
after { job.perform }
|
53
53
|
end
|
54
54
|
|
55
55
|
context "with exception" do
|
56
56
|
let(:job) { ::Resque::Job.new("default", "class" => "BrokenTestJob") }
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
before do
|
65
|
-
allow(Appsignal::Transaction).to receive(:current).and_return(transaction)
|
66
|
-
expect(Appsignal::Transaction).to receive(:create)
|
67
|
-
.with(
|
68
|
-
kind_of(String),
|
69
|
-
Appsignal::Transaction::BACKGROUND_JOB,
|
70
|
-
kind_of(Appsignal::Transaction::GenericRequest)
|
71
|
-
).and_return(transaction)
|
57
|
+
|
58
|
+
def perform
|
59
|
+
keep_transactions do
|
60
|
+
expect do
|
61
|
+
job.perform
|
62
|
+
end.to raise_error(ExampleException, "my error message")
|
63
|
+
end
|
72
64
|
end
|
73
65
|
|
74
66
|
it "sets the exception on the transaction" do
|
75
|
-
expect
|
76
|
-
|
67
|
+
expect do
|
68
|
+
perform
|
69
|
+
end.to change { created_transactions.length }.by(1)
|
77
70
|
|
78
|
-
|
79
|
-
expect
|
71
|
+
expect(last_transaction).to be_completed
|
72
|
+
expect(last_transaction.to_h).to include(
|
73
|
+
"namespace" => Appsignal::Transaction::BACKGROUND_JOB,
|
74
|
+
"action" => "BrokenTestJob#perform",
|
75
|
+
"error" => {
|
76
|
+
"name" => "ExampleException",
|
77
|
+
"message" => "my error message",
|
78
|
+
"backtrace" => kind_of(String)
|
79
|
+
}
|
80
|
+
)
|
80
81
|
end
|
81
82
|
end
|
82
83
|
end
|