From c33552ab5fc83d03833ce869132f1331beb1e73e Mon Sep 17 00:00:00 2001 From: Application-drop-up Date: Thu, 11 Jun 2026 23:38:01 +0900 Subject: [PATCH 1/3] fix: calculated timestamps correctly in not using `REQUEST_TIME_FLOAT` --- src/SDK/Trace/AutoRootSpan.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SDK/Trace/AutoRootSpan.php b/src/SDK/Trace/AutoRootSpan.php index 69790cd61..7e2b87c55 100644 --- a/src/SDK/Trace/AutoRootSpan.php +++ b/src/SDK/Trace/AutoRootSpan.php @@ -43,12 +43,12 @@ public static function create(ServerRequestInterface $request): void Version::VERSION_1_25_0->url(), ); $parent = Globals::propagator()->extract($request->getHeaders()); - $startTime = array_key_exists('REQUEST_TIME_FLOAT', $request->getServerParams()) - ? $request->getServerParams()['REQUEST_TIME_FLOAT'] - : (int) microtime(true); + $startTimeInNanos = array_key_exists('REQUEST_TIME_FLOAT', $request->getServerParams()) + ? (int) ($request->getServerParams()['REQUEST_TIME_FLOAT'] * ClockInterface::NANOS_PER_SECOND) + : (int) (microtime(true) * ClockInterface::NANOS_PER_SECOND); $span = $tracer->spanBuilder($request->getMethod()) ->setSpanKind(SpanKind::KIND_SERVER) - ->setStartTimestamp((int) ($startTime*ClockInterface::NANOS_PER_SECOND)) + ->setStartTimestamp($startTimeInNanos) ->setParent($parent) ->setAttribute(TraceAttributes::URL_FULL, (string) $request->getUri()) ->setAttribute(TraceAttributes::HTTP_REQUEST_METHOD, $request->getMethod()) From 48ceca8a34bd662f998cea6e2d6644519ffd4d8e Mon Sep 17 00:00:00 2001 From: Application-drop-up Date: Thu, 11 Jun 2026 23:38:27 +0900 Subject: [PATCH 2/3] chore: add new test patterns --- tests/Unit/SDK/Trace/AutoRootSpanTest.php | 68 +++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/tests/Unit/SDK/Trace/AutoRootSpanTest.php b/tests/Unit/SDK/Trace/AutoRootSpanTest.php index a53859f52..1ee7b7b4d 100644 --- a/tests/Unit/SDK/Trace/AutoRootSpanTest.php +++ b/tests/Unit/SDK/Trace/AutoRootSpanTest.php @@ -5,6 +5,7 @@ namespace OpenTelemetry\Tests\SDK\Trace; use Nyholm\Psr7\ServerRequest; +use OpenTelemetry\API\Common\Time\ClockInterface; use OpenTelemetry\API\Instrumentation\Configurator; use OpenTelemetry\API\Trace\Propagation\TraceContextPropagator; use OpenTelemetry\API\Trace\Span; @@ -133,6 +134,73 @@ public function test_create(): void $scope->detach(); } + public function test_create_converts_request_time_float_to_nanoseconds(): void + { + $requestTimeFloat = 1700000000.5; + $expectedNanos = (int) ($requestTimeFloat * ClockInterface::NANOS_PER_SECOND); + + $request = new ServerRequest( + 'GET', + 'https://example.com/', + [], + null, + '1.1', + ['REQUEST_TIME_FLOAT' => $requestTimeFloat], + ); + + $span = $this->createMock(SpanInterface::class); + $spanBuilder = $this->createMock(SpanBuilderInterface::class); + $spanBuilder->method('setSpanKind')->willReturnSelf(); + $spanBuilder->method('setParent')->willReturnSelf(); + $spanBuilder->method('setAttribute')->willReturnSelf(); + $spanBuilder->method('startSpan')->willReturn($span); + $spanBuilder + ->expects($this->once()) + ->method('setStartTimestamp') + ->with($this->identicalTo($expectedNanos)) + ->willReturnSelf(); + + $this->tracer->method('spanBuilder')->willReturn($spanBuilder); + + AutoRootSpan::create($request); + + Context::storage()->scope()?->detach(); + } + + public function test_create_start_timestamp_preserves_sub_second_precision_without_request_time_float(): void + { + $request = new ServerRequest('GET', 'https://example.com/'); + + $capturedTimestamp = null; + $span = $this->createMock(SpanInterface::class); + $spanBuilder = $this->createMock(SpanBuilderInterface::class); + $spanBuilder->method('setSpanKind')->willReturnSelf(); + $spanBuilder->method('setParent')->willReturnSelf(); + $spanBuilder->method('setAttribute')->willReturnSelf(); + $spanBuilder->method('startSpan')->willReturn($span); + $spanBuilder + ->expects($this->once()) + ->method('setStartTimestamp') + ->with($this->callback(function (int $timestamp) use (&$capturedTimestamp): bool { + $capturedTimestamp = $timestamp; + + return true; + })) + ->willReturnSelf(); + + $this->tracer->method('spanBuilder')->willReturn($spanBuilder); + + $before = (int) (microtime(true) * ClockInterface::NANOS_PER_SECOND); + AutoRootSpan::create($request); + $after = (int) (microtime(true) * ClockInterface::NANOS_PER_SECOND); + + $this->assertNotNull($capturedTimestamp); + $this->assertGreaterThanOrEqual($before, $capturedTimestamp); + $this->assertLessThanOrEqual($after, $capturedTimestamp); + + Context::storage()->scope()?->detach(); + } + public function test_shutdown_handler(): void { $this->setEnvironmentVariable('OTEL_PHP_DEBUG_SCOPES_DISABLED', 'true'); From e91263105d6b2e88c70b3e4c399c83341b4ecca4 Mon Sep 17 00:00:00 2001 From: Application-drop-up Date: Fri, 12 Jun 2026 08:39:34 +0900 Subject: [PATCH 3/3] fix: failed psalm --- src/SDK/Trace/AutoRootSpan.php | 4 ++-- tests/Unit/SDK/Trace/AutoRootSpanTest.php | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/SDK/Trace/AutoRootSpan.php b/src/SDK/Trace/AutoRootSpan.php index 7e2b87c55..f675f85bf 100644 --- a/src/SDK/Trace/AutoRootSpan.php +++ b/src/SDK/Trace/AutoRootSpan.php @@ -44,8 +44,8 @@ public static function create(ServerRequestInterface $request): void ); $parent = Globals::propagator()->extract($request->getHeaders()); $startTimeInNanos = array_key_exists('REQUEST_TIME_FLOAT', $request->getServerParams()) - ? (int) ($request->getServerParams()['REQUEST_TIME_FLOAT'] * ClockInterface::NANOS_PER_SECOND) - : (int) (microtime(true) * ClockInterface::NANOS_PER_SECOND); + ? (int) ((float) $request->getServerParams()['REQUEST_TIME_FLOAT'] * (float) ClockInterface::NANOS_PER_SECOND) + : (int) (microtime(true) * (float) ClockInterface::NANOS_PER_SECOND); $span = $tracer->spanBuilder($request->getMethod()) ->setSpanKind(SpanKind::KIND_SERVER) ->setStartTimestamp($startTimeInNanos) diff --git a/tests/Unit/SDK/Trace/AutoRootSpanTest.php b/tests/Unit/SDK/Trace/AutoRootSpanTest.php index 1ee7b7b4d..0cfe528ea 100644 --- a/tests/Unit/SDK/Trace/AutoRootSpanTest.php +++ b/tests/Unit/SDK/Trace/AutoRootSpanTest.php @@ -137,7 +137,7 @@ public function test_create(): void public function test_create_converts_request_time_float_to_nanoseconds(): void { $requestTimeFloat = 1700000000.5; - $expectedNanos = (int) ($requestTimeFloat * ClockInterface::NANOS_PER_SECOND); + $expectedNanos = (int) ($requestTimeFloat * (float) ClockInterface::NANOS_PER_SECOND); $request = new ServerRequest( 'GET', @@ -190,9 +190,9 @@ public function test_create_start_timestamp_preserves_sub_second_precision_witho $this->tracer->method('spanBuilder')->willReturn($spanBuilder); - $before = (int) (microtime(true) * ClockInterface::NANOS_PER_SECOND); + $before = (int) (microtime(true) * (float) ClockInterface::NANOS_PER_SECOND); AutoRootSpan::create($request); - $after = (int) (microtime(true) * ClockInterface::NANOS_PER_SECOND); + $after = (int) (microtime(true) * (float) ClockInterface::NANOS_PER_SECOND); $this->assertNotNull($capturedTimestamp); $this->assertGreaterThanOrEqual($before, $capturedTimestamp);