Skip to content

Commit be91e4f

Browse files
authored
Symfony auto instrumentation improvements (#120)
* Add tests to Symfony instrumentation * Add tests to Symfony instrumentation Make class final Calculate content length if header don't exist * cs - single quote * cs - psalm * more readable code * add tests for StreamedResponse & BinaryFileResponse
1 parent be97d9d commit be91e4f

File tree

3 files changed

+81
-8
lines changed

3 files changed

+81
-8
lines changed

src/HeadersPropagator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
/**
1212
* @internal
1313
*/
14-
class HeadersPropagator implements PropagationGetterInterface
14+
final class HeadersPropagator implements PropagationGetterInterface
1515
{
1616
public static function instance(): self
1717
{

src/SymfonyInstrumentation.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
use Symfony\Component\HttpKernel\HttpKernel;
1919
use Throwable;
2020

21-
class SymfonyInstrumentation
21+
final class SymfonyInstrumentation
2222
{
2323
public static function register(): void
2424
{
@@ -76,12 +76,18 @@ public static function register(): void
7676
$span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage());
7777
}
7878
if ($response) {
79-
if ($response->getStatusCode() >= 400) {
79+
if ($response->getStatusCode() >= Response::HTTP_BAD_REQUEST) {
8080
$span->setStatus(StatusCode::STATUS_ERROR);
8181
}
8282
$span->setAttribute(TraceAttributes::HTTP_STATUS_CODE, $response->getStatusCode());
8383
$span->setAttribute(TraceAttributes::HTTP_FLAVOR, $response->getProtocolVersion());
84-
$span->setAttribute(TraceAttributes::HTTP_RESPONSE_CONTENT_LENGTH, $response->headers->get('Content-Length'));
84+
$contentLength = $response->headers->get('Content-Length');
85+
/** @psalm-suppress PossiblyFalseArgument */
86+
if (null === $contentLength && is_string($response->getContent())) {
87+
$contentLength = \strlen($response->getContent());
88+
}
89+
90+
$span->setAttribute(TraceAttributes::HTTP_RESPONSE_CONTENT_LENGTH, $contentLength);
8591
}
8692

8793
$span->end();

tests/Integration/SymfonyInstrumentationTest.php

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,15 @@
1010
use OpenTelemetry\SDK\Trace\SpanExporter\InMemoryExporter;
1111
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
1212
use OpenTelemetry\SDK\Trace\TracerProvider;
13+
use OpenTelemetry\SemConv\TraceAttributes;
1314
use PHPUnit\Framework\TestCase;
1415
use Symfony\Component\EventDispatcher\EventDispatcher;
1516
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
17+
use Symfony\Component\HttpFoundation\BinaryFileResponse;
1618
use Symfony\Component\HttpFoundation\Request;
1719
use Symfony\Component\HttpFoundation\RequestStack;
1820
use Symfony\Component\HttpFoundation\Response;
21+
use Symfony\Component\HttpFoundation\StreamedResponse;
1922
use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface;
2023
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
2124
use Symfony\Component\HttpKernel\HttpKernel;
@@ -46,30 +49,94 @@ public function tearDown(): void
4649
$this->scope->detach();
4750
}
4851

49-
public function test_http_kernel_handle(): void
52+
public function test_http_kernel_handle_exception(): void
5053
{
5154
$this->expectException(\RuntimeException::class);
5255
$kernel = $this->getHttpKernel(new EventDispatcher(), function () {
5356
throw new \RuntimeException();
5457
});
5558
$this->assertCount(0, $this->storage);
59+
60+
$kernel->handle(new Request());
61+
}
62+
63+
public function test_http_kernel_handle_attributes(): void
64+
{
65+
$kernel = $this->getHttpKernel(new EventDispatcher());
66+
$this->assertCount(0, $this->storage);
67+
$request = new Request();
68+
$request->attributes->set('_route', 'test_route');
69+
70+
$kernel->handle($request);
71+
72+
$attributes = $this->storage[0]->getAttributes();
73+
$this->assertCount(1, $this->storage);
74+
$this->assertEquals('HTTP GET', $this->storage[0]->getName());
75+
$this->assertEquals('http://:/', $attributes->get(TraceAttributes::HTTP_URL));
76+
$this->assertEquals('GET', $attributes->get(TraceAttributes::HTTP_METHOD));
77+
$this->assertEquals('http', $attributes->get(TraceAttributes::HTTP_SCHEME));
78+
$this->assertEquals('test_route', $attributes->get(TraceAttributes::HTTP_ROUTE));
79+
$this->assertEquals(200, $attributes->get(TraceAttributes::HTTP_STATUS_CODE));
80+
$this->assertEquals('1.0', $attributes->get(TraceAttributes::HTTP_FLAVOR));
81+
$this->assertEquals(5, $attributes->get(TraceAttributes::HTTP_RESPONSE_CONTENT_LENGTH));
82+
}
83+
84+
public function test_http_kernel_handle_stream_response(): void
85+
{
86+
$kernel = $this->getHttpKernel(new EventDispatcher(), fn () => new StreamedResponse(function () {
87+
echo 'Hello';
88+
flush();
89+
}));
90+
$this->assertCount(0, $this->storage);
91+
92+
$kernel->handle(new Request());
93+
$this->assertCount(1, $this->storage);
94+
$this->assertNull($this->storage[0]->getAttributes()->get(TraceAttributes::HTTP_RESPONSE_CONTENT_LENGTH));
95+
}
96+
97+
public function test_http_kernel_handle_binary_file_response(): void
98+
{
99+
$kernel = $this->getHttpKernel(new EventDispatcher(), fn () => new BinaryFileResponse(__FILE__));
100+
$this->assertCount(0, $this->storage);
101+
102+
$kernel->handle(new Request());
103+
$this->assertCount(1, $this->storage);
104+
$this->assertNull($this->storage[0]->getAttributes()->get(TraceAttributes::HTTP_RESPONSE_CONTENT_LENGTH));
105+
}
106+
107+
public function test_http_kernel_handle_with_empty_route(): void
108+
{
109+
$kernel = $this->getHttpKernel(new EventDispatcher());
110+
$this->assertCount(0, $this->storage);
111+
$request = new Request();
112+
$request->attributes->set('_route', '');
113+
114+
$kernel->handle($request, HttpKernelInterface::MAIN_REQUEST, true);
115+
$this->assertCount(1, $this->storage);
116+
$this->assertFalse($this->storage[0]->getAttributes()->has(TraceAttributes::HTTP_ROUTE));
117+
}
118+
119+
public function test_http_kernel_handle_without_route(): void
120+
{
121+
$kernel = $this->getHttpKernel(new EventDispatcher());
122+
$this->assertCount(0, $this->storage);
123+
56124
$kernel->handle(new Request(), HttpKernelInterface::MAIN_REQUEST, true);
57125
$this->assertCount(1, $this->storage);
126+
$this->assertFalse($this->storage[0]->getAttributes()->has(TraceAttributes::HTTP_ROUTE));
58127
}
59128

60-
private function getHttpKernel(EventDispatcherInterface $eventDispatcher, $controller = null, RequestStack $requestStack = null, array $arguments = [])
129+
private function getHttpKernel(EventDispatcherInterface $eventDispatcher, $controller = null, RequestStack $requestStack = null, array $arguments = []): HttpKernel
61130
{
62131
$controller ??= fn () => new Response('Hello');
63132

64133
$controllerResolver = $this->createMock(ControllerResolverInterface::class);
65134
$controllerResolver
66-
->expects($this->any())
67135
->method('getController')
68136
->willReturn($controller);
69137

70138
$argumentResolver = $this->createMock(ArgumentResolverInterface::class);
71139
$argumentResolver
72-
->expects($this->any())
73140
->method('getArguments')
74141
->willReturn($arguments);
75142

0 commit comments

Comments
 (0)