From 0afa9b3a4f9712323009f8229e0c7a7c58f62823 Mon Sep 17 00:00:00 2001 From: Vladimir Plakhotnikov Date: Sun, 22 Dec 2024 15:44:05 +0300 Subject: [PATCH] fix(Instrumentation/TraceableRouteLoader): undefined method named "getDeclaringClass" of class "ReflectionClass" (#91) --- .../Routing/TraceableRouteLoader.php | 6 ++- .../ClassInvokeTraceableController.php | 20 +++++++++ .../Controller/ClassTraceableController.php | 2 +- .../NotTraceableClassController.php | 16 +++++++ .../Instrumentation/HttpKernelTracingTest.php | 45 ++++++++++++++++++- .../NotTraceableClassInvokeController.php | 13 ++++++ .../Routing/TraceableActionController.php | 2 +- .../Routing/TraceableClassController.php | 4 +- .../TraceableClassInvokeController.php | 15 +++++++ .../Routing/TraceableRouteLoaderTest.php | 28 ++++++++++-- 10 files changed, 141 insertions(+), 10 deletions(-) create mode 100644 tests/Functional/Application/src/Controller/ClassInvokeTraceableController.php create mode 100644 tests/Functional/Application/src/Controller/NotTraceableClassController.php create mode 100644 tests/Unit/Instrumentation/Symfony/Routing/NotTraceableClassInvokeController.php create mode 100644 tests/Unit/Instrumentation/Symfony/Routing/TraceableClassInvokeController.php diff --git a/src/Instrumentation/Symfony/Framework/Routing/TraceableRouteLoader.php b/src/Instrumentation/Symfony/Framework/Routing/TraceableRouteLoader.php index 0ef5c65..f5ba296 100644 --- a/src/Instrumentation/Symfony/Framework/Routing/TraceableRouteLoader.php +++ b/src/Instrumentation/Symfony/Framework/Routing/TraceableRouteLoader.php @@ -66,7 +66,11 @@ private static function parseAttribute(Route $route): void return; } - $attribute = $reflection->getAttributes(Traceable::class)[0] ?? $reflection->getDeclaringClass()->getAttributes(Traceable::class)[0] ?? null; + if ($reflection instanceof \ReflectionMethod) { + $attribute = $reflection->getAttributes(Traceable::class)[0] ?? $reflection->getDeclaringClass()->getAttributes(Traceable::class)[0] ?? null; + } else { + $attribute = $reflection->getAttributes(Traceable::class)[0] ?? null; + } if (null !== $attribute) { $traceable = $attribute->newInstance(); diff --git a/tests/Functional/Application/src/Controller/ClassInvokeTraceableController.php b/tests/Functional/Application/src/Controller/ClassInvokeTraceableController.php new file mode 100644 index 0000000..83ef72c --- /dev/null +++ b/tests/Functional/Application/src/Controller/ClassInvokeTraceableController.php @@ -0,0 +1,20 @@ +json([ + 'status' => 'ok', + ]); + } +} diff --git a/tests/Functional/Application/src/Controller/ClassTraceableController.php b/tests/Functional/Application/src/Controller/ClassTraceableController.php index 3a36d92..eb564ef 100644 --- a/tests/Functional/Application/src/Controller/ClassTraceableController.php +++ b/tests/Functional/Application/src/Controller/ClassTraceableController.php @@ -11,7 +11,7 @@ class ClassTraceableController extends AbstractController { #[Route('/class-traceable', methods: ['GET'])] - public function __invoke(): Response + public function index(): Response { return $this->json([ 'status' => 'ok', diff --git a/tests/Functional/Application/src/Controller/NotTraceableClassController.php b/tests/Functional/Application/src/Controller/NotTraceableClassController.php new file mode 100644 index 0000000..77ed9f5 --- /dev/null +++ b/tests/Functional/Application/src/Controller/NotTraceableClassController.php @@ -0,0 +1,16 @@ +request('GET', '/class-invoke-traceable'); + + static::assertResponseIsSuccessful(); + static::assertSame('{"status":"ok"}', $client->getResponse()->getContent()); + + self::assertSpansCount(1); + + $mainSpan = self::getSpans()[0]; + self::assertSpanName($mainSpan, 'friendsofopentelemetry_opentelemetry_tests_functional_application_classinvoketraceable__invoke'); + self::assertSpanStatus($mainSpan, StatusData::ok()); + self::assertSpanAttributes($mainSpan, [ + 'url.full' => 'http://localhost/class-invoke-traceable', + 'http.request.method' => 'GET', + 'url.path' => '/class-invoke-traceable', + 'symfony.kernel.http.host' => 'localhost', + 'url.scheme' => 'http', + 'network.protocol.version' => '1.1', + 'user_agent.original' => 'Symfony BrowserKit', + 'network.peer.address' => '127.0.0.1', + 'symfony.kernel.net.peer_ip' => '127.0.0.1', + 'server.address' => 'localhost', + 'server.port' => 80, + 'http.route' => 'friendsofopentelemetry_opentelemetry_tests_functional_application_classinvoketraceable__invoke', + 'http.response.status_code' => Response::HTTP_OK, + ]); + self::assertSpanEventsCount($mainSpan, 0); + } + public function testTraceableClass(): void { $client = static::createClient(); @@ -126,7 +157,7 @@ public function testTraceableClass(): void self::assertSpansCount(1); $mainSpan = self::getSpans()[0]; - self::assertSpanName($mainSpan, 'friendsofopentelemetry_opentelemetry_tests_functional_application_classtraceable__invoke'); + self::assertSpanName($mainSpan, 'friendsofopentelemetry_opentelemetry_tests_functional_application_classtraceable_index'); self::assertSpanStatus($mainSpan, StatusData::ok()); self::assertSpanAttributes($mainSpan, [ 'url.full' => 'http://localhost/class-traceable', @@ -140,7 +171,7 @@ public function testTraceableClass(): void 'symfony.kernel.net.peer_ip' => '127.0.0.1', 'server.address' => 'localhost', 'server.port' => 80, - 'http.route' => 'friendsofopentelemetry_opentelemetry_tests_functional_application_classtraceable__invoke', + 'http.route' => 'friendsofopentelemetry_opentelemetry_tests_functional_application_classtraceable_index', 'http.response.status_code' => Response::HTTP_OK, ]); self::assertSpanEventsCount($mainSpan, 0); @@ -156,6 +187,16 @@ public function testNotTraceable(): void self::assertSpansCount(0); } + public function testNotTraceableClass(): void + { + $client = static::createClient(); + $client->request('GET', '/not-traceable-class'); + + self::assertSame(Response::HTTP_FOUND, $client->getResponse()->getStatusCode()); + + self::assertSpansCount(0); + } + public function testTraceableFallback(): void { $client = static::createClient(); diff --git a/tests/Unit/Instrumentation/Symfony/Routing/NotTraceableClassInvokeController.php b/tests/Unit/Instrumentation/Symfony/Routing/NotTraceableClassInvokeController.php new file mode 100644 index 0000000..c7ff6f1 --- /dev/null +++ b/tests/Unit/Instrumentation/Symfony/Routing/NotTraceableClassInvokeController.php @@ -0,0 +1,13 @@ +loader->load(TraceableActionController::class); self::assertCount(1, $routes); - self::assertEquals('/path', $routes->get('action')->getPath()); + self::assertEquals('/traceable-action', $routes->get('action')->getPath()); self::assertEquals([ '_traceable' => true, '_controller' => 'FriendsOfOpenTelemetry\OpenTelemetryBundle\Tests\Unit\Instrumentation\Symfony\Routing\TraceableActionController::action', @@ -35,11 +35,33 @@ public function testTraceableClass(): void { $routes = $this->loader->load(TraceableClassController::class); self::assertCount(1, $routes); - self::assertEquals('/path', $routes->get('action')->getPath()); + self::assertEquals('/traceable-class', $routes->get('action')->getPath()); self::assertEquals([ '_traceable' => true, - '_controller' => 'FriendsOfOpenTelemetry\OpenTelemetryBundle\Tests\Unit\Instrumentation\Symfony\Routing\TraceableClassController', + '_controller' => 'FriendsOfOpenTelemetry\OpenTelemetryBundle\Tests\Unit\Instrumentation\Symfony\Routing\TraceableClassController::index', '_tracer' => 'test', ], $routes->get('action')->getDefaults()); } + + public function testTraceableClassInvoke(): void + { + $routes = $this->loader->load(TraceableClassInvokeController::class); + self::assertCount(1, $routes); + self::assertEquals('/traceable-class-invoke', $routes->get('action')->getPath()); + self::assertEquals([ + '_traceable' => true, + '_controller' => 'FriendsOfOpenTelemetry\OpenTelemetryBundle\Tests\Unit\Instrumentation\Symfony\Routing\TraceableClassInvokeController', + '_tracer' => 'test', + ], $routes->get('action')->getDefaults()); + } + + public function testNotTraceableTraceableClassInvoke(): void + { + $routes = $this->loader->load(NotTraceableClassInvokeController::class); + self::assertCount(1, $routes); + self::assertEquals('/not-traceable-class-invoke', $routes->get('action')->getPath()); + self::assertEquals([ + '_controller' => 'FriendsOfOpenTelemetry\OpenTelemetryBundle\Tests\Unit\Instrumentation\Symfony\Routing\NotTraceableClassInvokeController', + ], $routes->get('action')->getDefaults()); + } }