Skip to content

Commit 6e67999

Browse files
committed
Report response status when there is no response
When there is no response object given to the EventHandler's `on_finish` callback, we can expect an unhandled error has occurred. When have also received an exception in the `on_error` callback, report the response status as 500. This solution is not perfect. It may actually be another response status if something else above the EventHandler handles the exception. A setup we don't recommend.
1 parent d299589 commit 6e67999

File tree

3 files changed

+82
-20
lines changed

3 files changed

+82
-20
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
bump: patch
3+
type: add
4+
---
5+
6+
Track error response status for web requests. When an unhandled exception reaches the AppSignal EventHandler instrumentation, report the response status as `500` for the `response_status` tag on the transaction and on the `response_status` metric.

lib/appsignal/rack/event_handler.rb

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ module Appsignal
44
module Rack
55
APPSIGNAL_TRANSACTION = "appsignal.transaction"
66
APPSIGNAL_EVENT_HANDLER_ID = "appsignal.event_handler_id"
7+
APPSIGNAL_EVENT_HANDLER_HAS_ERROR = "appsignal.event_handler.error"
78
RACK_AFTER_REPLY = "rack.after_reply"
89

910
# @api private
@@ -71,6 +72,7 @@ def on_error(request, _response, error)
7172
transaction = request.env[APPSIGNAL_TRANSACTION]
7273
return unless transaction
7374

75+
request.env[APPSIGNAL_EVENT_HANDLER_HAS_ERROR] = true
7476
transaction.set_error(error)
7577
end
7678
end
@@ -84,12 +86,18 @@ def on_finish(request, response)
8486
self.class.safe_execution("Appsignal::Rack::EventHandler#on_finish") do
8587
transaction.finish_event("process_request.rack", "", "")
8688
transaction.set_http_or_background_queue_start
87-
if response
88-
transaction.set_tags(:response_status => response.status)
89+
response_status =
90+
if response
91+
response.status
92+
elsif request.env[APPSIGNAL_EVENT_HANDLER_HAS_ERROR] == true
93+
500
94+
end
95+
if response_status
96+
transaction.set_tags(:response_status => response_status)
8997
Appsignal.increment_counter(
9098
:response_status,
9199
1,
92-
:status => response.status,
100+
:status => response_status,
93101
:namespace => format_namespace(transaction.namespace)
94102
)
95103
end

spec/lib/appsignal/rack/event_handler_spec.rb

Lines changed: 65 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ def on_start
2222
event_handler_instance.on_start(request, response)
2323
end
2424

25+
def on_error(error)
26+
event_handler_instance.on_error(request, response, error)
27+
end
28+
2529
describe "#on_start" do
2630
it "creates a new transaction" do
2731
expect { on_start }.to change { created_transactions.length }.by(1)
@@ -119,10 +123,6 @@ def on_start
119123
end
120124

121125
describe "#on_error" do
122-
def on_error(error)
123-
event_handler_instance.on_error(request, response, error)
124-
end
125-
126126
it "reports the error" do
127127
on_start
128128
on_error(ExampleStandardError.new("the error"))
@@ -235,6 +235,29 @@ def on_finish(given_request = request, given_response = response)
235235
on_start
236236
on_finish(request, nil)
237237
end
238+
239+
context "with an error previously recorded by on_error" do
240+
it "sets response status 500 as a tag" do
241+
on_start
242+
on_error(ExampleStandardError.new("the error"))
243+
on_finish(request, nil)
244+
245+
expect(last_transaction.to_h).to include(
246+
"sample_data" => hash_including(
247+
"tags" => { "response_status" => 500 }
248+
)
249+
)
250+
end
251+
252+
it "increments the response status counter for response status 500" do
253+
expect(Appsignal).to receive(:increment_counter)
254+
.with(:response_status, 1, :status => 500, :namespace => :web)
255+
256+
on_start
257+
on_error(ExampleStandardError.new("the error"))
258+
on_finish(request, nil)
259+
end
260+
end
238261
end
239262

240263
context "with error inside on_finish handler" do
@@ -296,23 +319,48 @@ def on_finish(given_request = request, given_response = response)
296319
)
297320
end
298321

299-
it "sets the response status as a tag" do
300-
on_start
301-
on_finish
322+
context "with response" do
323+
it "sets the response status as a tag" do
324+
on_start
325+
on_finish
302326

303-
expect(last_transaction.to_h).to include(
304-
"sample_data" => hash_including(
305-
"tags" => { "response_status" => 200 }
327+
expect(last_transaction.to_h).to include(
328+
"sample_data" => hash_including(
329+
"tags" => { "response_status" => 200 }
330+
)
306331
)
307-
)
308-
end
332+
end
309333

310-
it "increments the response status counter for response status" do
311-
expect(Appsignal).to receive(:increment_counter)
312-
.with(:response_status, 1, :status => 200, :namespace => :web)
334+
it "increments the response status counter for response status" do
335+
expect(Appsignal).to receive(:increment_counter)
336+
.with(:response_status, 1, :status => 200, :namespace => :web)
313337

314-
on_start
315-
on_finish
338+
on_start
339+
on_finish
340+
end
341+
342+
context "with an error previously recorded by on_error" do
343+
it "sets response status from the response as a tag" do
344+
on_start
345+
on_error(ExampleStandardError.new("the error"))
346+
on_finish
347+
348+
expect(last_transaction.to_h).to include(
349+
"sample_data" => hash_including(
350+
"tags" => { "response_status" => 200 }
351+
)
352+
)
353+
end
354+
355+
it "increments the response status counter based on the response" do
356+
expect(Appsignal).to receive(:increment_counter)
357+
.with(:response_status, 1, :status => 200, :namespace => :web)
358+
359+
on_start
360+
on_error(ExampleStandardError.new("the error"))
361+
on_finish
362+
end
363+
end
316364
end
317365

318366
it "logs an error in case of an error" do

0 commit comments

Comments
 (0)