Skip to content

Commit b7a9577

Browse files
committed
handle guzzle response exceptions
if a guzzle client is configured with exceptions=true, try to retrieve the http status code, body size, and network protocol version and set as span attributes
1 parent 2d38c8f commit b7a9577

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

src/Instrumentation/Guzzle/src/GuzzleInstrumentation.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use function get_cfg_var;
88
use GuzzleHttp\Client;
9+
use GuzzleHttp\Exception\BadResponseException;
910
use GuzzleHttp\Promise\PromiseInterface;
1011
use OpenTelemetry\API\Globals;
1112
use OpenTelemetry\API\Instrumentation\CachedInstrumentation;
@@ -120,6 +121,12 @@ public static function register(): void
120121
return $response;
121122
},
122123
onRejected: function (\Throwable $t) use ($span) {
124+
if ($t instanceof BadResponseException && $t->hasResponse()) {
125+
$response = $t->getResponse();
126+
$span->setAttribute(TraceAttributes::HTTP_RESPONSE_STATUS_CODE, $response->getStatusCode());
127+
$span->setAttribute(TraceAttributes::NETWORK_PROTOCOL_VERSION, $response->getProtocolVersion());
128+
$span->setAttribute(TraceAttributes::HTTP_RESPONSE_BODY_SIZE, $response->getBody()->getSize());
129+
}
123130
$span->recordException($t);
124131
$span->setStatus(StatusCode::STATUS_ERROR, $t->getMessage());
125132
$span->end();

src/Instrumentation/Guzzle/tests/Integration/GuzzleInstrumentationTest.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use ArrayObject;
88
use GuzzleHttp\Client;
9+
use GuzzleHttp\Exception\ConnectException;
910
use GuzzleHttp\Handler\MockHandler;
1011
use GuzzleHttp\HandlerStack;
1112
use GuzzleHttp\Promise\PromiseInterface;
@@ -165,4 +166,47 @@ public function test_headers_propagation(): void
165166
$this->client->get('/');
166167

167168
}
169+
170+
/**
171+
* @dataProvider exceptionProvider
172+
*/
173+
public function test_exceptions_enabled_sets_response_attributes($response, ?int $expected = null): void
174+
{
175+
$client = new Client([
176+
'handler' => $this->handlerStack,
177+
'base_uri' => 'https://example.com/',
178+
'http_errors' => true,
179+
'exceptions' => true,
180+
]);
181+
$this->mock->append($response);
182+
$this->assertCount(0, $this->storage);
183+
184+
try {
185+
$client->send(new Request('GET', 'https://example.com/error'));
186+
} catch (\Exception $e) {
187+
// Expected exception
188+
}
189+
$this->assertCount(1, $this->storage);
190+
$span = $this->storage->offsetGet(0);
191+
$attributes = $span->getAttributes()->toArray();
192+
if ($expected) {
193+
$this->assertSame($expected, $attributes[TraceAttributes::HTTP_RESPONSE_STATUS_CODE]);
194+
$this->assertGreaterThan(0, $attributes[TraceAttributes::HTTP_RESPONSE_BODY_SIZE]);
195+
$this->assertArrayHasKey(TraceAttributes::NETWORK_PROTOCOL_VERSION, $attributes);
196+
} else {
197+
$this->assertArrayNotHasKey(TraceAttributes::HTTP_RESPONSE_STATUS_CODE, $attributes);
198+
}
199+
}
200+
201+
public static function exceptionProvider(): array
202+
{
203+
return [
204+
'400 Bad Request' => [new Response(400, [], 'Bad Request'), 400],
205+
'404 Not Found' => [new Response(404, [], 'Not Found'), 404],
206+
'500 Internal Server Error' => [new Response(500, [], 'Internal Server Error'), 500],
207+
'503 Service Unavailable' => [new Response(503, [], 'Service Unavailable'), 503],
208+
'network connection error' => [new ConnectException('network error', new Request('GET', 'https://example.com/error'))],
209+
'runtime exception' => [new \RuntimeException('runtime error')],
210+
];
211+
}
168212
}

0 commit comments

Comments
 (0)