appsignal 3.9.3-java → 3.11.0-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/.github/workflows/ci.yml +22 -19
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +180 -0
- data/Gemfile +1 -0
- data/README.md +0 -1
- data/Rakefile +1 -1
- data/benchmark.rake +99 -42
- data/build_matrix.yml +10 -12
- data/gemfiles/webmachine1.gemfile +5 -4
- data/lib/appsignal/cli/demo.rb +0 -1
- data/lib/appsignal/config.rb +57 -97
- data/lib/appsignal/demo.rb +15 -20
- data/lib/appsignal/environment.rb +6 -1
- data/lib/appsignal/event_formatter/rom/sql_formatter.rb +1 -0
- data/lib/appsignal/event_formatter.rb +3 -2
- data/lib/appsignal/helpers/instrumentation.rb +490 -16
- data/lib/appsignal/hooks/action_cable.rb +21 -16
- data/lib/appsignal/hooks/active_job.rb +15 -14
- data/lib/appsignal/hooks/delayed_job.rb +1 -1
- data/lib/appsignal/hooks/shoryuken.rb +3 -63
- data/lib/appsignal/integrations/action_cable.rb +5 -7
- data/lib/appsignal/integrations/active_support_notifications.rb +1 -0
- data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +36 -35
- data/lib/appsignal/integrations/data_mapper.rb +1 -0
- data/lib/appsignal/integrations/delayed_job_plugin.rb +27 -33
- data/lib/appsignal/integrations/dry_monitor.rb +1 -0
- data/lib/appsignal/integrations/excon.rb +1 -0
- data/lib/appsignal/integrations/http.rb +1 -0
- data/lib/appsignal/integrations/net_http.rb +1 -0
- data/lib/appsignal/integrations/object.rb +6 -0
- data/lib/appsignal/integrations/padrino.rb +21 -25
- data/lib/appsignal/integrations/que.rb +13 -20
- data/lib/appsignal/integrations/railtie.rb +1 -1
- data/lib/appsignal/integrations/rake.rb +45 -15
- data/lib/appsignal/integrations/redis.rb +1 -0
- data/lib/appsignal/integrations/redis_client.rb +1 -0
- data/lib/appsignal/integrations/resque.rb +2 -5
- data/lib/appsignal/integrations/shoryuken.rb +75 -0
- data/lib/appsignal/integrations/sidekiq.rb +7 -25
- data/lib/appsignal/integrations/unicorn.rb +1 -0
- data/lib/appsignal/integrations/webmachine.rb +12 -9
- data/lib/appsignal/logger.rb +7 -3
- data/lib/appsignal/probes/helpers.rb +1 -0
- data/lib/appsignal/probes/mri.rb +1 -0
- data/lib/appsignal/probes/sidekiq.rb +1 -0
- data/lib/appsignal/probes.rb +3 -0
- data/lib/appsignal/rack/abstract_middleware.rb +67 -24
- data/lib/appsignal/rack/body_wrapper.rb +143 -0
- data/lib/appsignal/rack/event_handler.rb +39 -8
- data/lib/appsignal/rack/generic_instrumentation.rb +6 -4
- data/lib/appsignal/rack/grape_middleware.rb +3 -2
- data/lib/appsignal/rack/hanami_middleware.rb +1 -1
- data/lib/appsignal/rack/instrumentation_middleware.rb +62 -0
- data/lib/appsignal/rack/rails_instrumentation.rb +1 -3
- data/lib/appsignal/rack/sinatra_instrumentation.rb +1 -3
- data/lib/appsignal/rack/streaming_listener.rb +14 -59
- data/lib/appsignal/rack.rb +60 -0
- data/lib/appsignal/span.rb +1 -0
- data/lib/appsignal/transaction.rb +353 -104
- data/lib/appsignal/utils/data.rb +0 -1
- data/lib/appsignal/utils/hash_sanitizer.rb +0 -1
- data/lib/appsignal/utils/integration_logger.rb +0 -13
- data/lib/appsignal/utils/integration_memory_logger.rb +0 -13
- data/lib/appsignal/utils/json.rb +0 -1
- data/lib/appsignal/utils/query_params_sanitizer.rb +0 -1
- data/lib/appsignal/utils/stdout_and_logger_message.rb +0 -1
- data/lib/appsignal/utils.rb +6 -0
- data/lib/appsignal/version.rb +1 -1
- data/lib/appsignal.rb +9 -6
- data/spec/lib/appsignal/capistrano2_spec.rb +1 -1
- data/spec/lib/appsignal/config_spec.rb +139 -43
- data/spec/lib/appsignal/hooks/action_cable_spec.rb +43 -74
- data/spec/lib/appsignal/hooks/activejob_spec.rb +9 -0
- data/spec/lib/appsignal/hooks/delayed_job_spec.rb +2 -443
- data/spec/lib/appsignal/hooks/rake_spec.rb +100 -17
- data/spec/lib/appsignal/hooks/shoryuken_spec.rb +0 -171
- data/spec/lib/appsignal/integrations/delayed_job_plugin_spec.rb +459 -0
- data/spec/lib/appsignal/integrations/padrino_spec.rb +181 -131
- data/spec/lib/appsignal/integrations/que_spec.rb +3 -4
- data/spec/lib/appsignal/integrations/shoryuken_spec.rb +167 -0
- data/spec/lib/appsignal/integrations/sidekiq_spec.rb +4 -4
- data/spec/lib/appsignal/integrations/sinatra_spec.rb +10 -2
- data/spec/lib/appsignal/integrations/webmachine_spec.rb +77 -17
- data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +144 -11
- data/spec/lib/appsignal/rack/body_wrapper_spec.rb +263 -0
- data/spec/lib/appsignal/rack/event_handler_spec.rb +81 -10
- data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +70 -17
- data/spec/lib/appsignal/rack/grape_middleware_spec.rb +1 -1
- data/spec/lib/appsignal/rack/instrumentation_middleware_spec.rb +38 -0
- data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +4 -2
- data/spec/lib/appsignal/rack/streaming_listener_spec.rb +43 -120
- data/spec/lib/appsignal/rack_spec.rb +63 -0
- data/spec/lib/appsignal/transaction_spec.rb +1675 -953
- data/spec/lib/appsignal/utils/integration_logger_spec.rb +12 -16
- data/spec/lib/appsignal/utils/integration_memory_logger_spec.rb +0 -10
- data/spec/lib/appsignal_spec.rb +517 -13
- data/spec/support/helpers/transaction_helpers.rb +44 -20
- data/spec/support/matchers/transaction.rb +15 -1
- data/spec/support/mocks/dummy_app.rb +1 -1
- data/spec/support/testing.rb +1 -1
- metadata +12 -4
- data/support/check_versions +0 -22
|
@@ -1,132 +1,211 @@
|
|
|
1
1
|
describe Appsignal::Transaction do
|
|
2
|
-
|
|
3
|
-
start_agent
|
|
4
|
-
end
|
|
5
|
-
|
|
6
|
-
let(:transaction_id) { "1" }
|
|
7
|
-
let(:time) { Time.at(fixed_time) }
|
|
8
|
-
let(:namespace) { Appsignal::Transaction::HTTP_REQUEST }
|
|
9
|
-
let(:env) { {} }
|
|
10
|
-
let(:merged_env) { http_request_env_with_data(env) }
|
|
11
|
-
let(:options) { {} }
|
|
12
|
-
let(:request) { Rack::Request.new(merged_env) }
|
|
13
|
-
let(:transaction) { Appsignal::Transaction.new(transaction_id, namespace, request, options) }
|
|
14
|
-
let(:log) { StringIO.new }
|
|
2
|
+
let(:time) { Time.at(fixed_time) }
|
|
15
3
|
|
|
16
4
|
before { Timecop.freeze(time) }
|
|
17
5
|
after { Timecop.return }
|
|
18
6
|
around do |example|
|
|
19
|
-
|
|
7
|
+
start_agent
|
|
8
|
+
keep_transactions do
|
|
20
9
|
example.run
|
|
21
10
|
end
|
|
22
11
|
end
|
|
23
12
|
|
|
24
|
-
describe "
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
13
|
+
describe ".create" do
|
|
14
|
+
context "when no transaction is running" do
|
|
15
|
+
it "returns the created transaction" do
|
|
16
|
+
mock_transaction_id = "mock-uuid"
|
|
17
|
+
allow(SecureRandom).to receive(:uuid).and_return(mock_transaction_id)
|
|
18
|
+
|
|
19
|
+
transaction = create_transaction
|
|
20
|
+
expect(transaction).to be_a Appsignal::Transaction
|
|
28
21
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
22
|
+
expect(transaction).to have_id(mock_transaction_id)
|
|
23
|
+
expect(transaction.transaction_id).to eq(mock_transaction_id)
|
|
24
|
+
|
|
25
|
+
expect(transaction).to have_namespace(default_namespace)
|
|
26
|
+
expect(transaction.namespace).to eq(default_namespace)
|
|
32
27
|
end
|
|
33
28
|
|
|
34
|
-
|
|
35
|
-
|
|
29
|
+
it "assigns the transaction to current" do
|
|
30
|
+
transaction = create_transaction
|
|
31
|
+
expect(transaction).to eq current_transaction
|
|
32
|
+
end
|
|
36
33
|
|
|
34
|
+
context "with legacy arguments" do
|
|
37
35
|
it "returns the created transaction" do
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
transaction_id = "mock-id"
|
|
37
|
+
namespace = "my_namespace"
|
|
38
|
+
transaction = legacy_create_transaction(
|
|
39
|
+
:id => transaction_id,
|
|
40
|
+
:namespace => namespace
|
|
41
|
+
)
|
|
42
|
+
expect(transaction).to be_a(Appsignal::Transaction)
|
|
42
43
|
|
|
43
44
|
expect(transaction).to have_id(transaction_id)
|
|
45
|
+
expect(transaction.transaction_id).to eq(transaction_id)
|
|
46
|
+
|
|
44
47
|
expect(transaction).to have_namespace(namespace)
|
|
48
|
+
expect(transaction.namespace).to eq(namespace)
|
|
45
49
|
end
|
|
46
50
|
|
|
47
|
-
it "
|
|
48
|
-
|
|
51
|
+
it "logs deprecation warnings" do
|
|
52
|
+
logs =
|
|
53
|
+
capture_logs do
|
|
54
|
+
legacy_create_transaction(
|
|
55
|
+
:id => "mock-id",
|
|
56
|
+
:namespace => "my_namespace",
|
|
57
|
+
:request => Appsignal::Transaction::InternalGenericRequest.new({}),
|
|
58
|
+
:options => { :force => true }
|
|
59
|
+
)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
expect(logs).to contains_log(
|
|
63
|
+
:warn,
|
|
64
|
+
"Appsignal::Transaction.create: " \
|
|
65
|
+
"A new Transaction is created using the transaction ID argument."
|
|
66
|
+
)
|
|
67
|
+
expect(logs).to contains_log(
|
|
68
|
+
:warn,
|
|
69
|
+
"Appsignal::Transaction.create: " \
|
|
70
|
+
"A Transaction is created using the namespace argument."
|
|
71
|
+
)
|
|
72
|
+
expect(logs).to contains_log(
|
|
73
|
+
:warn,
|
|
74
|
+
"Appsignal::Transaction.create: " \
|
|
75
|
+
"A Transaction is created using the request argument."
|
|
76
|
+
)
|
|
77
|
+
expect(logs).to contains_log(
|
|
78
|
+
:warn,
|
|
79
|
+
"Appsignal::Transaction.create: " \
|
|
80
|
+
"A Transaction is created using the `:force => true` option argument. "
|
|
81
|
+
)
|
|
49
82
|
end
|
|
50
|
-
end
|
|
51
83
|
|
|
52
|
-
|
|
53
|
-
|
|
84
|
+
it "prints deprecation warnings" do
|
|
85
|
+
err_stream = std_stream
|
|
86
|
+
capture_std_streams(std_stream, err_stream) do
|
|
87
|
+
legacy_create_transaction(
|
|
88
|
+
:id => "mock-id",
|
|
89
|
+
:namespace => "my_namespace",
|
|
90
|
+
:request => Appsignal::Transaction::InternalGenericRequest.new({}),
|
|
91
|
+
:options => { :force => true }
|
|
92
|
+
)
|
|
93
|
+
end
|
|
54
94
|
|
|
55
|
-
|
|
56
|
-
expect
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
95
|
+
stderr = err_stream.read
|
|
96
|
+
expect(stderr).to include(
|
|
97
|
+
"appsignal WARNING: Appsignal::Transaction.create: " \
|
|
98
|
+
"A new Transaction is created using the transaction ID argument."
|
|
99
|
+
)
|
|
100
|
+
expect(stderr).to include(
|
|
101
|
+
"appsignal WARNING: Appsignal::Transaction.create: " \
|
|
102
|
+
"A Transaction is created using the namespace argument."
|
|
103
|
+
)
|
|
104
|
+
expect(stderr).to include(
|
|
105
|
+
"appsignal WARNING: Appsignal::Transaction.create: " \
|
|
106
|
+
"A Transaction is created using the request argument."
|
|
107
|
+
)
|
|
108
|
+
expect(stderr).to include(
|
|
109
|
+
"appsignal WARNING: Appsignal::Transaction.create: " \
|
|
110
|
+
"A Transaction is created using the `:force => true` option argument. "
|
|
111
|
+
)
|
|
61
112
|
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
62
115
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
116
|
+
context "when a transaction is already running" do
|
|
117
|
+
before do
|
|
118
|
+
allow(SecureRandom).to receive(:uuid)
|
|
119
|
+
.and_return(
|
|
120
|
+
"transaction_id_1",
|
|
121
|
+
"transaction_id_2"
|
|
122
|
+
)
|
|
123
|
+
create_transaction
|
|
124
|
+
end
|
|
70
125
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
expect(original_transaction).to_not be_nil
|
|
75
|
-
expect(current_transaction.transaction_id).to eq transaction_id
|
|
126
|
+
it "does not create a new transaction, but returns the current transaction" do
|
|
127
|
+
expect do
|
|
128
|
+
new_transaction = create_transaction
|
|
76
129
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
130
|
+
expect(new_transaction).to eq(current_transaction)
|
|
131
|
+
end.to_not(change { current_transaction })
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it "logs a debug message" do
|
|
135
|
+
logs = capture_logs { create_transaction }
|
|
136
|
+
|
|
137
|
+
expect(logs).to contains_log :warn,
|
|
138
|
+
"Trying to start new transaction with id 'transaction_id_2', but a " \
|
|
139
|
+
"transaction with id 'transaction_id_1' is already " \
|
|
140
|
+
"running. Using transaction 'transaction_id_1'."
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
context "with option :force => true" do
|
|
144
|
+
it "returns the newly created (and current) transaction" do
|
|
145
|
+
original_transaction = create_transaction
|
|
146
|
+
|
|
147
|
+
expect(original_transaction).to be_a(Appsignal::Transaction)
|
|
148
|
+
expect(current_transaction).to have_id("transaction_id_1")
|
|
149
|
+
|
|
150
|
+
new_transaction = legacy_create_transaction(
|
|
151
|
+
:id => "transaction_id_2",
|
|
152
|
+
:options => { :force => true }
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
expect(new_transaction).to be_a(Appsignal::Transaction)
|
|
156
|
+
expect(new_transaction).to_not eq(original_transaction)
|
|
157
|
+
expect(new_transaction).to have_id("transaction_id_2")
|
|
158
|
+
expect(current_transaction).to eq(new_transaction)
|
|
81
159
|
end
|
|
82
160
|
end
|
|
83
161
|
end
|
|
162
|
+
end
|
|
84
163
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
Appsignal::Transaction.create(transaction_id, namespace, request, options)
|
|
89
|
-
end
|
|
164
|
+
describe ".current" do
|
|
165
|
+
context "when there is a current transaction" do
|
|
166
|
+
let!(:transaction) { create_transaction }
|
|
90
167
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
168
|
+
it "reads :appsignal_transaction from the current Thread" do
|
|
169
|
+
expect(current_transaction).to eq(Thread.current[:appsignal_transaction])
|
|
170
|
+
expect(current_transaction).to eq(transaction)
|
|
171
|
+
end
|
|
95
172
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
173
|
+
it "is not a NilTransaction" do
|
|
174
|
+
expect(current_transaction.nil_transaction?).to be(false)
|
|
175
|
+
expect(current_transaction).to be_a(Appsignal::Transaction)
|
|
176
|
+
end
|
|
100
177
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
end
|
|
178
|
+
it "returns true for current?" do
|
|
179
|
+
expect(Appsignal::Transaction.current?).to be(true)
|
|
104
180
|
end
|
|
181
|
+
end
|
|
105
182
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
183
|
+
context "when there is no current transaction" do
|
|
184
|
+
it "has no :appsignal_transaction registered on the current Thread" do
|
|
185
|
+
expect(Thread.current[:appsignal_transaction]).to be_nil
|
|
186
|
+
end
|
|
110
187
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
188
|
+
it "returns a NilTransaction stub" do
|
|
189
|
+
expect(current_transaction.nil_transaction?).to be(true)
|
|
190
|
+
expect(current_transaction).to be_a(Appsignal::Transaction::NilTransaction)
|
|
191
|
+
end
|
|
115
192
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
end
|
|
193
|
+
it "returns false for current?" do
|
|
194
|
+
expect(Appsignal::Transaction.current?).to be(false)
|
|
119
195
|
end
|
|
120
196
|
end
|
|
197
|
+
end
|
|
121
198
|
|
|
122
|
-
|
|
123
|
-
|
|
199
|
+
describe ".complete_current!" do
|
|
200
|
+
context "with active transaction" do
|
|
201
|
+
let!(:transaction) { create_transaction }
|
|
124
202
|
|
|
125
203
|
it "completes the current transaction" do
|
|
126
|
-
expect(transaction).to eq
|
|
127
|
-
expect(transaction).to receive(:complete).and_call_original
|
|
204
|
+
expect(transaction).to eq(current_transaction)
|
|
128
205
|
|
|
129
206
|
Appsignal::Transaction.complete_current!
|
|
207
|
+
|
|
208
|
+
expect(transaction).to be_completed
|
|
130
209
|
end
|
|
131
210
|
|
|
132
211
|
it "unsets the current transaction on the current Thread" do
|
|
@@ -141,8 +220,11 @@ describe Appsignal::Transaction do
|
|
|
141
220
|
end
|
|
142
221
|
|
|
143
222
|
it "logs an error message" do
|
|
144
|
-
|
|
145
|
-
|
|
223
|
+
logs =
|
|
224
|
+
capture_logs do
|
|
225
|
+
Appsignal::Transaction.complete_current!
|
|
226
|
+
end
|
|
227
|
+
expect(logs).to contains_log :error,
|
|
146
228
|
"Failed to complete transaction ##{transaction.transaction_id}. ExampleStandardError"
|
|
147
229
|
end
|
|
148
230
|
|
|
@@ -153,9 +235,19 @@ describe Appsignal::Transaction do
|
|
|
153
235
|
end
|
|
154
236
|
end
|
|
155
237
|
end
|
|
238
|
+
|
|
239
|
+
context "without active transaction" do
|
|
240
|
+
it "does nothing" do
|
|
241
|
+
expect do
|
|
242
|
+
Appsignal::Transaction.complete_current!
|
|
243
|
+
end.to_not(change { Thread.current[:appsignal_transaction] })
|
|
244
|
+
end
|
|
245
|
+
end
|
|
156
246
|
end
|
|
157
247
|
|
|
158
248
|
describe "#complete" do
|
|
249
|
+
let(:transaction) { create_transaction }
|
|
250
|
+
|
|
159
251
|
context "when transaction is being sampled" do
|
|
160
252
|
it "samples data" do
|
|
161
253
|
transaction.set_tags(:foo => "bar")
|
|
@@ -183,11 +275,12 @@ describe Appsignal::Transaction do
|
|
|
183
275
|
end
|
|
184
276
|
|
|
185
277
|
it "logs a debug message" do
|
|
278
|
+
allow(SecureRandom).to receive(:uuid).and_return("mock_transaction_id")
|
|
186
279
|
transaction.discard!
|
|
187
|
-
transaction.complete
|
|
280
|
+
logs = capture_logs { transaction.complete }
|
|
188
281
|
|
|
189
|
-
expect(
|
|
190
|
-
"Skipping transaction '
|
|
282
|
+
expect(logs).to contains_log :debug,
|
|
283
|
+
"Skipping transaction 'mock_transaction_id' because it was manually discarded."
|
|
191
284
|
end
|
|
192
285
|
|
|
193
286
|
context "when a discarded transaction is restored" do
|
|
@@ -207,6 +300,8 @@ describe Appsignal::Transaction do
|
|
|
207
300
|
end
|
|
208
301
|
|
|
209
302
|
context "pausing" do
|
|
303
|
+
let(:transaction) { new_transaction }
|
|
304
|
+
|
|
210
305
|
describe "#pause!" do
|
|
211
306
|
it "changes the pause flag to true" do
|
|
212
307
|
expect do
|
|
@@ -242,834 +337,1439 @@ describe Appsignal::Transaction do
|
|
|
242
337
|
end
|
|
243
338
|
end
|
|
244
339
|
|
|
245
|
-
context "
|
|
246
|
-
|
|
247
|
-
it "loads the AppSignal extension" do
|
|
248
|
-
expect(transaction.ext).to_not be_nil
|
|
249
|
-
end
|
|
340
|
+
context "initialization" do
|
|
341
|
+
let(:transaction) { new_transaction }
|
|
250
342
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
end
|
|
343
|
+
it "loads the AppSignal extension" do
|
|
344
|
+
expect(transaction.ext).to_not be_nil
|
|
345
|
+
end
|
|
255
346
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
transaction.finish_event(
|
|
260
|
-
"name",
|
|
261
|
-
"title",
|
|
262
|
-
"body",
|
|
263
|
-
Appsignal::EventFormatter::DEFAULT
|
|
264
|
-
)
|
|
265
|
-
end
|
|
347
|
+
context "when extension is not loaded", :extension_installation_failure do
|
|
348
|
+
around do |example|
|
|
349
|
+
Appsignal::Testing.without_testing { example.run }
|
|
266
350
|
end
|
|
267
351
|
|
|
268
|
-
it "
|
|
269
|
-
expect(transaction.
|
|
352
|
+
it "does not error on missing extension method calls" do
|
|
353
|
+
expect(transaction.ext).to be_kind_of(Appsignal::Extension::MockTransaction)
|
|
354
|
+
transaction.start_event
|
|
355
|
+
transaction.finish_event(
|
|
356
|
+
"name",
|
|
357
|
+
"title",
|
|
358
|
+
"body",
|
|
359
|
+
Appsignal::EventFormatter::DEFAULT
|
|
360
|
+
)
|
|
270
361
|
end
|
|
362
|
+
end
|
|
271
363
|
|
|
272
|
-
|
|
273
|
-
|
|
364
|
+
context "transaction id" do
|
|
365
|
+
before do
|
|
366
|
+
allow(SecureRandom).to receive(:uuid).and_return("mock_transaction_id")
|
|
274
367
|
end
|
|
275
368
|
|
|
276
|
-
it "sets the
|
|
277
|
-
expect(transaction
|
|
369
|
+
it "sets the transaction id" do
|
|
370
|
+
expect(transaction).to have_id("mock_transaction_id")
|
|
278
371
|
end
|
|
372
|
+
end
|
|
279
373
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
374
|
+
it "sets the namespace to http_request" do
|
|
375
|
+
expect(transaction.namespace).to eq "http_request"
|
|
376
|
+
end
|
|
283
377
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
378
|
+
it "sets the request" do
|
|
379
|
+
expect(transaction.request).to be_a(Appsignal::Transaction::InternalGenericRequest)
|
|
380
|
+
end
|
|
287
381
|
|
|
288
|
-
|
|
289
|
-
|
|
382
|
+
it "sets the request not to paused" do
|
|
383
|
+
expect(transaction.paused?).to be_falsy
|
|
384
|
+
end
|
|
290
385
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
386
|
+
it "sets no tags by default" do
|
|
387
|
+
expect(transaction.tags).to be_empty
|
|
388
|
+
end
|
|
294
389
|
|
|
295
|
-
|
|
296
|
-
|
|
390
|
+
describe "#options" do
|
|
391
|
+
let(:options) { transaction.options }
|
|
297
392
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
393
|
+
it "sets the default :params_method" do
|
|
394
|
+
expect(options[:params_method]).to eq :params
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
context "with overridden options" do
|
|
398
|
+
let(:transaction) do
|
|
399
|
+
legacy_new_transaction(:options => { :params_method => :filtered_params })
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
it "sets the overridden :params_method" do
|
|
403
|
+
expect(options[:params_method]).to eq :filtered_params
|
|
301
404
|
end
|
|
302
405
|
end
|
|
303
406
|
end
|
|
407
|
+
end
|
|
304
408
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
409
|
+
describe "#store" do
|
|
410
|
+
let(:transaction) { new_transaction }
|
|
411
|
+
|
|
412
|
+
it "returns an empty store when it's not already present" do
|
|
413
|
+
expect(transaction.store("test")).to eql({})
|
|
414
|
+
end
|
|
309
415
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
416
|
+
it "stores changes to the store" do
|
|
417
|
+
transaction_store = transaction.store("test")
|
|
418
|
+
transaction_store["transaction"] = "value"
|
|
313
419
|
|
|
314
|
-
|
|
315
|
-
end
|
|
420
|
+
expect(transaction.store("test")).to eql("transaction" => "value")
|
|
316
421
|
end
|
|
422
|
+
end
|
|
317
423
|
|
|
318
|
-
|
|
319
|
-
|
|
424
|
+
describe "#params" do
|
|
425
|
+
let(:transaction) { new_transaction }
|
|
426
|
+
let(:params) { transaction.params }
|
|
320
427
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
428
|
+
context "with custom params set on transaction" do
|
|
429
|
+
before { transaction.set_params(:foo => "bar") }
|
|
430
|
+
|
|
431
|
+
it "returns custom parameters" do
|
|
432
|
+
expect(params).to eq(:foo => "bar")
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
context "when params is a callable object" do
|
|
436
|
+
it "calls the params object and sets the return value as parametesr" do
|
|
437
|
+
transaction.set_params { { "param1" => "value1" } }
|
|
325
438
|
|
|
326
|
-
|
|
327
|
-
expect(subject).to eq(:foo => "bar")
|
|
439
|
+
expect(params).to eq("param1" => "value1")
|
|
328
440
|
end
|
|
329
441
|
end
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
context "without custom params set on transaction" do
|
|
445
|
+
let(:transaction) do
|
|
446
|
+
legacy_new_transaction(
|
|
447
|
+
:request => legacy_request(
|
|
448
|
+
:params => {
|
|
449
|
+
"action" => "show",
|
|
450
|
+
"controller" => "blog_posts",
|
|
451
|
+
"id" => "1"
|
|
330
452
|
|
|
331
|
-
|
|
332
|
-
it "returns parameters from request" do
|
|
333
|
-
expect(subject).to eq(
|
|
334
|
-
"action" => "show",
|
|
335
|
-
"controller" => "blog_posts",
|
|
336
|
-
"id" => "1"
|
|
453
|
+
}
|
|
337
454
|
)
|
|
338
|
-
|
|
455
|
+
)
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
it "returns parameters from request" do
|
|
459
|
+
expect(params).to eq(
|
|
460
|
+
"action" => "show",
|
|
461
|
+
"controller" => "blog_posts",
|
|
462
|
+
"id" => "1"
|
|
463
|
+
)
|
|
339
464
|
end
|
|
340
465
|
end
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
describe "#params=" do
|
|
469
|
+
let(:transaction) { new_transaction }
|
|
470
|
+
|
|
471
|
+
it "sets params on the transaction" do
|
|
472
|
+
params = { "foo" => "bar" }
|
|
473
|
+
silence { transaction.params = params }
|
|
474
|
+
|
|
475
|
+
transaction._sample
|
|
476
|
+
expect(transaction.params).to eq(params)
|
|
477
|
+
expect(transaction).to include_params(params)
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
it "logs a deprecation warning" do
|
|
481
|
+
logs =
|
|
482
|
+
capture_logs do
|
|
483
|
+
transaction.params = { "foo" => "bar" }
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
expect(logs).to contains_log(
|
|
487
|
+
:warn,
|
|
488
|
+
"Transaction#params= is deprecated." \
|
|
489
|
+
"Use Transaction#set_params or #set_params_if_nil instead."
|
|
490
|
+
)
|
|
491
|
+
end
|
|
492
|
+
end
|
|
341
493
|
|
|
342
|
-
|
|
343
|
-
|
|
494
|
+
describe "#set_params" do
|
|
495
|
+
let(:transaction) { new_transaction }
|
|
344
496
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
497
|
+
context "when the params are set" do
|
|
498
|
+
it "updates the params on the transaction" do
|
|
499
|
+
params = { "key" => "value" }
|
|
500
|
+
transaction.set_params(params)
|
|
348
501
|
|
|
349
502
|
transaction._sample
|
|
350
503
|
expect(transaction.params).to eq(params)
|
|
351
504
|
expect(transaction).to include_params(params)
|
|
352
505
|
end
|
|
353
506
|
|
|
354
|
-
it "
|
|
355
|
-
|
|
507
|
+
it "updates the params on the transaction with a block" do
|
|
508
|
+
params = { "key" => "value" }
|
|
509
|
+
transaction.set_params { params }
|
|
356
510
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
"Use Transaction#set_params or #set_params_if_nil instead."
|
|
361
|
-
)
|
|
511
|
+
transaction._sample
|
|
512
|
+
expect(transaction.params).to eq(params)
|
|
513
|
+
expect(transaction).to include_params(params)
|
|
362
514
|
end
|
|
363
|
-
end
|
|
364
515
|
|
|
365
|
-
|
|
366
|
-
|
|
516
|
+
it "updates with the params argument when both an argument and block are given" do
|
|
517
|
+
arg_params = { "argument" => "value" }
|
|
518
|
+
block_params = { "block" => "value" }
|
|
519
|
+
transaction.set_params(arg_params) { block_params }
|
|
367
520
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
521
|
+
transaction._sample
|
|
522
|
+
expect(transaction.params).to eq(arg_params)
|
|
523
|
+
expect(transaction).to include_params(arg_params)
|
|
524
|
+
end
|
|
372
525
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
526
|
+
it "logs an error if an error occurred storing the params" do
|
|
527
|
+
transaction.set_params { raise "uh oh" }
|
|
528
|
+
|
|
529
|
+
logs = capture_logs { transaction._sample }
|
|
530
|
+
expect(logs).to contains_log(
|
|
531
|
+
:error,
|
|
532
|
+
"Exception while fetching params: RuntimeError: uh oh"
|
|
533
|
+
)
|
|
377
534
|
end
|
|
535
|
+
end
|
|
378
536
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
537
|
+
context "when the given params is nil" do
|
|
538
|
+
it "does not update the params on the transaction" do
|
|
539
|
+
params = { "key" => "value" }
|
|
540
|
+
transaction.set_params(params)
|
|
541
|
+
transaction.set_params(nil)
|
|
384
542
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
end
|
|
543
|
+
transaction._sample
|
|
544
|
+
expect(transaction.params).to eq(params)
|
|
545
|
+
expect(transaction).to include_params(params)
|
|
389
546
|
end
|
|
390
547
|
end
|
|
548
|
+
end
|
|
391
549
|
|
|
392
|
-
|
|
393
|
-
|
|
550
|
+
describe "#set_params_if_nil" do
|
|
551
|
+
let(:transaction) { new_transaction }
|
|
394
552
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
553
|
+
context "when the params are not set" do
|
|
554
|
+
it "sets the params on the transaction" do
|
|
555
|
+
params = { "key" => "value" }
|
|
556
|
+
transaction.set_params_if_nil(params)
|
|
399
557
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
558
|
+
transaction._sample
|
|
559
|
+
expect(transaction.params).to eq(params)
|
|
560
|
+
expect(transaction).to include_params(params)
|
|
561
|
+
end
|
|
404
562
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
transaction.set_params(params)
|
|
409
|
-
transaction.set_params_if_nil(nil)
|
|
563
|
+
it "updates the params on the transaction with a block" do
|
|
564
|
+
params = { "key" => "value" }
|
|
565
|
+
transaction.set_params_if_nil { params }
|
|
410
566
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
567
|
+
transaction._sample
|
|
568
|
+
expect(transaction.params).to eq(params)
|
|
569
|
+
expect(transaction).to include_params(params)
|
|
570
|
+
end
|
|
571
|
+
|
|
572
|
+
it "updates with the params argument when both an argument and block are given" do
|
|
573
|
+
arg_params = { "argument" => "value" }
|
|
574
|
+
block_params = { "block" => "value" }
|
|
575
|
+
transaction.set_params_if_nil(arg_params) { block_params }
|
|
576
|
+
|
|
577
|
+
transaction._sample
|
|
578
|
+
expect(transaction.params).to eq(arg_params)
|
|
579
|
+
expect(transaction).to include_params(arg_params)
|
|
416
580
|
end
|
|
417
581
|
|
|
418
|
-
context "when the params
|
|
582
|
+
context "when the given params is nil" do
|
|
419
583
|
it "does not update the params on the transaction" do
|
|
420
|
-
preset_params = { "other" => "params" }
|
|
421
584
|
params = { "key" => "value" }
|
|
422
|
-
transaction.set_params(
|
|
423
|
-
transaction.set_params_if_nil(
|
|
585
|
+
transaction.set_params(params)
|
|
586
|
+
transaction.set_params_if_nil(nil)
|
|
424
587
|
|
|
425
588
|
transaction._sample
|
|
426
|
-
expect(transaction.params).to eq(
|
|
427
|
-
expect(transaction).to include_params(
|
|
589
|
+
expect(transaction.params).to eq(params)
|
|
590
|
+
expect(transaction).to include_params(params)
|
|
428
591
|
end
|
|
429
592
|
end
|
|
430
593
|
end
|
|
431
594
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
:object => Object.new,
|
|
443
|
-
:too_long_value => long_string,
|
|
444
|
-
long_string => "too_long_key"
|
|
445
|
-
)
|
|
446
|
-
transaction.sample_data
|
|
595
|
+
context "when the params are set" do
|
|
596
|
+
it "does not update the params on the transaction" do
|
|
597
|
+
preset_params = { "other" => "params" }
|
|
598
|
+
params = { "key" => "value" }
|
|
599
|
+
transaction.set_params(preset_params)
|
|
600
|
+
transaction.set_params_if_nil(params)
|
|
601
|
+
|
|
602
|
+
transaction._sample
|
|
603
|
+
expect(transaction.params).to eq(preset_params)
|
|
604
|
+
expect(transaction).to include_params(preset_params)
|
|
447
605
|
end
|
|
448
606
|
|
|
449
|
-
it "
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
)
|
|
607
|
+
it "does not update the params with a block on the transaction" do
|
|
608
|
+
preset_params = { "other" => "params" }
|
|
609
|
+
params = { "key" => "value" }
|
|
610
|
+
transaction.set_params(preset_params)
|
|
611
|
+
transaction.set_params_if_nil { params }
|
|
612
|
+
|
|
613
|
+
transaction._sample
|
|
614
|
+
expect(transaction.params).to eq(preset_params)
|
|
615
|
+
expect(transaction).to include_params(preset_params)
|
|
458
616
|
end
|
|
459
617
|
end
|
|
618
|
+
end
|
|
460
619
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
before do
|
|
464
|
-
22.times do |i|
|
|
465
|
-
transaction.add_breadcrumb(
|
|
466
|
-
"network",
|
|
467
|
-
"GET http://localhost",
|
|
468
|
-
"User made external network request",
|
|
469
|
-
{ :code => i + 1 },
|
|
470
|
-
Time.parse("10-10-2010 10:00:00 UTC")
|
|
471
|
-
)
|
|
472
|
-
end
|
|
473
|
-
transaction.sample_data
|
|
474
|
-
end
|
|
620
|
+
describe "#set_session_data" do
|
|
621
|
+
let(:transaction) { new_transaction }
|
|
475
622
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
"time" => 1286704800 # rubocop:disable Style/NumericLiterals
|
|
484
|
-
)
|
|
485
|
-
expect(transaction.to_h["sample_data"]["breadcrumbs"][19]).to eq(
|
|
486
|
-
"action" => "GET http://localhost",
|
|
487
|
-
"category" => "network",
|
|
488
|
-
"message" => "User made external network request",
|
|
489
|
-
"metadata" => { "code" => 22 },
|
|
490
|
-
"time" => 1286704800 # rubocop:disable Style/NumericLiterals
|
|
491
|
-
)
|
|
492
|
-
end
|
|
623
|
+
context "when the session data is set" do
|
|
624
|
+
it "updates the session data on the transaction" do
|
|
625
|
+
data = { "key" => "value" }
|
|
626
|
+
transaction.set_session_data(data)
|
|
627
|
+
|
|
628
|
+
transaction._sample
|
|
629
|
+
expect(transaction).to include_session_data(data)
|
|
493
630
|
end
|
|
494
631
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
transaction.add_breadcrumb("user_action", "clicked HOME")
|
|
499
|
-
transaction.sample_data
|
|
500
|
-
timeframe_end = Time.now.utc.to_i
|
|
632
|
+
it "updates the session data on the transaction with a block" do
|
|
633
|
+
data = { "key" => "value" }
|
|
634
|
+
transaction.set_session_data { data }
|
|
501
635
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
"user_action",
|
|
505
|
-
"",
|
|
506
|
-
{},
|
|
507
|
-
be_between(timeframe_start, timeframe_end)
|
|
508
|
-
)
|
|
509
|
-
end
|
|
636
|
+
transaction._sample
|
|
637
|
+
expect(transaction).to include_session_data(data)
|
|
510
638
|
end
|
|
511
639
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
640
|
+
it "updates with the session data argument when both an argument and block are given" do
|
|
641
|
+
arg_data = { "argument" => "value" }
|
|
642
|
+
block_data = { "block" => "value" }
|
|
643
|
+
transaction.set_session_data(arg_data) { block_data }
|
|
516
644
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
:error,
|
|
520
|
-
"add_breadcrumb: Cannot add breadcrumb. The given metadata argument is not a Hash."
|
|
521
|
-
)
|
|
522
|
-
end
|
|
645
|
+
transaction._sample
|
|
646
|
+
expect(transaction).to include_session_data(arg_data)
|
|
523
647
|
end
|
|
524
|
-
end
|
|
525
648
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
action_name = "PagesController#show"
|
|
530
|
-
transaction.set_action(action_name)
|
|
649
|
+
it "does not include filtered out session data" do
|
|
650
|
+
Appsignal.config[:filter_session_data] = ["filtered_key"]
|
|
651
|
+
transaction.set_session_data("data" => "value1", "filtered_key" => "filtered_value")
|
|
531
652
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
end
|
|
653
|
+
transaction._sample
|
|
654
|
+
expect(transaction).to include_session_data("data" => "value1")
|
|
535
655
|
end
|
|
536
656
|
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
action_name = "PagesController#show"
|
|
540
|
-
transaction.set_action(action_name)
|
|
541
|
-
transaction.set_action(nil)
|
|
657
|
+
it "logs an error if an error occurred storing the session data" do
|
|
658
|
+
transaction.set_session_data { raise "uh oh" }
|
|
542
659
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
660
|
+
logs = capture_logs { transaction._sample }
|
|
661
|
+
expect(logs).to contains_log(
|
|
662
|
+
:error,
|
|
663
|
+
"Exception while fetching session data: RuntimeError: uh oh"
|
|
664
|
+
)
|
|
546
665
|
end
|
|
547
666
|
end
|
|
548
667
|
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
668
|
+
context "when the given session data is nil" do
|
|
669
|
+
it "does not update the session data on the transaction" do
|
|
670
|
+
data = { "key" => "value" }
|
|
671
|
+
transaction.set_session_data(data)
|
|
672
|
+
transaction.set_session_data(nil)
|
|
554
673
|
|
|
555
|
-
|
|
556
|
-
|
|
674
|
+
transaction._sample
|
|
675
|
+
expect(transaction).to include_session_data(data)
|
|
676
|
+
end
|
|
677
|
+
end
|
|
678
|
+
end
|
|
557
679
|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
end
|
|
680
|
+
describe "#set_session_data_if_nil" do
|
|
681
|
+
let(:transaction) { new_transaction }
|
|
561
682
|
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
transaction.set_action_if_nil(nil)
|
|
683
|
+
context "when the params are not set" do
|
|
684
|
+
it "sets the params on the transaction" do
|
|
685
|
+
data = { "key" => "value" }
|
|
686
|
+
transaction.set_session_data_if_nil(data)
|
|
567
687
|
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
end
|
|
571
|
-
end
|
|
688
|
+
transaction._sample
|
|
689
|
+
expect(transaction).to include_session_data(data)
|
|
572
690
|
end
|
|
573
691
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
transaction.set_action("something")
|
|
578
|
-
transaction.set_action_if_nil("something else")
|
|
692
|
+
it "updates the params on the transaction with a block" do
|
|
693
|
+
data = { "key" => "value" }
|
|
694
|
+
transaction.set_session_data_if_nil { data }
|
|
579
695
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
end
|
|
696
|
+
transaction._sample
|
|
697
|
+
expect(transaction).to include_session_data(data)
|
|
583
698
|
end
|
|
584
|
-
end
|
|
585
699
|
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
transaction.set_namespace(namespace)
|
|
700
|
+
it "updates with the params argument when both an argument and block are given" do
|
|
701
|
+
arg_data = { "argument" => "value" }
|
|
702
|
+
block_data = { "block" => "value" }
|
|
703
|
+
transaction.set_session_data_if_nil(arg_data) { block_data }
|
|
591
704
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
end
|
|
705
|
+
transaction._sample
|
|
706
|
+
expect(transaction).to include_session_data(arg_data)
|
|
595
707
|
end
|
|
596
708
|
|
|
597
|
-
context "when the
|
|
598
|
-
it "does not update the
|
|
599
|
-
|
|
600
|
-
transaction.
|
|
601
|
-
transaction.
|
|
709
|
+
context "when the given params is nil" do
|
|
710
|
+
it "does not update the params on the transaction" do
|
|
711
|
+
data = { "key" => "value" }
|
|
712
|
+
transaction.set_session_data(data)
|
|
713
|
+
transaction.set_session_data_if_nil(nil)
|
|
602
714
|
|
|
603
|
-
|
|
604
|
-
expect(transaction).to
|
|
715
|
+
transaction._sample
|
|
716
|
+
expect(transaction).to include_session_data(data)
|
|
605
717
|
end
|
|
606
718
|
end
|
|
607
719
|
end
|
|
608
720
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
)
|
|
616
|
-
expect(transaction).to have_action("HomeController#show")
|
|
617
|
-
end
|
|
618
|
-
end
|
|
721
|
+
context "when the params are set" do
|
|
722
|
+
it "does not update the params on the transaction" do
|
|
723
|
+
preset_data = { "other" => "data" }
|
|
724
|
+
data = { "key" => "value" }
|
|
725
|
+
transaction.set_session_data(preset_data)
|
|
726
|
+
transaction.set_session_data_if_nil(data)
|
|
619
727
|
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
transaction.set_http_or_background_action(:action => "show")
|
|
623
|
-
expect(transaction).to have_action("show")
|
|
624
|
-
end
|
|
728
|
+
transaction._sample
|
|
729
|
+
expect(transaction).to include_session_data(preset_data)
|
|
625
730
|
end
|
|
626
731
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
end
|
|
732
|
+
it "does not update the params with a block on the transaction" do
|
|
733
|
+
preset_data = { "other" => "data" }
|
|
734
|
+
data = { "key" => "value" }
|
|
735
|
+
transaction.set_session_data(preset_data)
|
|
736
|
+
transaction.set_session_data_if_nil { data }
|
|
633
737
|
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
transaction.set_action("MyCustomAction#perform")
|
|
637
|
-
transaction.set_http_or_background_action(:class => "Worker", :method => "perform")
|
|
638
|
-
expect(transaction).to have_action("MyCustomAction#perform")
|
|
639
|
-
end
|
|
738
|
+
transaction._sample
|
|
739
|
+
expect(transaction).to include_session_data(preset_data)
|
|
640
740
|
end
|
|
641
741
|
end
|
|
742
|
+
end
|
|
743
|
+
|
|
744
|
+
describe "#set_headers" do
|
|
745
|
+
let(:transaction) { new_transaction }
|
|
642
746
|
|
|
643
|
-
|
|
644
|
-
it "
|
|
645
|
-
|
|
747
|
+
context "when the headers are set" do
|
|
748
|
+
it "updates the headers on the transaction" do
|
|
749
|
+
headers = { "PATH_INFO" => "value" }
|
|
750
|
+
transaction.set_headers(headers)
|
|
646
751
|
|
|
647
|
-
transaction.
|
|
752
|
+
transaction._sample
|
|
753
|
+
expect(transaction).to include_environment(headers)
|
|
648
754
|
end
|
|
649
755
|
|
|
650
|
-
it "
|
|
651
|
-
|
|
756
|
+
it "updates the headers on the transaction with a block" do
|
|
757
|
+
headers = { "PATH_INFO" => "value" }
|
|
758
|
+
transaction.set_headers { headers }
|
|
652
759
|
|
|
653
|
-
transaction.
|
|
760
|
+
transaction._sample
|
|
761
|
+
expect(transaction).to include_environment(headers)
|
|
654
762
|
end
|
|
655
763
|
|
|
656
|
-
it "
|
|
657
|
-
|
|
764
|
+
it "updates with the headers argument when both an argument and block are given" do
|
|
765
|
+
arg_data = { "PATH_INFO" => "/arg-path" }
|
|
766
|
+
block_data = { "PATH_INFO" => "/block-path" }
|
|
767
|
+
transaction.set_headers(arg_data) { block_data }
|
|
658
768
|
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
769
|
+
transaction._sample
|
|
770
|
+
expect(transaction).to include_environment(arg_data)
|
|
771
|
+
end
|
|
772
|
+
|
|
773
|
+
it "does not include filtered out headers" do
|
|
774
|
+
Appsignal.config[:request_headers] = ["MY_HEADER"]
|
|
775
|
+
transaction.set_headers("MY_HEADER" => "value1", "filtered_key" => "filtered_value")
|
|
776
|
+
|
|
777
|
+
transaction._sample
|
|
778
|
+
expect(transaction).to include_environment("MY_HEADER" => "value1")
|
|
779
|
+
end
|
|
780
|
+
|
|
781
|
+
it "logs an error if an error occurred storing the headers" do
|
|
782
|
+
transaction.set_headers { raise "uh oh" }
|
|
783
|
+
|
|
784
|
+
logs = capture_logs { transaction._sample }
|
|
785
|
+
expect(logs).to contains_log(
|
|
786
|
+
:error,
|
|
787
|
+
"Exception while fetching headers: RuntimeError: uh oh"
|
|
788
|
+
)
|
|
662
789
|
end
|
|
663
790
|
end
|
|
664
791
|
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
792
|
+
context "when the given headers is nil" do
|
|
793
|
+
it "does not update the headers on the transaction" do
|
|
794
|
+
headers = { "PATH_INFO" => "value" }
|
|
795
|
+
transaction.set_headers(headers)
|
|
796
|
+
transaction.set_headers(nil)
|
|
668
797
|
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
798
|
+
transaction._sample
|
|
799
|
+
expect(transaction).to include_environment(headers)
|
|
800
|
+
end
|
|
801
|
+
end
|
|
802
|
+
end
|
|
672
803
|
|
|
673
|
-
|
|
674
|
-
|
|
804
|
+
describe "#set_headers_if_nil" do
|
|
805
|
+
let(:transaction) { new_transaction }
|
|
675
806
|
|
|
676
|
-
|
|
677
|
-
|
|
807
|
+
context "when the params are not set" do
|
|
808
|
+
it "sets the params on the transaction" do
|
|
809
|
+
headers = { "PATH_INFO" => "value" }
|
|
810
|
+
transaction.set_headers_if_nil(headers)
|
|
678
811
|
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
"HTTP_X_REQUEST_START" => "t=#{header_time}",
|
|
683
|
-
:queue_start => env_queue_start
|
|
684
|
-
}
|
|
685
|
-
end
|
|
812
|
+
transaction._sample
|
|
813
|
+
expect(transaction).to include_environment(headers)
|
|
814
|
+
end
|
|
686
815
|
|
|
687
|
-
|
|
688
|
-
|
|
816
|
+
it "updates the params on the transaction with a block" do
|
|
817
|
+
headers = { "PATH_INFO" => "value" }
|
|
818
|
+
transaction.set_headers_if_nil { headers }
|
|
689
819
|
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
end
|
|
820
|
+
transaction._sample
|
|
821
|
+
expect(transaction).to include_environment(headers)
|
|
693
822
|
end
|
|
694
823
|
|
|
695
|
-
|
|
696
|
-
|
|
824
|
+
it "updates with the params argument when both an argument and block are given" do
|
|
825
|
+
arg_data = { "PATH_INFO" => "/arg-path" }
|
|
826
|
+
block_data = { "PATH_INFO" => "/block-path" }
|
|
827
|
+
transaction.set_headers_if_nil(arg_data) { block_data }
|
|
697
828
|
|
|
698
|
-
|
|
699
|
-
|
|
829
|
+
transaction._sample
|
|
830
|
+
expect(transaction).to include_environment(arg_data)
|
|
831
|
+
end
|
|
700
832
|
|
|
701
|
-
|
|
833
|
+
context "when the given params is nil" do
|
|
834
|
+
it "does not update the params on the transaction" do
|
|
835
|
+
headers = { "PATH_INFO" => "value" }
|
|
836
|
+
transaction.set_headers(headers)
|
|
837
|
+
transaction.set_headers_if_nil(nil)
|
|
838
|
+
|
|
839
|
+
transaction._sample
|
|
840
|
+
expect(transaction).to include_environment(headers)
|
|
702
841
|
end
|
|
703
842
|
end
|
|
704
843
|
end
|
|
705
844
|
|
|
706
|
-
|
|
707
|
-
it "
|
|
708
|
-
|
|
845
|
+
context "when the params are set" do
|
|
846
|
+
it "does not update the params on the transaction" do
|
|
847
|
+
preset_headers = { "PATH_INFO" => "/first-path" }
|
|
848
|
+
headers = { "PATH_INFO" => "/other-path" }
|
|
849
|
+
transaction.set_headers(preset_headers)
|
|
850
|
+
transaction.set_headers_if_nil(headers)
|
|
709
851
|
|
|
710
|
-
|
|
852
|
+
transaction._sample
|
|
853
|
+
expect(transaction).to include_environment(preset_headers)
|
|
711
854
|
end
|
|
712
855
|
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
transaction.set_metadata(:filter_key, "filtered value")
|
|
719
|
-
transaction.set_metadata("filter_key", "filtered value")
|
|
856
|
+
it "does not update the params with a block on the transaction" do
|
|
857
|
+
preset_headers = { "PATH_INFO" => "/first-path" }
|
|
858
|
+
headers = { "PATH_INFO" => "/other-path" }
|
|
859
|
+
transaction.set_headers(preset_headers)
|
|
860
|
+
transaction.set_headers_if_nil { headers }
|
|
720
861
|
|
|
721
|
-
|
|
722
|
-
|
|
862
|
+
transaction._sample
|
|
863
|
+
expect(transaction).to include_environment(preset_headers)
|
|
723
864
|
end
|
|
865
|
+
end
|
|
866
|
+
end
|
|
724
867
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
868
|
+
describe "#set_tags" do
|
|
869
|
+
let(:transaction) { new_transaction }
|
|
870
|
+
let(:long_string) { "a" * 10_001 }
|
|
871
|
+
|
|
872
|
+
it "stores tags on the transaction" do
|
|
873
|
+
transaction.set_tags(
|
|
874
|
+
:valid_key => "valid_value",
|
|
875
|
+
"valid_string_key" => "valid_value",
|
|
876
|
+
:both_symbols => :valid_value,
|
|
877
|
+
:integer_value => 1,
|
|
878
|
+
:hash_value => { "invalid" => "hash" },
|
|
879
|
+
:array_value => %w[invalid array],
|
|
880
|
+
:object => Object.new,
|
|
881
|
+
:too_long_value => long_string,
|
|
882
|
+
long_string => "too_long_key",
|
|
883
|
+
:true_tag => true,
|
|
884
|
+
:false_tag => false
|
|
885
|
+
)
|
|
886
|
+
transaction._sample
|
|
887
|
+
|
|
888
|
+
expect(transaction).to include_tags(
|
|
889
|
+
"valid_key" => "valid_value",
|
|
890
|
+
"valid_string_key" => "valid_value",
|
|
891
|
+
"both_symbols" => "valid_value",
|
|
892
|
+
"integer_value" => 1,
|
|
893
|
+
"too_long_value" => "#{"a" * 10_000}...",
|
|
894
|
+
long_string => "too_long_key",
|
|
895
|
+
"true_tag" => true,
|
|
896
|
+
"false_tag" => false
|
|
897
|
+
)
|
|
898
|
+
end
|
|
728
899
|
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
900
|
+
it "merges the tags when called multiple times" do
|
|
901
|
+
transaction.set_tags(:key1 => "value1")
|
|
902
|
+
transaction.set_tags(:key2 => "value2")
|
|
903
|
+
transaction._sample
|
|
904
|
+
|
|
905
|
+
expect(transaction).to include_tags(
|
|
906
|
+
"key1" => "value1",
|
|
907
|
+
"key2" => "value2"
|
|
908
|
+
)
|
|
909
|
+
end
|
|
910
|
+
end
|
|
911
|
+
|
|
912
|
+
describe "#set_custom_data" do
|
|
913
|
+
let(:transaction) { new_transaction }
|
|
914
|
+
|
|
915
|
+
it "stores custom Hash data on the transaction" do
|
|
916
|
+
transaction.set_custom_data(
|
|
917
|
+
:user => {
|
|
918
|
+
:id => 123,
|
|
919
|
+
:locale => "abc"
|
|
920
|
+
},
|
|
921
|
+
:organization => {
|
|
922
|
+
:slug => "appsignal",
|
|
923
|
+
:plan => "enterprise"
|
|
924
|
+
}
|
|
925
|
+
)
|
|
926
|
+
|
|
927
|
+
transaction._sample
|
|
928
|
+
expect(transaction).to include_custom_data(
|
|
929
|
+
"user" => {
|
|
930
|
+
"id" => 123,
|
|
931
|
+
"locale" => "abc"
|
|
932
|
+
},
|
|
933
|
+
"organization" => {
|
|
934
|
+
"slug" => "appsignal",
|
|
935
|
+
"plan" => "enterprise"
|
|
936
|
+
}
|
|
937
|
+
)
|
|
938
|
+
end
|
|
939
|
+
|
|
940
|
+
it "stores custom Array data on the transaction" do
|
|
941
|
+
transaction.set_custom_data([
|
|
942
|
+
[123, "abc"],
|
|
943
|
+
["appsignal", "enterprise"]
|
|
944
|
+
])
|
|
945
|
+
|
|
946
|
+
transaction._sample
|
|
947
|
+
expect(transaction).to include_custom_data([
|
|
948
|
+
[123, "abc"],
|
|
949
|
+
["appsignal", "enterprise"]
|
|
950
|
+
])
|
|
951
|
+
end
|
|
952
|
+
|
|
953
|
+
it "does not store non Hash or Array custom data" do
|
|
954
|
+
logs =
|
|
955
|
+
capture_logs do
|
|
956
|
+
transaction.set_custom_data("abc")
|
|
957
|
+
transaction._sample
|
|
958
|
+
expect(transaction).to_not include_custom_data
|
|
959
|
+
|
|
960
|
+
transaction.set_custom_data(123)
|
|
961
|
+
transaction._sample
|
|
962
|
+
expect(transaction).to_not include_custom_data
|
|
963
|
+
|
|
964
|
+
transaction.set_custom_data(Object.new)
|
|
965
|
+
transaction._sample
|
|
966
|
+
expect(transaction).to_not include_custom_data
|
|
967
|
+
end
|
|
968
|
+
|
|
969
|
+
expect(logs).to contains_log(
|
|
970
|
+
:error,
|
|
971
|
+
"set_custom_data: Unsupported data type String received."
|
|
972
|
+
)
|
|
973
|
+
expect(logs).to contains_log(
|
|
974
|
+
:error,
|
|
975
|
+
"set_custom_data: Unsupported data type Integer received."
|
|
976
|
+
)
|
|
977
|
+
expect(logs).to contains_log(
|
|
978
|
+
:error,
|
|
979
|
+
"set_custom_data: Unsupported data type String received."
|
|
980
|
+
)
|
|
981
|
+
end
|
|
982
|
+
|
|
983
|
+
it "overwrites the custom data if called multiple times" do
|
|
984
|
+
transaction.set_custom_data("user" => { "id" => 123 })
|
|
985
|
+
transaction.set_custom_data("user" => { "id" => 456 })
|
|
986
|
+
|
|
987
|
+
transaction._sample
|
|
988
|
+
expect(transaction).to include_custom_data("user" => { "id" => 456 })
|
|
989
|
+
end
|
|
990
|
+
end
|
|
732
991
|
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
transaction.set_metadata("request_method", nil)
|
|
992
|
+
describe "#add_breadcrumb" do
|
|
993
|
+
let(:transaction) { new_transaction }
|
|
736
994
|
|
|
737
|
-
|
|
995
|
+
context "when over the limit" do
|
|
996
|
+
before do
|
|
997
|
+
22.times do |i|
|
|
998
|
+
transaction.add_breadcrumb(
|
|
999
|
+
"network",
|
|
1000
|
+
"GET http://localhost",
|
|
1001
|
+
"User made external network request",
|
|
1002
|
+
{ :code => i + 1 },
|
|
1003
|
+
Time.parse("10-10-2010 10:00:00 UTC")
|
|
1004
|
+
)
|
|
738
1005
|
end
|
|
1006
|
+
transaction._sample
|
|
1007
|
+
end
|
|
1008
|
+
|
|
1009
|
+
it "stores last <LIMIT> breadcrumbs on the transaction" do
|
|
1010
|
+
expect(transaction.to_h["sample_data"]["breadcrumbs"].length).to eql(20)
|
|
1011
|
+
expect(transaction.to_h["sample_data"]["breadcrumbs"][0]).to eq(
|
|
1012
|
+
"action" => "GET http://localhost",
|
|
1013
|
+
"category" => "network",
|
|
1014
|
+
"message" => "User made external network request",
|
|
1015
|
+
"metadata" => { "code" => 3 },
|
|
1016
|
+
"time" => 1286704800 # rubocop:disable Style/NumericLiterals
|
|
1017
|
+
)
|
|
1018
|
+
expect(transaction.to_h["sample_data"]["breadcrumbs"][19]).to eq(
|
|
1019
|
+
"action" => "GET http://localhost",
|
|
1020
|
+
"category" => "network",
|
|
1021
|
+
"message" => "User made external network request",
|
|
1022
|
+
"metadata" => { "code" => 22 },
|
|
1023
|
+
"time" => 1286704800 # rubocop:disable Style/NumericLiterals
|
|
1024
|
+
)
|
|
739
1025
|
end
|
|
740
1026
|
end
|
|
741
1027
|
|
|
742
|
-
|
|
743
|
-
it "
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
1028
|
+
context "with defaults" do
|
|
1029
|
+
it "stores breadcrumb with defaults on transaction" do
|
|
1030
|
+
timeframe_start = Time.now.utc.to_i
|
|
1031
|
+
transaction.add_breadcrumb("user_action", "clicked HOME")
|
|
1032
|
+
transaction._sample
|
|
1033
|
+
timeframe_end = Time.now.utc.to_i
|
|
1034
|
+
|
|
1035
|
+
expect(transaction).to include_breadcrumb(
|
|
1036
|
+
"clicked HOME",
|
|
1037
|
+
"user_action",
|
|
1038
|
+
"",
|
|
1039
|
+
{},
|
|
1040
|
+
be_between(timeframe_start, timeframe_end)
|
|
749
1041
|
)
|
|
1042
|
+
end
|
|
1043
|
+
end
|
|
750
1044
|
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
1045
|
+
context "with metadata argument that's not a Hash" do
|
|
1046
|
+
it "does not add the breadcrumb and logs and error" do
|
|
1047
|
+
logs =
|
|
1048
|
+
capture_logs do
|
|
1049
|
+
transaction.add_breadcrumb("category", "action", "message", "invalid metadata")
|
|
1050
|
+
end
|
|
1051
|
+
transaction._sample
|
|
1052
|
+
|
|
1053
|
+
expect(transaction).to_not include_breadcrumbs
|
|
1054
|
+
expect(logs).to contains_log(
|
|
1055
|
+
:error,
|
|
1056
|
+
"add_breadcrumb: Cannot add breadcrumb. The given metadata argument is not a Hash."
|
|
755
1057
|
)
|
|
756
1058
|
end
|
|
1059
|
+
end
|
|
1060
|
+
end
|
|
757
1061
|
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
transaction.set_sample_data("params", "string")
|
|
1062
|
+
describe "#set_action" do
|
|
1063
|
+
let(:transaction) { new_transaction }
|
|
761
1064
|
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
1065
|
+
context "when the action is set" do
|
|
1066
|
+
it "updates the action name on the transaction" do
|
|
1067
|
+
action_name = "PagesController#show"
|
|
1068
|
+
transaction.set_action(action_name)
|
|
1069
|
+
|
|
1070
|
+
expect(transaction.action).to eq(action_name)
|
|
1071
|
+
expect(transaction).to have_action(action_name)
|
|
1072
|
+
end
|
|
1073
|
+
end
|
|
1074
|
+
|
|
1075
|
+
context "when the action is nil" do
|
|
1076
|
+
it "does not update the action name on the transaction" do
|
|
1077
|
+
action_name = "PagesController#show"
|
|
1078
|
+
transaction.set_action(action_name)
|
|
1079
|
+
transaction.set_action(nil)
|
|
1080
|
+
|
|
1081
|
+
expect(transaction.action).to eq(action_name)
|
|
1082
|
+
expect(transaction).to have_action(action_name)
|
|
766
1083
|
end
|
|
1084
|
+
end
|
|
1085
|
+
end
|
|
767
1086
|
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
klass = Class.new do
|
|
771
|
-
def to_s
|
|
772
|
-
raise "foo" # Cause a deliberate error
|
|
773
|
-
end
|
|
774
|
-
end
|
|
775
|
-
transaction.set_sample_data("params", klass.new => 1)
|
|
1087
|
+
describe "#set_action_if_nil" do
|
|
1088
|
+
let(:transaction) { new_transaction }
|
|
776
1089
|
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
1090
|
+
context "when the action is not set" do
|
|
1091
|
+
it "updates the action name on the transaction" do
|
|
1092
|
+
expect(transaction.action).to eq(nil)
|
|
1093
|
+
expect(transaction).to_not have_action
|
|
1094
|
+
|
|
1095
|
+
action_name = "PagesController#show"
|
|
1096
|
+
transaction.set_action_if_nil(action_name)
|
|
1097
|
+
|
|
1098
|
+
expect(transaction.action).to eq(action_name)
|
|
1099
|
+
expect(transaction).to have_action(action_name)
|
|
1100
|
+
end
|
|
1101
|
+
|
|
1102
|
+
context "when the given action is nil" do
|
|
1103
|
+
it "does not update the action name on the transaction" do
|
|
1104
|
+
action_name = "something"
|
|
1105
|
+
transaction.set_action("something")
|
|
1106
|
+
transaction.set_action_if_nil(nil)
|
|
1107
|
+
|
|
1108
|
+
expect(transaction.action).to eq(action_name)
|
|
1109
|
+
expect(transaction).to have_action(action_name)
|
|
780
1110
|
end
|
|
781
1111
|
end
|
|
782
1112
|
end
|
|
783
1113
|
|
|
784
|
-
|
|
785
|
-
|
|
1114
|
+
context "when the action is set" do
|
|
1115
|
+
it "does not update the action name on the transaction" do
|
|
1116
|
+
action_name = "something"
|
|
1117
|
+
transaction.set_action("something")
|
|
1118
|
+
transaction.set_action_if_nil("something else")
|
|
786
1119
|
|
|
787
|
-
|
|
788
|
-
transaction.
|
|
789
|
-
|
|
790
|
-
|
|
1120
|
+
expect(transaction.action).to eq(action_name)
|
|
1121
|
+
expect(transaction).to have_action(action_name)
|
|
1122
|
+
end
|
|
1123
|
+
end
|
|
1124
|
+
end
|
|
791
1125
|
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
1126
|
+
describe "#set_namespace" do
|
|
1127
|
+
let(:transaction) { new_transaction }
|
|
1128
|
+
|
|
1129
|
+
context "when the namespace is not nil" do
|
|
1130
|
+
it "updates the namespace on the transaction" do
|
|
1131
|
+
namespace = "custom"
|
|
1132
|
+
transaction.set_namespace(namespace)
|
|
1133
|
+
|
|
1134
|
+
expect(transaction.namespace).to eq namespace
|
|
1135
|
+
expect(transaction).to have_namespace(namespace)
|
|
1136
|
+
end
|
|
1137
|
+
end
|
|
1138
|
+
|
|
1139
|
+
context "when the namespace is nil" do
|
|
1140
|
+
it "does not update the namespace on the transaction" do
|
|
1141
|
+
namespace = "custom"
|
|
1142
|
+
transaction.set_namespace(namespace)
|
|
1143
|
+
transaction.set_namespace(nil)
|
|
1144
|
+
|
|
1145
|
+
expect(transaction.namespace).to eq(namespace)
|
|
1146
|
+
expect(transaction).to have_namespace(namespace)
|
|
1147
|
+
end
|
|
1148
|
+
end
|
|
1149
|
+
end
|
|
1150
|
+
|
|
1151
|
+
describe "#set_http_or_background_action" do
|
|
1152
|
+
let(:transaction) { new_transaction }
|
|
1153
|
+
|
|
1154
|
+
context "for a hash with controller and action" do
|
|
1155
|
+
it "sets the action" do
|
|
1156
|
+
transaction.set_http_or_background_action(
|
|
1157
|
+
:controller => "HomeController",
|
|
1158
|
+
:action => "show"
|
|
812
1159
|
)
|
|
1160
|
+
expect(transaction).to have_action("HomeController#show")
|
|
813
1161
|
end
|
|
814
1162
|
end
|
|
815
1163
|
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
allow(e).to receive(:backtrace).and_return(["line 1"])
|
|
821
|
-
e
|
|
1164
|
+
context "for a hash with just action" do
|
|
1165
|
+
it "sets the action" do
|
|
1166
|
+
transaction.set_http_or_background_action(:action => "show")
|
|
1167
|
+
expect(transaction).to have_action("show")
|
|
822
1168
|
end
|
|
1169
|
+
end
|
|
823
1170
|
|
|
824
|
-
|
|
825
|
-
|
|
1171
|
+
context "for a hash with class and method" do
|
|
1172
|
+
it "sets the action" do
|
|
1173
|
+
transaction.set_http_or_background_action(:class => "Worker", :method => "perform")
|
|
1174
|
+
expect(transaction).to have_action("Worker#perform")
|
|
826
1175
|
end
|
|
1176
|
+
end
|
|
827
1177
|
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
1178
|
+
context "when action is already set" do
|
|
1179
|
+
it "does not overwrite the set action" do
|
|
1180
|
+
transaction.set_action("MyCustomAction#perform")
|
|
1181
|
+
transaction.set_http_or_background_action(:class => "Worker", :method => "perform")
|
|
1182
|
+
expect(transaction).to have_action("MyCustomAction#perform")
|
|
1183
|
+
end
|
|
1184
|
+
end
|
|
1185
|
+
end
|
|
831
1186
|
|
|
832
|
-
|
|
1187
|
+
describe "#set_queue_start" do
|
|
1188
|
+
let(:transaction) { new_transaction }
|
|
1189
|
+
|
|
1190
|
+
it "sets the queue start in extension" do
|
|
1191
|
+
transaction.set_queue_start(10)
|
|
1192
|
+
|
|
1193
|
+
expect(transaction).to have_queue_start(10)
|
|
1194
|
+
end
|
|
1195
|
+
|
|
1196
|
+
it "does not set the queue start in extension when value is nil" do
|
|
1197
|
+
transaction.set_queue_start(nil)
|
|
1198
|
+
|
|
1199
|
+
expect(transaction).to_not have_queue_start
|
|
1200
|
+
end
|
|
1201
|
+
|
|
1202
|
+
it "does not raise an error when the queue start is too big" do
|
|
1203
|
+
expect(transaction.ext).to receive(:set_queue_start).and_raise(RangeError)
|
|
1204
|
+
|
|
1205
|
+
expect(Appsignal.internal_logger).to receive(:warn).with("Queue start value 10 is too big")
|
|
1206
|
+
|
|
1207
|
+
transaction.set_queue_start(10)
|
|
1208
|
+
end
|
|
1209
|
+
end
|
|
1210
|
+
|
|
1211
|
+
describe "#set_http_or_background_queue_start" do
|
|
1212
|
+
let(:transaction) { legacy_new_transaction(:request => legacy_request(env)) }
|
|
1213
|
+
let(:err_stream) { std_stream }
|
|
1214
|
+
let(:stderr) { err_stream.read }
|
|
1215
|
+
let(:header_factor) { 1_000 }
|
|
1216
|
+
let(:env_queue_start) { fixed_time + 20 } # in seconds
|
|
1217
|
+
|
|
1218
|
+
def set_http_or_background_queue_start
|
|
1219
|
+
capture_std_streams(std_stream, err_stream) do
|
|
1220
|
+
transaction.set_http_or_background_queue_start
|
|
833
1221
|
end
|
|
1222
|
+
end
|
|
834
1223
|
|
|
835
|
-
|
|
836
|
-
|
|
1224
|
+
context "when a queue time is found in a request header" do
|
|
1225
|
+
let(:header_time) { ((fixed_time + 10) * header_factor).to_i } # in milliseconds
|
|
1226
|
+
let(:env) { { "HTTP_X_REQUEST_START" => "t=#{header_time}" } }
|
|
837
1227
|
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
"Appsignal::Transaction#set_error: Cannot set error. " \
|
|
841
|
-
"The given value is not an exception: #{error.inspect}"
|
|
842
|
-
)
|
|
843
|
-
expect(transaction.ext).to_not receive(:set_error)
|
|
1228
|
+
it "sets the http header value in milliseconds on the transaction" do
|
|
1229
|
+
set_http_or_background_queue_start
|
|
844
1230
|
|
|
845
|
-
|
|
846
|
-
end
|
|
1231
|
+
expect(transaction).to have_queue_start(1_389_783_610_000)
|
|
847
1232
|
end
|
|
848
1233
|
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
expect(transaction.ext).to receive(:set_error).with(
|
|
852
|
-
"ExampleStandardError",
|
|
853
|
-
"test message",
|
|
854
|
-
Appsignal::Utils::Data.generate(["line 1"])
|
|
855
|
-
)
|
|
1234
|
+
it "logs a deprecation message" do
|
|
1235
|
+
logs = capture_logs { set_http_or_background_queue_start }
|
|
856
1236
|
|
|
857
|
-
|
|
858
|
-
|
|
1237
|
+
expect(logs).to contains_log(
|
|
1238
|
+
:warn,
|
|
1239
|
+
"The Appsignal::Transaction#set_http_or_background_queue_start " \
|
|
1240
|
+
"method has been deprecated."
|
|
1241
|
+
)
|
|
859
1242
|
end
|
|
860
1243
|
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
expect(transaction.ext).to_not receive(:set_sample_data)
|
|
1244
|
+
it "prints a deprecation message" do
|
|
1245
|
+
set_http_or_background_queue_start
|
|
864
1246
|
|
|
865
|
-
|
|
1247
|
+
expect(stderr).to include(
|
|
1248
|
+
"The Appsignal::Transaction#set_http_or_background_queue_start " \
|
|
1249
|
+
"method has been deprecated."
|
|
1250
|
+
)
|
|
1251
|
+
end
|
|
1252
|
+
|
|
1253
|
+
context "when a :queue_start key is found in the transaction environment" do
|
|
1254
|
+
let(:env) do
|
|
1255
|
+
{
|
|
1256
|
+
"HTTP_X_REQUEST_START" => "t=#{header_time}",
|
|
1257
|
+
:queue_start => env_queue_start
|
|
1258
|
+
}
|
|
866
1259
|
end
|
|
1260
|
+
|
|
1261
|
+
it "sets the http header value in milliseconds on the transaction" do
|
|
1262
|
+
set_http_or_background_queue_start
|
|
1263
|
+
|
|
1264
|
+
expect(transaction).to have_queue_start(1_389_783_610_000)
|
|
1265
|
+
end
|
|
1266
|
+
end
|
|
1267
|
+
end
|
|
1268
|
+
|
|
1269
|
+
context "when a :queue_start key is found in the transaction environment" do
|
|
1270
|
+
let(:env) { { :queue_start => env_queue_start } } # in seconds
|
|
1271
|
+
|
|
1272
|
+
it "sets the :queue_start value in milliseconds on the transaction" do
|
|
1273
|
+
set_http_or_background_queue_start
|
|
1274
|
+
|
|
1275
|
+
expect(transaction).to have_queue_start(1_389_783_620_000)
|
|
867
1276
|
end
|
|
1277
|
+
end
|
|
1278
|
+
end
|
|
1279
|
+
|
|
1280
|
+
describe "#set_metadata" do
|
|
1281
|
+
let(:transaction) { new_transaction }
|
|
1282
|
+
|
|
1283
|
+
it "updates the metadata on the transaction" do
|
|
1284
|
+
transaction.set_metadata("request_method", "GET")
|
|
1285
|
+
|
|
1286
|
+
expect(transaction).to include_metadata("request_method" => "GET")
|
|
1287
|
+
end
|
|
1288
|
+
|
|
1289
|
+
context "when filter_metadata includes metadata key" do
|
|
1290
|
+
before { Appsignal.config[:filter_metadata] = ["filter_key"] }
|
|
1291
|
+
after { Appsignal.config[:filter_metadata] = [] }
|
|
1292
|
+
|
|
1293
|
+
it "does not set the metadata on the transaction" do
|
|
1294
|
+
transaction.set_metadata(:filter_key, "filtered value")
|
|
1295
|
+
transaction.set_metadata("filter_key", "filtered value")
|
|
1296
|
+
|
|
1297
|
+
expect(transaction).to_not include_metadata("filter_key" => anything)
|
|
1298
|
+
end
|
|
1299
|
+
end
|
|
1300
|
+
|
|
1301
|
+
context "when the key is nil" do
|
|
1302
|
+
it "does not update the metadata on the transaction" do
|
|
1303
|
+
transaction.set_metadata(nil, "GET")
|
|
1304
|
+
|
|
1305
|
+
expect(transaction).to_not include_metadata
|
|
1306
|
+
end
|
|
1307
|
+
end
|
|
1308
|
+
|
|
1309
|
+
context "when the value is nil" do
|
|
1310
|
+
it "does not update the metadata on the transaction" do
|
|
1311
|
+
transaction.set_metadata("request_method", nil)
|
|
1312
|
+
|
|
1313
|
+
expect(transaction).to_not include_metadata
|
|
1314
|
+
end
|
|
1315
|
+
end
|
|
1316
|
+
end
|
|
1317
|
+
|
|
1318
|
+
describe "storing sample data" do
|
|
1319
|
+
let(:transaction) { new_transaction }
|
|
1320
|
+
|
|
1321
|
+
it "stores sample data on the transaction" do
|
|
1322
|
+
transaction.set_params(
|
|
1323
|
+
"string_param" => "string_value",
|
|
1324
|
+
:symbol_param => "symbol_value",
|
|
1325
|
+
"integer" => 123,
|
|
1326
|
+
"float" => 123.45,
|
|
1327
|
+
"array" => ["abc", 456, { "option" => true }],
|
|
1328
|
+
"hash" => { "hash_key" => "hash_value" }
|
|
1329
|
+
)
|
|
1330
|
+
|
|
1331
|
+
transaction._sample
|
|
1332
|
+
expect(transaction).to include_params(
|
|
1333
|
+
"string_param" => "string_value",
|
|
1334
|
+
"symbol_param" => "symbol_value",
|
|
1335
|
+
"integer" => 123,
|
|
1336
|
+
"float" => 123.45,
|
|
1337
|
+
"array" => ["abc", 456, { "option" => true }],
|
|
1338
|
+
"hash" => { "hash_key" => "hash_value" }
|
|
1339
|
+
)
|
|
1340
|
+
end
|
|
868
1341
|
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
1342
|
+
it "does not store non-Array and non-Hash data" do
|
|
1343
|
+
logs =
|
|
1344
|
+
capture_logs do
|
|
1345
|
+
transaction.set_params("some string")
|
|
1346
|
+
transaction._sample
|
|
1347
|
+
expect(transaction).to_not include_params
|
|
1348
|
+
|
|
1349
|
+
transaction.set_params(123)
|
|
1350
|
+
transaction._sample
|
|
1351
|
+
expect(transaction).to_not include_params
|
|
1352
|
+
|
|
1353
|
+
transaction.set_params(Class.new)
|
|
1354
|
+
transaction._sample
|
|
1355
|
+
expect(transaction).to_not include_params
|
|
1356
|
+
|
|
1357
|
+
set = Set.new
|
|
1358
|
+
set.add("some value")
|
|
1359
|
+
transaction.set_params(set)
|
|
1360
|
+
transaction._sample
|
|
1361
|
+
expect(transaction).to_not include_params
|
|
878
1362
|
end
|
|
879
1363
|
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
1364
|
+
expect(logs).to contains_log :error,
|
|
1365
|
+
%(Invalid sample data for 'params'. Value is not an Array or Hash: '"some string"')
|
|
1366
|
+
expect(logs).to contains_log :error,
|
|
1367
|
+
%(Invalid sample data for 'params'. Value is not an Array or Hash: '123')
|
|
1368
|
+
expect(logs).to contains_log :error,
|
|
1369
|
+
%(Invalid sample data for 'params'. Value is not an Array or Hash: '"#<Class>"')
|
|
1370
|
+
expect(logs).to contains_log :error,
|
|
1371
|
+
%(Invalid sample data for 'params'. Value is not an Array or Hash: '"#<Set>"')
|
|
1372
|
+
end
|
|
886
1373
|
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
:name => "RuntimeError",
|
|
893
|
-
:message => "cause message"
|
|
894
|
-
},
|
|
895
|
-
{
|
|
896
|
-
:name => "StandardError",
|
|
897
|
-
:message => "cause message 2"
|
|
898
|
-
}
|
|
899
|
-
]
|
|
900
|
-
)
|
|
901
|
-
)
|
|
1374
|
+
it "does not store data that can't be converted to JSON" do
|
|
1375
|
+
klass = Class.new do
|
|
1376
|
+
def initialize
|
|
1377
|
+
@calls = 0
|
|
1378
|
+
end
|
|
902
1379
|
|
|
903
|
-
|
|
1380
|
+
def to_s
|
|
1381
|
+
raise "foo" if @calls > 0 # Cause a deliberate error
|
|
904
1382
|
|
|
905
|
-
|
|
1383
|
+
@calls += 1
|
|
906
1384
|
end
|
|
907
1385
|
end
|
|
908
1386
|
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
1387
|
+
transaction.set_params(klass.new => 1)
|
|
1388
|
+
logs = capture_logs { transaction._sample }
|
|
1389
|
+
|
|
1390
|
+
expect(transaction).to_not include_params
|
|
1391
|
+
expect(logs).to contains_log :error,
|
|
1392
|
+
"Error generating data (RuntimeError: foo) for"
|
|
1393
|
+
end
|
|
1394
|
+
end
|
|
1395
|
+
|
|
1396
|
+
describe "#set_sample_data" do
|
|
1397
|
+
let(:transaction) { new_transaction }
|
|
1398
|
+
|
|
1399
|
+
it "updates the sample data on the transaction" do
|
|
1400
|
+
silence do
|
|
1401
|
+
transaction.set_sample_data(
|
|
1402
|
+
"params",
|
|
1403
|
+
:controller => "blog_posts",
|
|
1404
|
+
:action => "show",
|
|
1405
|
+
:id => "1"
|
|
1406
|
+
)
|
|
1407
|
+
end
|
|
1408
|
+
|
|
1409
|
+
expect(transaction).to include_params(
|
|
1410
|
+
"action" => "show",
|
|
1411
|
+
"controller" => "blog_posts",
|
|
1412
|
+
"id" => "1"
|
|
1413
|
+
)
|
|
1414
|
+
end
|
|
912
1415
|
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
1416
|
+
context "when the data is no Array or Hash" do
|
|
1417
|
+
it "does not update the sample data on the transaction" do
|
|
1418
|
+
logs =
|
|
1419
|
+
capture_logs do
|
|
1420
|
+
silence { transaction.set_sample_data("params", "string") }
|
|
917
1421
|
end
|
|
918
1422
|
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
1423
|
+
expect(transaction.to_h["sample_data"]).to eq({})
|
|
1424
|
+
expect(logs).to contains_log :error,
|
|
1425
|
+
%(Invalid sample data for 'params'. Value is not an Array or Hash: '"string"')
|
|
1426
|
+
end
|
|
1427
|
+
end
|
|
1428
|
+
|
|
1429
|
+
context "when the data cannot be converted to JSON" do
|
|
1430
|
+
it "does not update the sample data on the transaction" do
|
|
1431
|
+
klass = Class.new do
|
|
1432
|
+
def to_s
|
|
1433
|
+
raise "foo" # Cause a deliberate error
|
|
1434
|
+
end
|
|
1435
|
+
end
|
|
1436
|
+
logs =
|
|
1437
|
+
capture_logs do
|
|
1438
|
+
silence { transaction.set_sample_data("params", klass.new => 1) }
|
|
1439
|
+
end
|
|
1440
|
+
|
|
1441
|
+
expect(transaction).to_not include_params
|
|
1442
|
+
expect(logs).to contains_log :error,
|
|
1443
|
+
"Error generating data (RuntimeError: foo) for"
|
|
1444
|
+
end
|
|
1445
|
+
end
|
|
1446
|
+
end
|
|
1447
|
+
|
|
1448
|
+
describe "#sample_data" do
|
|
1449
|
+
let(:transaction) { legacy_new_transaction(:request => rack_request(env)) }
|
|
1450
|
+
let(:env) do
|
|
1451
|
+
Rack::MockRequest.env_for(
|
|
1452
|
+
"/blog",
|
|
1453
|
+
"REQUEST_METHOD" => "GET",
|
|
1454
|
+
"SERVER_NAME" => "example.org",
|
|
1455
|
+
"SERVER_PORT" => "80",
|
|
1456
|
+
"PATH_INFO" => "/blog",
|
|
1457
|
+
"rack.session" => { "session" => "value" },
|
|
1458
|
+
:params => {
|
|
1459
|
+
"controller" => "blog_posts",
|
|
1460
|
+
"action" => "show",
|
|
1461
|
+
"id" => "1"
|
|
1462
|
+
}
|
|
1463
|
+
).merge(
|
|
1464
|
+
:metadata => { "metadata" => "value" }
|
|
1465
|
+
)
|
|
1466
|
+
end
|
|
1467
|
+
|
|
1468
|
+
it "sets sample data from request" do
|
|
1469
|
+
transaction.set_tags "tag" => "value"
|
|
1470
|
+
transaction.add_breadcrumb "category", "action", "message", "key" => "value"
|
|
1471
|
+
silence { transaction.sample_data }
|
|
1472
|
+
|
|
1473
|
+
expect(transaction).to include_environment(
|
|
1474
|
+
"REQUEST_METHOD" => "GET",
|
|
1475
|
+
"SERVER_NAME" => "example.org",
|
|
1476
|
+
"SERVER_PORT" => "80",
|
|
1477
|
+
"PATH_INFO" => "/blog"
|
|
1478
|
+
)
|
|
1479
|
+
expect(transaction).to include_session_data("session" => "value")
|
|
1480
|
+
expect(transaction).to include_params(
|
|
1481
|
+
"controller" => "blog_posts",
|
|
1482
|
+
"action" => "show",
|
|
1483
|
+
"id" => "1"
|
|
1484
|
+
)
|
|
1485
|
+
expect(transaction).to include_sample_metadata("metadata" => "value")
|
|
1486
|
+
expect(transaction).to include_tags("tag" => "value")
|
|
1487
|
+
expect(transaction).to include_breadcrumb(
|
|
1488
|
+
"action",
|
|
1489
|
+
"category",
|
|
1490
|
+
"message",
|
|
1491
|
+
{ "key" => "value" },
|
|
1492
|
+
kind_of(Integer)
|
|
1493
|
+
)
|
|
1494
|
+
end
|
|
1495
|
+
end
|
|
1496
|
+
|
|
1497
|
+
describe "#set_error" do
|
|
1498
|
+
let(:transaction) { new_transaction }
|
|
1499
|
+
let(:env) { http_request_env_with_data }
|
|
1500
|
+
let(:error) do
|
|
1501
|
+
e = ExampleStandardError.new("test message")
|
|
1502
|
+
allow(e).to receive(:backtrace).and_return(["line 1"])
|
|
1503
|
+
e
|
|
1504
|
+
end
|
|
1505
|
+
|
|
1506
|
+
it "should also respond to add_exception for backwards compatibility" do
|
|
1507
|
+
expect(transaction).to respond_to(:add_exception)
|
|
1508
|
+
end
|
|
1509
|
+
|
|
1510
|
+
it "should not add the error if appsignal is not active" do
|
|
1511
|
+
allow(Appsignal).to receive(:active?).and_return(false)
|
|
1512
|
+
expect(transaction.ext).to_not receive(:set_error)
|
|
1513
|
+
|
|
1514
|
+
transaction.set_error(error)
|
|
1515
|
+
end
|
|
1516
|
+
|
|
1517
|
+
context "when error is not an error" do
|
|
1518
|
+
let(:error) { Object.new }
|
|
1519
|
+
|
|
1520
|
+
it "does not add the error" do
|
|
1521
|
+
expect(Appsignal.internal_logger).to receive(:error).with(
|
|
1522
|
+
"Appsignal::Transaction#set_error: Cannot set error. " \
|
|
1523
|
+
"The given value is not an exception: #{error.inspect}"
|
|
1524
|
+
)
|
|
1525
|
+
expect(transaction.ext).to_not receive(:set_error)
|
|
1526
|
+
|
|
1527
|
+
transaction.set_error(error)
|
|
1528
|
+
end
|
|
1529
|
+
end
|
|
1530
|
+
|
|
1531
|
+
context "for a http request" do
|
|
1532
|
+
it "should set an error in the extension" do
|
|
1533
|
+
expect(transaction.ext).to receive(:set_error).with(
|
|
1534
|
+
"ExampleStandardError",
|
|
1535
|
+
"test message",
|
|
1536
|
+
Appsignal::Utils::Data.generate(["line 1"])
|
|
1537
|
+
)
|
|
1538
|
+
|
|
1539
|
+
transaction.set_error(error)
|
|
1540
|
+
end
|
|
1541
|
+
end
|
|
1542
|
+
|
|
1543
|
+
context "when the error has no causes" do
|
|
1544
|
+
it "should not send the causes information as sample data" do
|
|
1545
|
+
expect(transaction.ext).to_not receive(:set_sample_data)
|
|
1546
|
+
|
|
1547
|
+
transaction.set_error(error)
|
|
1548
|
+
end
|
|
1549
|
+
end
|
|
1550
|
+
|
|
1551
|
+
context "when the error has multiple causes" do
|
|
1552
|
+
let(:error) do
|
|
1553
|
+
e = ExampleStandardError.new("test message")
|
|
1554
|
+
e2 = RuntimeError.new("cause message")
|
|
1555
|
+
e3 = StandardError.new("cause message 2")
|
|
1556
|
+
allow(e).to receive(:backtrace).and_return(["line 1"])
|
|
1557
|
+
allow(e).to receive(:cause).and_return(e2)
|
|
1558
|
+
allow(e2).to receive(:cause).and_return(e3)
|
|
1559
|
+
e
|
|
1560
|
+
end
|
|
1561
|
+
|
|
1562
|
+
it "sends the causes information as sample data" do
|
|
1563
|
+
expect(transaction.ext).to receive(:set_error).with(
|
|
1564
|
+
"ExampleStandardError",
|
|
1565
|
+
"test message",
|
|
1566
|
+
Appsignal::Utils::Data.generate(["line 1"])
|
|
1567
|
+
)
|
|
922
1568
|
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
1569
|
+
expect(transaction.ext).to receive(:set_sample_data).with(
|
|
1570
|
+
"error_causes",
|
|
1571
|
+
Appsignal::Utils::Data.generate(
|
|
1572
|
+
[
|
|
1573
|
+
{
|
|
1574
|
+
:name => "RuntimeError",
|
|
1575
|
+
:message => "cause message"
|
|
1576
|
+
},
|
|
1577
|
+
{
|
|
1578
|
+
:name => "StandardError",
|
|
1579
|
+
:message => "cause message 2"
|
|
1580
|
+
}
|
|
1581
|
+
]
|
|
928
1582
|
)
|
|
1583
|
+
)
|
|
929
1584
|
|
|
930
|
-
|
|
931
|
-
{
|
|
932
|
-
:name => "ExampleStandardError",
|
|
933
|
-
:message => "wrapper error #{9 - i}"
|
|
934
|
-
}
|
|
935
|
-
end
|
|
936
|
-
|
|
937
|
-
expected_error_causes.last[:is_root_cause] = false
|
|
1585
|
+
expect(Appsignal.internal_logger).to_not receive(:debug)
|
|
938
1586
|
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
)
|
|
1587
|
+
transaction.set_error(error)
|
|
1588
|
+
end
|
|
1589
|
+
end
|
|
943
1590
|
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
"will be reported."
|
|
948
|
-
)
|
|
1591
|
+
context "when the error has too many causes" do
|
|
1592
|
+
let(:error) do
|
|
1593
|
+
e = ExampleStandardError.new("root cause error")
|
|
949
1594
|
|
|
950
|
-
|
|
1595
|
+
11.times do |i|
|
|
1596
|
+
next_e = ExampleStandardError.new("wrapper error #{i}")
|
|
1597
|
+
allow(next_e).to receive(:cause).and_return(e)
|
|
1598
|
+
e = next_e
|
|
951
1599
|
end
|
|
1600
|
+
|
|
1601
|
+
allow(e).to receive(:backtrace).and_return(["line 1"])
|
|
1602
|
+
e
|
|
952
1603
|
end
|
|
953
1604
|
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
end
|
|
1605
|
+
it "sends only the first causes as sample data" do
|
|
1606
|
+
expect(transaction.ext).to receive(:set_error).with(
|
|
1607
|
+
"ExampleStandardError",
|
|
1608
|
+
"wrapper error 10",
|
|
1609
|
+
Appsignal::Utils::Data.generate(["line 1"])
|
|
1610
|
+
)
|
|
961
1611
|
|
|
962
|
-
|
|
963
|
-
|
|
1612
|
+
expected_error_causes = Array.new(10) do |i|
|
|
1613
|
+
{
|
|
1614
|
+
:name => "ExampleStandardError",
|
|
1615
|
+
:message => "wrapper error #{9 - i}"
|
|
1616
|
+
}
|
|
964
1617
|
end
|
|
965
1618
|
|
|
966
|
-
|
|
967
|
-
expect(transaction.ext).to receive(:set_error).with(
|
|
968
|
-
"ExampleStandardError",
|
|
969
|
-
"",
|
|
970
|
-
Appsignal::Utils::Data.generate(["line 1"])
|
|
971
|
-
)
|
|
1619
|
+
expected_error_causes.last[:is_root_cause] = false
|
|
972
1620
|
|
|
973
|
-
|
|
974
|
-
|
|
1621
|
+
expect(transaction.ext).to receive(:set_sample_data).with(
|
|
1622
|
+
"error_causes",
|
|
1623
|
+
Appsignal::Utils::Data.generate(expected_error_causes)
|
|
1624
|
+
)
|
|
1625
|
+
|
|
1626
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(
|
|
1627
|
+
"Appsignal::Transaction#set_error: Error has more " \
|
|
1628
|
+
"than 10 error causes. Only the first 10 " \
|
|
1629
|
+
"will be reported."
|
|
1630
|
+
)
|
|
1631
|
+
|
|
1632
|
+
transaction.set_error(error)
|
|
975
1633
|
end
|
|
976
1634
|
end
|
|
977
1635
|
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
1636
|
+
context "when error message is nil" do
|
|
1637
|
+
let(:error) do
|
|
1638
|
+
e = ExampleStandardError.new
|
|
1639
|
+
allow(e).to receive(:message).and_return(nil)
|
|
1640
|
+
allow(e).to receive(:backtrace).and_return(["line 1"])
|
|
1641
|
+
e
|
|
1642
|
+
end
|
|
981
1643
|
|
|
982
|
-
|
|
1644
|
+
it "should not raise an error" do
|
|
1645
|
+
transaction.set_error(error)
|
|
983
1646
|
end
|
|
984
1647
|
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
1648
|
+
it "should set an error in the extension" do
|
|
1649
|
+
expect(transaction.ext).to receive(:set_error).with(
|
|
1650
|
+
"ExampleStandardError",
|
|
1651
|
+
"",
|
|
1652
|
+
Appsignal::Utils::Data.generate(["line 1"])
|
|
1653
|
+
)
|
|
989
1654
|
|
|
990
|
-
|
|
991
|
-
end
|
|
1655
|
+
transaction.set_error(error)
|
|
992
1656
|
end
|
|
993
1657
|
end
|
|
1658
|
+
end
|
|
994
1659
|
|
|
995
|
-
|
|
996
|
-
|
|
1660
|
+
describe "#start_event" do
|
|
1661
|
+
let(:transaction) { new_transaction }
|
|
997
1662
|
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
"name",
|
|
1001
|
-
"title",
|
|
1002
|
-
"body",
|
|
1003
|
-
1,
|
|
1004
|
-
fake_gc_time
|
|
1005
|
-
).and_call_original
|
|
1663
|
+
it "starts the event in the extension" do
|
|
1664
|
+
expect(transaction.ext).to receive(:start_event).with(0).and_call_original
|
|
1006
1665
|
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
"title",
|
|
1010
|
-
"body",
|
|
1011
|
-
1
|
|
1012
|
-
)
|
|
1013
|
-
end
|
|
1666
|
+
transaction.start_event
|
|
1667
|
+
end
|
|
1014
1668
|
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
"",
|
|
1020
|
-
0,
|
|
1021
|
-
fake_gc_time
|
|
1022
|
-
).and_call_original
|
|
1669
|
+
context "when transaction is paused" do
|
|
1670
|
+
it "does not start the event" do
|
|
1671
|
+
transaction.pause!
|
|
1672
|
+
expect(transaction.ext).to_not receive(:start_event)
|
|
1023
1673
|
|
|
1024
|
-
transaction.
|
|
1025
|
-
"name",
|
|
1026
|
-
nil,
|
|
1027
|
-
nil,
|
|
1028
|
-
nil
|
|
1029
|
-
)
|
|
1674
|
+
transaction.start_event
|
|
1030
1675
|
end
|
|
1676
|
+
end
|
|
1677
|
+
end
|
|
1031
1678
|
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1679
|
+
describe "#finish_event" do
|
|
1680
|
+
let(:transaction) { new_transaction }
|
|
1681
|
+
let(:fake_gc_time) { 0 }
|
|
1682
|
+
|
|
1683
|
+
it "should finish the event in the extension" do
|
|
1684
|
+
expect(transaction.ext).to receive(:finish_event).with(
|
|
1685
|
+
"name",
|
|
1686
|
+
"title",
|
|
1687
|
+
"body",
|
|
1688
|
+
1,
|
|
1689
|
+
fake_gc_time
|
|
1690
|
+
).and_call_original
|
|
1691
|
+
|
|
1692
|
+
transaction.finish_event(
|
|
1693
|
+
"name",
|
|
1694
|
+
"title",
|
|
1695
|
+
"body",
|
|
1696
|
+
1
|
|
1697
|
+
)
|
|
1040
1698
|
end
|
|
1041
1699
|
|
|
1042
|
-
|
|
1043
|
-
|
|
1700
|
+
it "should finish the event in the extension with nil arguments" do
|
|
1701
|
+
expect(transaction.ext).to receive(:finish_event).with(
|
|
1702
|
+
"name",
|
|
1703
|
+
"",
|
|
1704
|
+
"",
|
|
1705
|
+
0,
|
|
1706
|
+
fake_gc_time
|
|
1707
|
+
).and_call_original
|
|
1708
|
+
|
|
1709
|
+
transaction.finish_event(
|
|
1710
|
+
"name",
|
|
1711
|
+
nil,
|
|
1712
|
+
nil,
|
|
1713
|
+
nil
|
|
1714
|
+
)
|
|
1715
|
+
end
|
|
1044
1716
|
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
"body",
|
|
1050
|
-
1,
|
|
1051
|
-
1000,
|
|
1052
|
-
fake_gc_time
|
|
1053
|
-
).and_call_original
|
|
1717
|
+
context "when transaction is paused" do
|
|
1718
|
+
it "does not finish the event" do
|
|
1719
|
+
transaction.pause!
|
|
1720
|
+
expect(transaction.ext).to_not receive(:finish_event)
|
|
1054
1721
|
|
|
1055
|
-
transaction.
|
|
1056
|
-
"name",
|
|
1057
|
-
"title",
|
|
1058
|
-
"body",
|
|
1059
|
-
1000,
|
|
1060
|
-
1
|
|
1061
|
-
)
|
|
1722
|
+
transaction.start_event
|
|
1062
1723
|
end
|
|
1724
|
+
end
|
|
1725
|
+
end
|
|
1063
1726
|
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1727
|
+
describe "#record_event" do
|
|
1728
|
+
let(:transaction) { new_transaction }
|
|
1729
|
+
let(:fake_gc_time) { 0 }
|
|
1730
|
+
|
|
1731
|
+
it "should record the event in the extension" do
|
|
1732
|
+
expect(transaction.ext).to receive(:record_event).with(
|
|
1733
|
+
"name",
|
|
1734
|
+
"title",
|
|
1735
|
+
"body",
|
|
1736
|
+
1,
|
|
1737
|
+
1000,
|
|
1738
|
+
fake_gc_time
|
|
1739
|
+
).and_call_original
|
|
1740
|
+
|
|
1741
|
+
transaction.record_event(
|
|
1742
|
+
"name",
|
|
1743
|
+
"title",
|
|
1744
|
+
"body",
|
|
1745
|
+
1000,
|
|
1746
|
+
1
|
|
1747
|
+
)
|
|
1748
|
+
end
|
|
1749
|
+
|
|
1750
|
+
it "should finish the event in the extension with nil arguments" do
|
|
1751
|
+
expect(transaction.ext).to receive(:record_event).with(
|
|
1752
|
+
"name",
|
|
1753
|
+
"",
|
|
1754
|
+
"",
|
|
1755
|
+
0,
|
|
1756
|
+
1000,
|
|
1757
|
+
fake_gc_time
|
|
1758
|
+
).and_call_original
|
|
1759
|
+
|
|
1760
|
+
transaction.record_event(
|
|
1761
|
+
"name",
|
|
1762
|
+
nil,
|
|
1763
|
+
nil,
|
|
1764
|
+
1000,
|
|
1765
|
+
nil
|
|
1766
|
+
)
|
|
1767
|
+
end
|
|
1768
|
+
|
|
1769
|
+
context "when transaction is paused" do
|
|
1770
|
+
it "does not record the event" do
|
|
1771
|
+
transaction.pause!
|
|
1772
|
+
expect(transaction.ext).to_not receive(:record_event)
|
|
1073
1773
|
|
|
1074
1774
|
transaction.record_event(
|
|
1075
1775
|
"name",
|
|
@@ -1079,172 +1779,192 @@ describe Appsignal::Transaction do
|
|
|
1079
1779
|
nil
|
|
1080
1780
|
)
|
|
1081
1781
|
end
|
|
1782
|
+
end
|
|
1783
|
+
end
|
|
1082
1784
|
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
transaction.record_event(
|
|
1089
|
-
"name",
|
|
1090
|
-
nil,
|
|
1091
|
-
nil,
|
|
1092
|
-
1000,
|
|
1093
|
-
nil
|
|
1094
|
-
)
|
|
1095
|
-
end
|
|
1096
|
-
end
|
|
1785
|
+
describe "#instrument" do
|
|
1786
|
+
it_behaves_like "instrument helper" do
|
|
1787
|
+
let(:transaction) { new_transaction }
|
|
1788
|
+
let(:instrumenter) { transaction }
|
|
1097
1789
|
end
|
|
1790
|
+
end
|
|
1098
1791
|
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1792
|
+
context "GenericRequest" do
|
|
1793
|
+
let(:env) { {} }
|
|
1794
|
+
subject { Appsignal::Transaction::GenericRequest.new(env) }
|
|
1795
|
+
|
|
1796
|
+
it "prints a deprecation warning on use" do
|
|
1797
|
+
err_stream = std_stream
|
|
1798
|
+
capture_std_streams(std_stream, err_stream) { subject }
|
|
1799
|
+
|
|
1800
|
+
expect(err_stream.read).to include(
|
|
1801
|
+
"appsignal WARNING: The use of Appsignal::Transaction::GenericRequest is deprecated."
|
|
1802
|
+
)
|
|
1103
1803
|
end
|
|
1104
1804
|
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
subject { Appsignal::Transaction::GenericRequest.new(env) }
|
|
1805
|
+
it "logs a deprecation warning on use" do
|
|
1806
|
+
logs = capture_logs { silence { subject } }
|
|
1108
1807
|
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1808
|
+
expect(logs).to contains_log(
|
|
1809
|
+
:warn,
|
|
1810
|
+
"The use of Appsignal::Transaction::GenericRequest is deprecated."
|
|
1811
|
+
)
|
|
1812
|
+
end
|
|
1112
1813
|
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
:params => { :id => 1 },
|
|
1117
|
-
:queue_start => 10
|
|
1118
|
-
}
|
|
1119
|
-
end
|
|
1814
|
+
it "initializes with an empty env" do
|
|
1815
|
+
expect(subject.env).to be_empty
|
|
1816
|
+
end
|
|
1120
1817
|
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1818
|
+
context "when given an env" do
|
|
1819
|
+
let(:env) do
|
|
1820
|
+
{
|
|
1821
|
+
:params => { :id => 1 },
|
|
1822
|
+
:queue_start => 10
|
|
1823
|
+
}
|
|
1824
|
+
end
|
|
1124
1825
|
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
end
|
|
1826
|
+
it "sets the given env" do
|
|
1827
|
+
expect(subject.env).to eq env
|
|
1128
1828
|
end
|
|
1829
|
+
|
|
1830
|
+
it "sets the params present in the env" do
|
|
1831
|
+
expect(subject.params).to eq(:id => 1)
|
|
1832
|
+
end
|
|
1833
|
+
end
|
|
1834
|
+
end
|
|
1835
|
+
|
|
1836
|
+
# private
|
|
1837
|
+
|
|
1838
|
+
describe "#background_queue_start" do
|
|
1839
|
+
let(:transaction) { legacy_new_transaction(:request => request) }
|
|
1840
|
+
let(:request) { rack_request(env) }
|
|
1841
|
+
let(:env) { {} }
|
|
1842
|
+
subject { transaction.send(:background_queue_start) }
|
|
1843
|
+
|
|
1844
|
+
context "when request is nil" do
|
|
1845
|
+
let(:request) { nil }
|
|
1846
|
+
|
|
1847
|
+
it { is_expected.to eq nil }
|
|
1848
|
+
end
|
|
1849
|
+
|
|
1850
|
+
context "when env is nil" do
|
|
1851
|
+
before { expect(request).to receive(:env).and_return(nil) }
|
|
1852
|
+
|
|
1853
|
+
it { is_expected.to eq nil }
|
|
1854
|
+
end
|
|
1855
|
+
|
|
1856
|
+
context "when queue start is nil" do
|
|
1857
|
+
it { is_expected.to eq nil }
|
|
1129
1858
|
end
|
|
1130
1859
|
|
|
1131
|
-
|
|
1860
|
+
context "when queue start is set" do
|
|
1861
|
+
before do
|
|
1862
|
+
env[:queue_start] = fixed_time
|
|
1863
|
+
end
|
|
1864
|
+
|
|
1865
|
+
it { is_expected.to eq 1_389_783_600_000 }
|
|
1866
|
+
end
|
|
1867
|
+
end
|
|
1132
1868
|
|
|
1133
|
-
|
|
1134
|
-
|
|
1869
|
+
describe "#http_queue_start" do
|
|
1870
|
+
let(:transaction) { legacy_new_transaction(:request => request) }
|
|
1871
|
+
let(:request) { rack_request(env) }
|
|
1872
|
+
let(:env) { {} }
|
|
1873
|
+
let(:slightly_earlier_time) { fixed_time - 0.4 }
|
|
1874
|
+
let(:slightly_earlier_time_value) { (slightly_earlier_time * factor).to_i }
|
|
1875
|
+
subject { transaction.send(:http_queue_start) }
|
|
1135
1876
|
|
|
1877
|
+
shared_examples "http queue start" do
|
|
1136
1878
|
context "when request is nil" do
|
|
1137
1879
|
let(:request) { nil }
|
|
1138
1880
|
|
|
1139
|
-
it { is_expected.to
|
|
1881
|
+
it { is_expected.to be_nil }
|
|
1140
1882
|
end
|
|
1141
1883
|
|
|
1142
1884
|
context "when env is nil" do
|
|
1143
|
-
before { expect(
|
|
1144
|
-
|
|
1145
|
-
it { is_expected.to eq nil }
|
|
1146
|
-
end
|
|
1885
|
+
before { expect(request).to receive(:env).and_return(nil) }
|
|
1147
1886
|
|
|
1148
|
-
|
|
1149
|
-
it { is_expected.to eq nil }
|
|
1887
|
+
it { is_expected.to be_nil }
|
|
1150
1888
|
end
|
|
1151
1889
|
|
|
1152
|
-
context "
|
|
1153
|
-
let(:env) {
|
|
1890
|
+
context "with no relevant header set" do
|
|
1891
|
+
let(:env) { {} }
|
|
1154
1892
|
|
|
1155
|
-
it { is_expected.to
|
|
1893
|
+
it { is_expected.to be_nil }
|
|
1156
1894
|
end
|
|
1157
|
-
end
|
|
1158
1895
|
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
let(:slightly_earlier_time_value) { (slightly_earlier_time * factor).to_i }
|
|
1162
|
-
subject { transaction.send(:http_queue_start) }
|
|
1896
|
+
context "with the HTTP_X_REQUEST_START header set" do
|
|
1897
|
+
let(:env) { { "HTTP_X_REQUEST_START" => "t=#{slightly_earlier_time_value}" } }
|
|
1163
1898
|
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1899
|
+
it { is_expected.to eq 1_389_783_599_600 }
|
|
1900
|
+
|
|
1901
|
+
context "with unparsable content" do
|
|
1902
|
+
let(:env) { { "HTTP_X_REQUEST_START" => "something" } }
|
|
1167
1903
|
|
|
1168
1904
|
it { is_expected.to be_nil }
|
|
1169
1905
|
end
|
|
1170
1906
|
|
|
1171
|
-
context "
|
|
1172
|
-
|
|
1907
|
+
context "with unparsable content at the end" do
|
|
1908
|
+
let(:env) { { "HTTP_X_REQUEST_START" => "t=#{slightly_earlier_time_value}aaaa" } }
|
|
1173
1909
|
|
|
1174
|
-
it { is_expected.to
|
|
1910
|
+
it { is_expected.to eq 1_389_783_599_600 }
|
|
1175
1911
|
end
|
|
1176
1912
|
|
|
1177
|
-
context "with
|
|
1178
|
-
let(:env) { {} }
|
|
1913
|
+
context "with a really low number" do
|
|
1914
|
+
let(:env) { { "HTTP_X_REQUEST_START" => "t=100" } }
|
|
1179
1915
|
|
|
1180
1916
|
it { is_expected.to be_nil }
|
|
1181
1917
|
end
|
|
1182
1918
|
|
|
1183
|
-
context "with the
|
|
1184
|
-
let(:env) { { "
|
|
1919
|
+
context "with the alternate HTTP_X_QUEUE_START header set" do
|
|
1920
|
+
let(:env) { { "HTTP_X_QUEUE_START" => "t=#{slightly_earlier_time_value}" } }
|
|
1185
1921
|
|
|
1186
1922
|
it { is_expected.to eq 1_389_783_599_600 }
|
|
1187
|
-
|
|
1188
|
-
context "with unparsable content" do
|
|
1189
|
-
let(:env) { { "HTTP_X_REQUEST_START" => "something" } }
|
|
1190
|
-
|
|
1191
|
-
it { is_expected.to be_nil }
|
|
1192
|
-
end
|
|
1193
|
-
|
|
1194
|
-
context "with unparsable content at the end" do
|
|
1195
|
-
let(:env) { { "HTTP_X_REQUEST_START" => "t=#{slightly_earlier_time_value}aaaa" } }
|
|
1196
|
-
|
|
1197
|
-
it { is_expected.to eq 1_389_783_599_600 }
|
|
1198
|
-
end
|
|
1199
|
-
|
|
1200
|
-
context "with a really low number" do
|
|
1201
|
-
let(:env) { { "HTTP_X_REQUEST_START" => "t=100" } }
|
|
1202
|
-
|
|
1203
|
-
it { is_expected.to be_nil }
|
|
1204
|
-
end
|
|
1205
|
-
|
|
1206
|
-
context "with the alternate HTTP_X_QUEUE_START header set" do
|
|
1207
|
-
let(:env) { { "HTTP_X_QUEUE_START" => "t=#{slightly_earlier_time_value}" } }
|
|
1208
|
-
|
|
1209
|
-
it { is_expected.to eq 1_389_783_599_600 }
|
|
1210
|
-
end
|
|
1211
1923
|
end
|
|
1212
1924
|
end
|
|
1925
|
+
end
|
|
1213
1926
|
|
|
1214
|
-
|
|
1215
|
-
|
|
1927
|
+
context "time in milliseconds" do
|
|
1928
|
+
let(:factor) { 1_000 }
|
|
1216
1929
|
|
|
1217
|
-
|
|
1218
|
-
|
|
1930
|
+
it_should_behave_like "http queue start"
|
|
1931
|
+
end
|
|
1219
1932
|
|
|
1220
|
-
|
|
1221
|
-
|
|
1933
|
+
context "time in microseconds" do
|
|
1934
|
+
let(:factor) { 1_000_000 }
|
|
1222
1935
|
|
|
1223
|
-
|
|
1224
|
-
end
|
|
1936
|
+
it_should_behave_like "http queue start"
|
|
1225
1937
|
end
|
|
1938
|
+
end
|
|
1226
1939
|
|
|
1227
|
-
|
|
1228
|
-
|
|
1940
|
+
describe "#sanitized_params" do
|
|
1941
|
+
let(:transaction) { new_transaction }
|
|
1942
|
+
subject { transaction.send(:sanitized_params) }
|
|
1229
1943
|
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1944
|
+
context "with params" do
|
|
1945
|
+
before do
|
|
1946
|
+
transaction.set_params(:foo => "bar", :baz => :bat)
|
|
1947
|
+
end
|
|
1234
1948
|
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1949
|
+
it "returns params" do
|
|
1950
|
+
is_expected.to eq(:foo => "bar", :baz => :bat)
|
|
1951
|
+
end
|
|
1238
1952
|
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1953
|
+
context "with AppSignal filtering" do
|
|
1954
|
+
before { Appsignal.config.config_hash[:filter_parameters] = %w[foo] }
|
|
1955
|
+
after { Appsignal.config.config_hash[:filter_parameters] = [] }
|
|
1242
1956
|
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
end
|
|
1957
|
+
it "returns sanitized custom params" do
|
|
1958
|
+
expect(subject).to eq(:foo => "[FILTERED]", :baz => :bat)
|
|
1246
1959
|
end
|
|
1247
1960
|
end
|
|
1961
|
+
end
|
|
1962
|
+
|
|
1963
|
+
context "params from request" do
|
|
1964
|
+
let(:transaction) { legacy_new_transaction(:request => request, :options => options) }
|
|
1965
|
+
let(:options) { {} }
|
|
1966
|
+
let(:request) { rack_request(env) }
|
|
1967
|
+
let(:env) { {} }
|
|
1248
1968
|
|
|
1249
1969
|
context "without request params" do
|
|
1250
1970
|
before { allow(transaction.request).to receive(:params).and_return(nil) }
|
|
@@ -1253,7 +1973,7 @@ describe Appsignal::Transaction do
|
|
|
1253
1973
|
end
|
|
1254
1974
|
|
|
1255
1975
|
context "when request params crashes" do
|
|
1256
|
-
before {
|
|
1976
|
+
before { expect(request).to receive(:params).and_raise(NoMethodError) }
|
|
1257
1977
|
|
|
1258
1978
|
it { is_expected.to be_nil }
|
|
1259
1979
|
end
|
|
@@ -1272,11 +1992,7 @@ describe Appsignal::Transaction do
|
|
|
1272
1992
|
end
|
|
1273
1993
|
|
|
1274
1994
|
context "with an array" do
|
|
1275
|
-
let(:request)
|
|
1276
|
-
Appsignal::Transaction::GenericRequest.new(
|
|
1277
|
-
background_env_with_data(:params => %w[arg1 arg2])
|
|
1278
|
-
)
|
|
1279
|
-
end
|
|
1995
|
+
let(:request) { legacy_request(:params => %w[arg1 arg2]) }
|
|
1280
1996
|
|
|
1281
1997
|
it { is_expected.to eq %w[arg1 arg2] }
|
|
1282
1998
|
|
|
@@ -1290,11 +2006,7 @@ describe Appsignal::Transaction do
|
|
|
1290
2006
|
|
|
1291
2007
|
context "with env" do
|
|
1292
2008
|
context "with sanitization" do
|
|
1293
|
-
let(:request)
|
|
1294
|
-
Appsignal::Transaction::GenericRequest.new(
|
|
1295
|
-
http_request_env_with_data(:params => { :foo => :bar })
|
|
1296
|
-
)
|
|
1297
|
-
end
|
|
2009
|
+
let(:request) { legacy_request(:params => { :foo => :bar }) }
|
|
1298
2010
|
|
|
1299
2011
|
it "should call the params sanitizer" do
|
|
1300
2012
|
expect(subject).to eq(:foo => :bar)
|
|
@@ -1302,11 +2014,7 @@ describe Appsignal::Transaction do
|
|
|
1302
2014
|
end
|
|
1303
2015
|
|
|
1304
2016
|
context "with AppSignal filtering" do
|
|
1305
|
-
let(:request)
|
|
1306
|
-
Appsignal::Transaction::GenericRequest.new(
|
|
1307
|
-
http_request_env_with_data(:params => { :foo => :bar, :baz => :bat })
|
|
1308
|
-
)
|
|
1309
|
-
end
|
|
2017
|
+
let(:request) { legacy_request(:params => { :foo => :bar, :baz => :bat }) }
|
|
1310
2018
|
before { Appsignal.config.config_hash[:filter_parameters] = %w[foo] }
|
|
1311
2019
|
after { Appsignal.config.config_hash[:filter_parameters] = [] }
|
|
1312
2020
|
|
|
@@ -1316,93 +2024,139 @@ describe Appsignal::Transaction do
|
|
|
1316
2024
|
end
|
|
1317
2025
|
end
|
|
1318
2026
|
end
|
|
2027
|
+
end
|
|
1319
2028
|
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
2029
|
+
describe "#sanitized_environment" do
|
|
2030
|
+
let(:transaction) { legacy_new_transaction(:request => request) }
|
|
2031
|
+
let(:request) { rack_request(env) }
|
|
2032
|
+
let(:env) { {} }
|
|
2033
|
+
let(:allowlisted_keys) { Appsignal.config[:request_headers] }
|
|
2034
|
+
subject { transaction.send(:sanitized_environment) }
|
|
1323
2035
|
|
|
1324
|
-
|
|
1325
|
-
|
|
2036
|
+
context "when request is nil" do
|
|
2037
|
+
let(:request) { nil }
|
|
1326
2038
|
|
|
1327
|
-
|
|
1328
|
-
|
|
2039
|
+
it { is_expected.to be_nil }
|
|
2040
|
+
end
|
|
1329
2041
|
|
|
1330
|
-
|
|
1331
|
-
|
|
2042
|
+
context "when env is nil" do
|
|
2043
|
+
before { expect(request).to receive(:env).and_return(nil) }
|
|
1332
2044
|
|
|
1333
|
-
|
|
2045
|
+
it { is_expected.to be_nil }
|
|
2046
|
+
end
|
|
2047
|
+
|
|
2048
|
+
context "when env is present" do
|
|
2049
|
+
let(:env) do
|
|
2050
|
+
{}.tap do |hash|
|
|
2051
|
+
allowlisted_keys.each { |o| hash[o] = 1 } # use all allowlisted keys
|
|
2052
|
+
hash[allowlisted_keys] = nil # don't add if nil
|
|
2053
|
+
hash[:not_allowlisted] = "I will be sanitized"
|
|
2054
|
+
end
|
|
1334
2055
|
end
|
|
1335
2056
|
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
2057
|
+
it "only sets allowlisted keys" do
|
|
2058
|
+
expect(subject.keys).to match_array(allowlisted_keys)
|
|
2059
|
+
end
|
|
2060
|
+
|
|
2061
|
+
context "with configured request_headers" do
|
|
2062
|
+
before do
|
|
2063
|
+
Appsignal.config.config_hash[:request_headers] = %w[CONTENT_LENGTH]
|
|
1343
2064
|
end
|
|
1344
2065
|
|
|
1345
2066
|
it "only sets allowlisted keys" do
|
|
1346
|
-
expect(subject.keys).to match_array(
|
|
2067
|
+
expect(subject.keys).to match_array(%w[CONTENT_LENGTH])
|
|
1347
2068
|
end
|
|
2069
|
+
end
|
|
2070
|
+
end
|
|
2071
|
+
end
|
|
1348
2072
|
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
2073
|
+
describe "#sanitized_session_data" do
|
|
2074
|
+
let(:transaction) { legacy_new_transaction(:request => request) }
|
|
2075
|
+
let(:request) { rack_request(env) }
|
|
2076
|
+
let(:env) { {} }
|
|
2077
|
+
subject { transaction.send(:sanitized_session_data) }
|
|
1353
2078
|
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
end
|
|
2079
|
+
context "when request is nil" do
|
|
2080
|
+
let(:request) { nil }
|
|
2081
|
+
|
|
2082
|
+
it { is_expected.to be_nil }
|
|
1359
2083
|
end
|
|
1360
2084
|
|
|
1361
|
-
|
|
1362
|
-
|
|
2085
|
+
context "when session is nil" do
|
|
2086
|
+
before { expect(transaction.request).to receive(:session).and_return(nil) }
|
|
1363
2087
|
|
|
1364
|
-
|
|
1365
|
-
|
|
2088
|
+
it { is_expected.to be_nil }
|
|
2089
|
+
end
|
|
1366
2090
|
|
|
1367
|
-
|
|
1368
|
-
|
|
2091
|
+
context "when session is empty" do
|
|
2092
|
+
before { expect(transaction.request).to receive(:session).and_return({}) }
|
|
1369
2093
|
|
|
1370
|
-
|
|
1371
|
-
|
|
2094
|
+
it { is_expected.to eq({}) }
|
|
2095
|
+
end
|
|
1372
2096
|
|
|
1373
|
-
|
|
1374
|
-
|
|
2097
|
+
context "when request class does not have a session method" do
|
|
2098
|
+
let(:request) { Appsignal::Transaction::GenericRequest.new({}) }
|
|
2099
|
+
|
|
2100
|
+
it { is_expected.to be_nil }
|
|
2101
|
+
end
|
|
1375
2102
|
|
|
1376
|
-
|
|
1377
|
-
|
|
2103
|
+
context "with a session" do
|
|
2104
|
+
let(:session_data_filter) { [] }
|
|
2105
|
+
before { Appsignal.config[:filter_session_data] = session_data_filter }
|
|
2106
|
+
after { Appsignal.config[:filter_session_data] = [] }
|
|
1378
2107
|
|
|
1379
|
-
|
|
1380
|
-
|
|
2108
|
+
context "with generic session object" do
|
|
2109
|
+
before do
|
|
2110
|
+
expect(transaction).to respond_to(:request)
|
|
2111
|
+
allow(transaction).to receive_message_chain(
|
|
2112
|
+
:request,
|
|
2113
|
+
:session => { :foo => :bar, :abc => :def }
|
|
2114
|
+
)
|
|
2115
|
+
allow(transaction).to receive_message_chain(:request, :fullpath => :bar)
|
|
2116
|
+
end
|
|
2117
|
+
|
|
2118
|
+
context "without session filtering" do
|
|
2119
|
+
it "keeps the session data intact" do
|
|
2120
|
+
expect(subject).to eq(:foo => :bar, :abc => :def)
|
|
2121
|
+
end
|
|
2122
|
+
end
|
|
1381
2123
|
|
|
1382
|
-
|
|
1383
|
-
|
|
2124
|
+
context "with session filtering" do
|
|
2125
|
+
let(:session_data_filter) { %w[foo] }
|
|
1384
2126
|
|
|
1385
|
-
|
|
2127
|
+
it "filters the session data" do
|
|
2128
|
+
expect(subject).to eq(:foo => "[FILTERED]", :abc => :def)
|
|
2129
|
+
end
|
|
2130
|
+
end
|
|
1386
2131
|
end
|
|
1387
2132
|
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
2133
|
+
if defined? ActionDispatch::Request::Session
|
|
2134
|
+
context "with ActionDispatch::Request::Session" do
|
|
2135
|
+
let(:action_dispatch_session) do
|
|
2136
|
+
store = Class.new do
|
|
2137
|
+
def load_session(_env)
|
|
2138
|
+
[1, { :foo => :bar, :abc => :def }]
|
|
2139
|
+
end
|
|
1392
2140
|
|
|
1393
|
-
|
|
2141
|
+
def session_exists?(_env)
|
|
2142
|
+
true
|
|
2143
|
+
end
|
|
2144
|
+
end.new
|
|
2145
|
+
ActionDispatch::Request::Session.create(store,
|
|
2146
|
+
ActionDispatch::Request.new("rack.input" => StringIO.new), {})
|
|
2147
|
+
end
|
|
1394
2148
|
before do
|
|
1395
2149
|
expect(transaction).to respond_to(:request)
|
|
1396
2150
|
allow(transaction).to receive_message_chain(
|
|
1397
2151
|
:request,
|
|
1398
|
-
:session =>
|
|
2152
|
+
:session => action_dispatch_session
|
|
1399
2153
|
)
|
|
1400
2154
|
allow(transaction).to receive_message_chain(:request, :fullpath => :bar)
|
|
1401
2155
|
end
|
|
1402
2156
|
|
|
1403
2157
|
context "without session filtering" do
|
|
1404
2158
|
it "keeps the session data intact" do
|
|
1405
|
-
expect(subject).to eq(
|
|
2159
|
+
expect(subject).to eq("foo" => :bar, "abc" => :def)
|
|
1406
2160
|
end
|
|
1407
2161
|
end
|
|
1408
2162
|
|
|
@@ -1410,120 +2164,87 @@ describe Appsignal::Transaction do
|
|
|
1410
2164
|
let(:session_data_filter) { %w[foo] }
|
|
1411
2165
|
|
|
1412
2166
|
it "filters the session data" do
|
|
1413
|
-
expect(subject).to eq(
|
|
1414
|
-
end
|
|
1415
|
-
end
|
|
1416
|
-
end
|
|
1417
|
-
|
|
1418
|
-
if defined? ActionDispatch::Request::Session
|
|
1419
|
-
context "with ActionDispatch::Request::Session" do
|
|
1420
|
-
let(:action_dispatch_session) do
|
|
1421
|
-
store = Class.new do
|
|
1422
|
-
def load_session(_env)
|
|
1423
|
-
[1, { :foo => :bar, :abc => :def }]
|
|
1424
|
-
end
|
|
1425
|
-
|
|
1426
|
-
def session_exists?(_env)
|
|
1427
|
-
true
|
|
1428
|
-
end
|
|
1429
|
-
end.new
|
|
1430
|
-
ActionDispatch::Request::Session.create(store,
|
|
1431
|
-
ActionDispatch::Request.new("rack.input" => StringIO.new), {})
|
|
1432
|
-
end
|
|
1433
|
-
before do
|
|
1434
|
-
expect(transaction).to respond_to(:request)
|
|
1435
|
-
allow(transaction).to receive_message_chain(
|
|
1436
|
-
:request,
|
|
1437
|
-
:session => action_dispatch_session
|
|
1438
|
-
)
|
|
1439
|
-
allow(transaction).to receive_message_chain(:request, :fullpath => :bar)
|
|
1440
|
-
end
|
|
1441
|
-
|
|
1442
|
-
context "without session filtering" do
|
|
1443
|
-
it "keeps the session data intact" do
|
|
1444
|
-
expect(subject).to eq("foo" => :bar, "abc" => :def)
|
|
1445
|
-
end
|
|
1446
|
-
end
|
|
1447
|
-
|
|
1448
|
-
context "with session filtering" do
|
|
1449
|
-
let(:session_data_filter) { %w[foo] }
|
|
1450
|
-
|
|
1451
|
-
it "filters the session data" do
|
|
1452
|
-
expect(subject).to eq("foo" => "[FILTERED]", "abc" => :def)
|
|
1453
|
-
end
|
|
2167
|
+
expect(subject).to eq("foo" => "[FILTERED]", "abc" => :def)
|
|
1454
2168
|
end
|
|
1455
2169
|
end
|
|
1456
2170
|
end
|
|
2171
|
+
end
|
|
1457
2172
|
|
|
1458
|
-
|
|
1459
|
-
|
|
2173
|
+
context "when not sending session data" do
|
|
2174
|
+
before { Appsignal.config[:send_session_data] = false }
|
|
1460
2175
|
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
end
|
|
2176
|
+
it "does not set any session data on the transaction" do
|
|
2177
|
+
expect(subject).to be_nil
|
|
1464
2178
|
end
|
|
1465
2179
|
end
|
|
1466
2180
|
end
|
|
2181
|
+
end
|
|
1467
2182
|
|
|
1468
|
-
|
|
1469
|
-
|
|
2183
|
+
describe "#sanitized_metadata" do
|
|
2184
|
+
let(:transaction) { legacy_new_transaction(:request => request) }
|
|
2185
|
+
let(:request) { rack_request(env) }
|
|
2186
|
+
let(:env) { {} }
|
|
2187
|
+
subject { transaction.send(:sanitized_metadata) }
|
|
1470
2188
|
|
|
1471
|
-
|
|
1472
|
-
|
|
2189
|
+
context "when request is nil" do
|
|
2190
|
+
let(:request) { nil }
|
|
1473
2191
|
|
|
1474
|
-
|
|
1475
|
-
|
|
2192
|
+
it { is_expected.to be_nil }
|
|
2193
|
+
end
|
|
1476
2194
|
|
|
1477
|
-
|
|
1478
|
-
|
|
2195
|
+
context "when env is nil" do
|
|
2196
|
+
before { expect(request).to receive(:env).and_return(nil) }
|
|
1479
2197
|
|
|
1480
|
-
|
|
1481
|
-
|
|
2198
|
+
it { is_expected.to be_nil }
|
|
2199
|
+
end
|
|
1482
2200
|
|
|
1483
|
-
|
|
1484
|
-
|
|
2201
|
+
context "when env is present" do
|
|
2202
|
+
let(:env) { { :metadata => { "key" => "value" } } }
|
|
1485
2203
|
|
|
1486
|
-
|
|
2204
|
+
it do
|
|
2205
|
+
is_expected.to eq("key" => "value")
|
|
2206
|
+
end
|
|
1487
2207
|
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
2208
|
+
context "with filter_metadata option set" do
|
|
2209
|
+
before { Appsignal.config[:filter_metadata] = ["key"] }
|
|
2210
|
+
after { Appsignal.config[:filter_metadata] = [] }
|
|
1491
2211
|
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
end
|
|
2212
|
+
it "filters out keys listed in the filter_metadata option" do
|
|
2213
|
+
expect(subject.keys).to_not include("key")
|
|
1495
2214
|
end
|
|
1496
2215
|
end
|
|
1497
2216
|
end
|
|
2217
|
+
end
|
|
1498
2218
|
|
|
1499
|
-
|
|
1500
|
-
|
|
2219
|
+
describe "#cleaned_backtrace" do
|
|
2220
|
+
let(:transaction) { new_transaction }
|
|
2221
|
+
subject { transaction.send(:cleaned_backtrace, ["line 1", "line 2"]) }
|
|
1501
2222
|
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
2223
|
+
it "returns the backtrace" do
|
|
2224
|
+
expect(subject).to eq ["line 1", "line 2"]
|
|
2225
|
+
end
|
|
1505
2226
|
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
end
|
|
2227
|
+
context "with Rails module but without backtrace_cleaner method" do
|
|
2228
|
+
it "returns the backtrace uncleaned" do
|
|
2229
|
+
stub_const("Rails", Module.new)
|
|
2230
|
+
expect(subject).to eq ["line 1", "line 2"]
|
|
1511
2231
|
end
|
|
2232
|
+
end
|
|
1512
2233
|
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
end
|
|
1519
|
-
expect(subject).to eq ["line 1", "line ?"]
|
|
2234
|
+
if rails_present?
|
|
2235
|
+
context "with rails" do
|
|
2236
|
+
it "cleans the backtrace with the Rails backtrace cleaner" do
|
|
2237
|
+
::Rails.backtrace_cleaner.add_filter do |line|
|
|
2238
|
+
line.tr("2", "?")
|
|
1520
2239
|
end
|
|
2240
|
+
expect(subject).to eq ["line 1", "line ?"]
|
|
1521
2241
|
end
|
|
1522
2242
|
end
|
|
1523
2243
|
end
|
|
1524
2244
|
end
|
|
1525
2245
|
|
|
1526
2246
|
describe "#cleaned_error_message" do
|
|
2247
|
+
let(:transaction) { new_transaction }
|
|
1527
2248
|
let(:error) { StandardError.new("Error message") }
|
|
1528
2249
|
subject { transaction.send(:cleaned_error_message, error) }
|
|
1529
2250
|
|
|
@@ -1570,6 +2291,7 @@ describe Appsignal::Transaction do
|
|
|
1570
2291
|
end
|
|
1571
2292
|
|
|
1572
2293
|
describe ".to_hash / .to_h" do
|
|
2294
|
+
let(:transaction) { new_transaction }
|
|
1573
2295
|
subject { transaction.to_hash }
|
|
1574
2296
|
|
|
1575
2297
|
context "when extension returns serialized JSON" do
|
|
@@ -1578,9 +2300,9 @@ describe Appsignal::Transaction do
|
|
|
1578
2300
|
"action" => nil,
|
|
1579
2301
|
"error" => nil,
|
|
1580
2302
|
"events" => [],
|
|
1581
|
-
"id" =>
|
|
2303
|
+
"id" => kind_of(String),
|
|
1582
2304
|
"metadata" => {},
|
|
1583
|
-
"namespace" =>
|
|
2305
|
+
"namespace" => default_namespace,
|
|
1584
2306
|
"sample_data" => {}
|
|
1585
2307
|
)
|
|
1586
2308
|
end
|
|
@@ -1613,7 +2335,7 @@ describe Appsignal::Transaction do
|
|
|
1613
2335
|
subject.set_http_or_background_queue_start
|
|
1614
2336
|
subject.set_metadata("key", "value")
|
|
1615
2337
|
subject.set_sample_data("key", "data")
|
|
1616
|
-
subject.
|
|
2338
|
+
subject._sample
|
|
1617
2339
|
subject.set_error("a")
|
|
1618
2340
|
end
|
|
1619
2341
|
end
|