Skip to content

Commit bed374a

Browse files
committed
ensure errors are recorded for uncaught exceptions
Add tests that demonstrate that Guzzle instrumentation does not affect agent's ability to record errors when uncaught exception is thrown.
1 parent 13db036 commit bed374a

File tree

2 files changed

+326
-0
lines changed

2 files changed

+326
-0
lines changed
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
<?php
2+
/*
3+
* Copyright 2020 New Relic Corporation. All rights reserved.
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/*DESCRIPTION
8+
Test that the span for a sync external request that ends up throwing an uncaught BadResponseException
9+
is marked as http, uri and status code are captured. Additionally, test that exception is recorded
10+
as traced error, error event, and the root span has error attributes.
11+
*/
12+
13+
/*SKIPIF
14+
<?php
15+
require("skipif.inc");
16+
*/
17+
18+
/*INI
19+
newrelic.distributed_tracing_enabled = true
20+
newrelic.transaction_tracer.threshold = 0
21+
newrelic.transaction_tracer.detail = 1
22+
newrelic.code_level_metrics.enabled = 0
23+
log_errors=0
24+
display_errors=1
25+
*/
26+
27+
/*ENVIRONMENT
28+
TEST_EXTERNAL_HOST=example.com
29+
*/
30+
31+
/*EXPECT_METRICS_EXIST
32+
External/ENV[TEST_EXTERNAL_HOST]/all
33+
*/
34+
35+
/*EXPECT_SPAN_EVENTS_LIKE
36+
[
37+
[
38+
{
39+
"category": "generic",
40+
"type": "Span",
41+
"guid": "??",
42+
"traceId": "??",
43+
"transactionId": "??",
44+
"name": "OtherTransaction/php__FILE__",
45+
"timestamp": "??",
46+
"duration": "??",
47+
"priority": "??",
48+
"sampled": true,
49+
"nr.entryPoint": true,
50+
"transaction.name": "OtherTransaction/php__FILE__"
51+
},
52+
{},
53+
{
54+
"error.message": "Uncaught exception 'GuzzleHttp\\Exception\\BadResponseException' with message 'ClientException' in __FILE__:??",
55+
"error.class": "GuzzleHttp\\Exception\\BadResponseException"
56+
}
57+
],
58+
[
59+
{
60+
"traceId": "??",
61+
"duration": "??",
62+
"transactionId": "??",
63+
"name": "External/ENV[TEST_EXTERNAL_HOST]/all",
64+
"guid": "??",
65+
"type": "Span",
66+
"category": "http",
67+
"priority": "??",
68+
"sampled": true,
69+
"timestamp": "??",
70+
"parentId": "??",
71+
"span.kind": "client",
72+
"component": "Guzzle 6"
73+
},
74+
{},
75+
{
76+
"http.url": "http://ENV[TEST_EXTERNAL_HOST]/resource",
77+
"http.method": "GET",
78+
"http.statusCode": 404
79+
}
80+
]
81+
]
82+
*/
83+
84+
/*EXPECT_TRACED_ERRORS
85+
[
86+
"?? agent run id",
87+
[
88+
[
89+
"?? when",
90+
"OtherTransaction/php__FILE__",
91+
"Uncaught exception 'GuzzleHttp\\Exception\\BadResponseException' with message 'ClientException' in __FILE__:??",
92+
"GuzzleHttp\\Exception\\BadResponseException",
93+
{
94+
"stack_trace": [],
95+
"agentAttributes": "??",
96+
"intrinsics": "??"
97+
},
98+
"?? transaction ID"
99+
]
100+
]
101+
]
102+
*/
103+
104+
/*EXPECT_ERROR_EVENTS
105+
[
106+
"?? agent run id",
107+
{
108+
"reservoir_size": "??",
109+
"events_seen": 1
110+
},
111+
[
112+
[
113+
{
114+
"type": "TransactionError",
115+
"timestamp": "??",
116+
"error.class": "GuzzleHttp\\Exception\\BadResponseException",
117+
"error.message": "Uncaught exception 'GuzzleHttp\\Exception\\BadResponseException' with message 'ClientException' in __FILE__:??",
118+
"transactionName": "OtherTransaction\/php__FILE__",
119+
"duration": "??",
120+
"externalDuration": "??",
121+
"externalCallCount": 1,
122+
"nr.transactionGuid": "??",
123+
"guid": "??",
124+
"sampled": true,
125+
"priority": "??",
126+
"traceId": "??",
127+
"spanId": "??"
128+
},
129+
{},
130+
{}
131+
]
132+
]
133+
]
134+
*/
135+
136+
/*EXPECT_REGEX
137+
^\s*Fatal error: Uncaught GuzzleHttp\\Exception\\BadResponseException: ClientException.*
138+
*/
139+
140+
require_once(realpath(dirname(__FILE__)) . '/../../../include/config.php');
141+
require_once(realpath(dirname(__FILE__)) . '/../../../include/unpack_guzzle.php');
142+
require_guzzle(7);
143+
144+
$TEST_EXTERNAL_HOST=getenv('TEST_EXTERNAL_HOST');
145+
146+
$request = new \GuzzleHttp\Psr7\Request('GET', "http://$TEST_EXTERNAL_HOST/resource");
147+
$response = new \GuzzleHttp\Psr7\Response(404, [], "Not found!");
148+
149+
$stack = GuzzleHttp\HandlerStack::create(
150+
new GuzzleHttp\Handler\MockHandler([
151+
new \GuzzleHttp\Exception\BadResponseException(
152+
"ClientException",
153+
$request,
154+
$response
155+
)
156+
]));
157+
158+
$client = new GuzzleHttp\Client([
159+
'handler' => $stack,
160+
161+
]);
162+
163+
$response = $client->send($request);
164+
165+
echo "you should not see this" . PHP_EOL;
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
<?php
2+
/*
3+
* Copyright 2020 New Relic Corporation. All rights reserved.
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/*DESCRIPTION
8+
Test that the span for a async external request that ends up throwing an uncaught exception
9+
(other than BadResponseException) is marked as http and uri is captured. Additionally,
10+
test that exception is recorded as traced error, error event, and the root span has error
11+
attributes.
12+
*/
13+
14+
/*SKIPIF
15+
<?php
16+
require("skipif.inc");
17+
*/
18+
19+
/*INI
20+
newrelic.distributed_tracing_enabled = true
21+
newrelic.transaction_tracer.threshold = 0
22+
newrelic.transaction_tracer.detail = 1
23+
newrelic.code_level_metrics.enabled = 0
24+
log_errors=0
25+
display_errors=1
26+
*/
27+
28+
/*ENVIRONMENT
29+
TEST_EXTERNAL_HOST=example.com
30+
*/
31+
32+
/*EXPECT_METRICS_EXIST
33+
External/ENV[TEST_EXTERNAL_HOST]/all
34+
*/
35+
36+
/*EXPECT_SPAN_EVENTS_LIKE
37+
[
38+
[
39+
{
40+
"category": "generic",
41+
"type": "Span",
42+
"guid": "??",
43+
"traceId": "??",
44+
"transactionId": "??",
45+
"name": "OtherTransaction/php__FILE__",
46+
"timestamp": "??",
47+
"duration": "??",
48+
"priority": "??",
49+
"sampled": true,
50+
"nr.entryPoint": true,
51+
"transaction.name": "OtherTransaction/php__FILE__"
52+
},
53+
{},
54+
{
55+
"error.message": "Uncaught exception 'GuzzleHttp\\Exception\\TransferException' with message 'I'm covered in bees!!!' in __FILE__:??",
56+
"error.class": "GuzzleHttp\\Exception\\TransferException"
57+
}
58+
],
59+
[
60+
{
61+
"traceId": "??",
62+
"duration": "??",
63+
"transactionId": "??",
64+
"name": "External/ENV[TEST_EXTERNAL_HOST]/all",
65+
"guid": "??",
66+
"type": "Span",
67+
"category": "http",
68+
"priority": "??",
69+
"sampled": true,
70+
"timestamp": "??",
71+
"parentId": "??",
72+
"span.kind": "client",
73+
"component": "Guzzle 6"
74+
},
75+
{},
76+
{
77+
"http.url": "http://ENV[TEST_EXTERNAL_HOST]/resource",
78+
"http.method": "GET",
79+
"http.statusCode": 0
80+
}
81+
]
82+
]
83+
*/
84+
85+
/*EXPECT_TRACED_ERRORS
86+
[
87+
"?? agent run id",
88+
[
89+
[
90+
"?? when",
91+
"OtherTransaction/php__FILE__",
92+
"Uncaught exception 'GuzzleHttp\\Exception\\TransferException' with message 'I'm covered in bees!!!' in __FILE__:??",
93+
"GuzzleHttp\\Exception\\TransferException",
94+
{
95+
"stack_trace": [],
96+
"agentAttributes": "??",
97+
"intrinsics": "??"
98+
},
99+
"?? transaction ID"
100+
]
101+
]
102+
]
103+
*/
104+
105+
/*EXPECT_ERROR_EVENTS
106+
[
107+
"?? agent run id",
108+
{
109+
"reservoir_size": "??",
110+
"events_seen": 1
111+
},
112+
[
113+
[
114+
{
115+
"type": "TransactionError",
116+
"timestamp": "??",
117+
"error.class": "GuzzleHttp\\Exception\\TransferException",
118+
"error.message": "Uncaught exception 'GuzzleHttp\\Exception\\TransferException' with message 'I'm covered in bees!!!' in __FILE__:??",
119+
"transactionName": "OtherTransaction\/php__FILE__",
120+
"duration": "??",
121+
"externalDuration": "??",
122+
"externalCallCount": 1,
123+
"nr.transactionGuid": "??",
124+
"guid": "??",
125+
"sampled": true,
126+
"priority": "??",
127+
"traceId": "??",
128+
"spanId": "??"
129+
},
130+
{},
131+
{}
132+
]
133+
]
134+
]
135+
*/
136+
137+
/*EXPECT_REGEX
138+
^\s*Fatal error: Uncaught GuzzleHttp\\Exception\\TransferException: I'm covered in bees!!!
139+
*/
140+
141+
require_once(realpath(dirname(__FILE__)) . '/../../../include/config.php');
142+
require_once(realpath(dirname(__FILE__)) . '/../../../include/unpack_guzzle.php');
143+
require_guzzle(7);
144+
145+
$TEST_EXTERNAL_HOST=getenv('TEST_EXTERNAL_HOST');
146+
147+
$request = new \GuzzleHttp\Psr7\Request('GET', "http://$TEST_EXTERNAL_HOST/resource");
148+
149+
$stack = GuzzleHttp\HandlerStack::create(
150+
new GuzzleHttp\Handler\MockHandler([
151+
new \GuzzleHttp\Exception\TransferException("I'm covered in bees!!!")
152+
]));
153+
154+
$client = new GuzzleHttp\Client([
155+
'handler' => $stack,
156+
]);
157+
158+
$promise = $client->sendAsync($request);
159+
$promise->wait();
160+
161+
echo "you should not see this" . PHP_EOL;

0 commit comments

Comments
 (0)