diff --git a/src/Facades/Tracer.php b/src/Facades/Tracer.php index db56fbb..22ca779 100644 --- a/src/Facades/Tracer.php +++ b/src/Facades/Tracer.php @@ -2,7 +2,6 @@ namespace Keepsuit\LaravelOpenTelemetry\Facades; -use Closure; use Illuminate\Support\Facades\Facade; use Keepsuit\LaravelOpenTelemetry\Support\SpanBuilder; use OpenTelemetry\API\Trace\SpanInterface; @@ -19,8 +18,6 @@ * @method static array propagationHeaders(?ContextInterface $context = null) * @method static Context|null extractContextFromPropagationHeaders(array $headers) * @method static SpanBuilder newSpan(string $name) - * @method static SpanInterface start(string $name) - * @method static mixed measure(string $name, Closure $callback) * @method static void updateLogContext() */ class Tracer extends Facade diff --git a/src/Instrumentation/QueryInstrumentation.php b/src/Instrumentation/QueryInstrumentation.php index 5997809..15fcd28 100644 --- a/src/Instrumentation/QueryInstrumentation.php +++ b/src/Instrumentation/QueryInstrumentation.php @@ -39,7 +39,7 @@ public function recordQuery(QueryExecuted $event): void ->setAttribute(TraceAttributes::DB_USER, $event->connection->getConfig('username')) ->setAttribute(TraceAttributes::SERVER_ADDRESS, $event->connection->getConfig('host')) ->setAttribute(TraceAttributes::SERVER_PORT, $event->connection->getConfig('port')) - ->startSpan(); + ->start(); $span->end(); } diff --git a/src/Instrumentation/QueueInstrumentation.php b/src/Instrumentation/QueueInstrumentation.php index 547157a..3615421 100644 --- a/src/Instrumentation/QueueInstrumentation.php +++ b/src/Instrumentation/QueueInstrumentation.php @@ -38,7 +38,7 @@ protected function recordJobStart(): void ->setAttribute('messaging.destination.kind', 'queue') ->setAttribute('messaging.destination.name', $event->job->getQueue()) ->setAttribute('messaging.destination.template', $event->job->resolveName()) - ->startSpan(); + ->start(); $span->activate(); diff --git a/src/Instrumentation/RedisInstrumentation.php b/src/Instrumentation/RedisInstrumentation.php index 90f6d8f..22cdef5 100644 --- a/src/Instrumentation/RedisInstrumentation.php +++ b/src/Instrumentation/RedisInstrumentation.php @@ -30,7 +30,7 @@ public function recordCommand(CommandExecuted $event): void $span = Tracer::newSpan($traceName) ->setSpanKind(SpanKind::KIND_CLIENT) ->setStartTimestamp($this->getEventStartTimestampNs($event->time)) - ->startSpan(); + ->start(); if ($span->isRecording()) { $span->setAttribute(TraceAttributes::DB_SYSTEM, 'redis') diff --git a/src/Support/CarbonClock.php b/src/Support/CarbonClock.php index d722d2e..293b8cf 100644 --- a/src/Support/CarbonClock.php +++ b/src/Support/CarbonClock.php @@ -4,6 +4,7 @@ use Carbon\Carbon; use Carbon\CarbonImmutable; +use Carbon\CarbonInterface; use OpenTelemetry\SDK\Common\Time\ClockInterface; use OpenTelemetry\SDK\Common\Time\SystemClock; @@ -19,14 +20,14 @@ public function __construct() public function now(): int { if (Carbon::hasTestNow()) { - return (int) CarbonImmutable::now()->getPreciseTimestamp(6) * 1000; + return static::carbonToNanos(CarbonImmutable::now()); } return $this->systemClock->now(); } - public function nanoTime(): int + public static function carbonToNanos(CarbonInterface $carbon): int { - return $this->now(); + return (int) $carbon->getPreciseTimestamp(6) * 1000; } } diff --git a/src/Support/HttpClient/GuzzleTraceMiddleware.php b/src/Support/HttpClient/GuzzleTraceMiddleware.php index 4ea7add..2e0773a 100644 --- a/src/Support/HttpClient/GuzzleTraceMiddleware.php +++ b/src/Support/HttpClient/GuzzleTraceMiddleware.php @@ -27,7 +27,7 @@ public static function make(): Closure ->setAttribute(TraceAttributes::URL_SCHEME, $request->getUri()->getScheme()) ->setAttribute(TraceAttributes::SERVER_ADDRESS, $request->getUri()->getHost()) ->setAttribute(TraceAttributes::SERVER_PORT, $request->getUri()->getPort()) - ->startSpan(); + ->start(); $context = $span->storeInContext(Tracer::currentContext()); diff --git a/src/Support/HttpServer/TraceRequestMiddleware.php b/src/Support/HttpServer/TraceRequestMiddleware.php index 1910ff2..2a1e746 100644 --- a/src/Support/HttpServer/TraceRequestMiddleware.php +++ b/src/Support/HttpServer/TraceRequestMiddleware.php @@ -68,7 +68,7 @@ protected function startTracing(Request $request): SpanInterface ->setAttribute(TraceAttributes::USER_AGENT_ORIGINAL, $request->userAgent()) ->setAttribute(TraceAttributes::NETWORK_PROTOCOL_VERSION, $request->getProtocolVersion()) ->setAttribute(TraceAttributes::NETWORK_PEER_ADDRESS, $request->ip()) - ->startSpan(); + ->start(); } protected function recordHttpResponseToSpan(SpanInterface $span, Response $response): void diff --git a/src/Support/SpanBuilder.php b/src/Support/SpanBuilder.php index 7efb02f..11857d6 100644 --- a/src/Support/SpanBuilder.php +++ b/src/Support/SpanBuilder.php @@ -2,21 +2,24 @@ namespace Keepsuit\LaravelOpenTelemetry\Support; +use Carbon\CarbonInterface; use Closure; use Illuminate\Foundation\Bus\PendingDispatch; use OpenTelemetry\API\Trace\SpanBuilderInterface; use OpenTelemetry\API\Trace\SpanContextInterface; use OpenTelemetry\API\Trace\SpanInterface; +use OpenTelemetry\API\Trace\SpanKind; +use OpenTelemetry\Context\ContextInterface; use Throwable; -class SpanBuilder implements SpanBuilderInterface +class SpanBuilder { public function __construct( protected SpanBuilderInterface $spanBuilder ) { } - public function setParent($context): SpanBuilder + public function setParent(?ContextInterface $context): SpanBuilder { $this->spanBuilder->setParent($context); @@ -30,16 +33,16 @@ public function addLink(SpanContextInterface $context, iterable $attributes = [] return $this; } - /** - * @param mixed $value - */ - public function setAttribute(string $key, $value): SpanBuilder + public function setAttribute(string $key, mixed $value): SpanBuilder { $this->spanBuilder->setAttribute($key, $value); return $this; } + /** + * @param iterable $attributes + */ public function setAttributes(iterable $attributes): SpanBuilder { $this->spanBuilder->setAttributes($attributes); @@ -47,13 +50,23 @@ public function setAttributes(iterable $attributes): SpanBuilder return $this; } - public function setStartTimestamp(int $timestampNanos): SpanBuilder + /** + * @param CarbonInterface|int $timestamp A carbon instance or a timestamp in nanoseconds + */ + public function setStartTimestamp(CarbonInterface|int $timestamp): SpanBuilder { - $this->spanBuilder->setStartTimestamp($timestampNanos); + if ($timestamp instanceof CarbonInterface) { + $timestamp = CarbonClock::carbonToNanos($timestamp); + } + + $this->spanBuilder->setStartTimestamp($timestamp); return $this; } + /** + * @phpstan-param SpanKind::KIND_* $spanKind + */ public function setSpanKind(int $spanKind): SpanBuilder { $this->spanBuilder->setSpanKind($spanKind); @@ -61,7 +74,7 @@ public function setSpanKind(int $spanKind): SpanBuilder return $this; } - public function startSpan(): SpanInterface + public function start(): SpanInterface { return $this->spanBuilder->startSpan(); } @@ -76,7 +89,7 @@ public function startSpan(): SpanInterface */ public function measure(Closure $callback): mixed { - $span = $this->startSpan(); + $span = $this->start(); $scope = $span->activate(); try { diff --git a/src/Tracer.php b/src/Tracer.php index 0494eca..bb54a07 100644 --- a/src/Tracer.php +++ b/src/Tracer.php @@ -2,8 +2,6 @@ namespace Keepsuit\LaravelOpenTelemetry; -use Closure; -use Illuminate\Foundation\Bus\PendingDispatch; use Illuminate\Support\Facades\Log; use Keepsuit\LaravelOpenTelemetry\Support\SpanBuilder; use OpenTelemetry\API\Trace\SpanInterface; @@ -22,36 +20,6 @@ public function __construct( ) { } - /** - * @phpstan-param non-empty-string $name - */ - public function newSpan(string $name): SpanBuilder - { - return new SpanBuilder($this->tracer->spanBuilder($name)); - } - - /** - * @phpstan-param non-empty-string $name - */ - public function start(string $name): SpanInterface - { - return $this->newSpan($name)->startSpan(); - } - - /** - * @template U - * - * @param non-empty-string $name - * @param Closure(SpanInterface $span): U $callback - * @return (U is PendingDispatch ? null : U) - * - * @throws \Throwable - */ - public function measure(string $name, Closure $callback) - { - return $this->newSpan($name)->measure($callback); - } - public function currentContext(): ContextInterface { return Context::getCurrent(); @@ -72,20 +40,6 @@ public function traceId(): string return $this->activeSpan()->getContext()->getTraceId(); } - public function propagationHeaders(?ContextInterface $context = null): array - { - $headers = []; - - $this->propagator->inject($headers, context: $context); - - return $headers; - } - - public function extractContextFromPropagationHeaders(array $headers): ContextInterface - { - return $this->propagator->extract($headers); - } - public function isRecording(): bool { $enabled = config('opentelemetry.enabled', true); @@ -101,6 +55,28 @@ public function isRecording(): bool return false; } + /** + * @phpstan-param non-empty-string $name + */ + public function newSpan(string $name): SpanBuilder + { + return new SpanBuilder($this->tracer->spanBuilder($name)); + } + + public function propagationHeaders(?ContextInterface $context = null): array + { + $headers = []; + + $this->propagator->inject($headers, context: $context); + + return $headers; + } + + public function extractContextFromPropagationHeaders(array $headers): ContextInterface + { + return $this->propagator->extract($headers); + } + public function updateLogContext(): void { if (config('opentelemetry.logs.inject_trace_id', true)) { diff --git a/tests/Instrumentation/HttpClientInstrumentationTest.php b/tests/Instrumentation/HttpClientInstrumentationTest.php index 2ad90c6..1a5c109 100644 --- a/tests/Instrumentation/HttpClientInstrumentationTest.php +++ b/tests/Instrumentation/HttpClientInstrumentationTest.php @@ -21,7 +21,7 @@ new Response(200, ['Content-Length' => 0]), ]); - $root = Tracer::start('root'); + $root = Tracer::newSpan('root')->start(); $scope = $root->activate(); Http::withTrace()->get(Server::$url); diff --git a/tests/Pest.php b/tests/Pest.php index 1722681..1968512 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -30,7 +30,7 @@ function getRecordedSpans(): array function withRootSpan(Closure $callback): mixed { - $rootSpan = \Keepsuit\LaravelOpenTelemetry\Facades\Tracer::newSpan('root')->startSpan(); + $rootSpan = \Keepsuit\LaravelOpenTelemetry\Facades\Tracer::newSpan('root')->start(); $rootScope = $rootSpan->activate(); $result = $callback(); diff --git a/tests/TracerTest.php b/tests/TracerTest.php index 65ce2de..70577ae 100644 --- a/tests/TracerTest.php +++ b/tests/TracerTest.php @@ -25,7 +25,7 @@ }); it('can measure a span', function () { - $span = Tracer::start('test span'); + $span = Tracer::newSpan('test span')->start(); expect(Tracer::activeSpan())->not->toBe($span); @@ -49,7 +49,7 @@ it('can measure sequential spans', function () { $startTimestamp = ClockFactory::getDefault()->now(); - $span1 = Tracer::start('test span 1'); + $span1 = Tracer::newSpan('test span 1')->start(); assert($span1 instanceof Span); expect(Tracer::activeSpan())->not->toBe($span1); @@ -58,7 +58,7 @@ $span1->end(); - $span2 = Tracer::start('test span 2'); + $span2 = Tracer::newSpan('test span 2')->start(); assert($span2 instanceof Span); expect(Tracer::activeSpan())->not->toBe($span2); @@ -83,10 +83,10 @@ it('can measure parallel spans', function () { $startTimestamp = ClockFactory::getDefault()->now(); - $span1 = Tracer::start('test span 1'); + $span1 = Tracer::newSpan('test span 1')->start(); assert($span1 instanceof Span); - $span2 = Tracer::start('test span 2'); + $span2 = Tracer::newSpan('test span 2')->start(); assert($span2 instanceof Span); expect(Tracer::activeSpan()) @@ -117,7 +117,7 @@ it('can measure nested spans', function () { $startTimestamp = ClockFactory::getDefault()->now(); - $span1 = Tracer::start('test span 1'); + $span1 = Tracer::newSpan('test span 1')->start(); assert($span1 instanceof Span); $scope = $span1->activate(); @@ -125,7 +125,7 @@ TestTime::addSecond(); - $span2 = Tracer::start('test span 2'); + $span2 = Tracer::newSpan('test span 2')->start(); assert($span2 instanceof Span); expect(Tracer::activeSpan())->toBe($span1); @@ -155,7 +155,7 @@ it('can measure a callback', function () { /** @var Span $span */ - $span = Tracer::measure('test span', function (SpanInterface $span) { + $span = Tracer::newSpan('test span')->measure(function (SpanInterface $span) { TestTime::addSecond(); expect($span) @@ -176,7 +176,7 @@ $callbackSpan = null; try { - Tracer::measure('test span', function (SpanInterface $span) use (&$callbackSpan) { + Tracer::newSpan('test span')->measure(function (SpanInterface $span) use (&$callbackSpan) { $callbackSpan = $span; throw new Exception('test exception'); @@ -198,7 +198,7 @@ }); it('provides headers for propagation', function () { - $span = Tracer::start('test span'); + $span = Tracer::newSpan('test span')->start(); $scope = $span->activate(); expect(Tracer::propagationHeaders()) @@ -211,7 +211,7 @@ }); it('provides traceId and spanId for propagation', function () { - $span = Tracer::start('test span'); + $span = Tracer::newSpan('test span')->start(); $scope = $span->activate(); expect(Tracer::traceId())->toBe($span->getContext()->getTraceId()); @@ -221,7 +221,7 @@ }); it('provides active span', function () { - $span = Tracer::start('test span'); + $span = Tracer::newSpan('test span')->start(); $scope = $span->activate(); expect(Tracer::activeSpan())->toBe($span); @@ -231,7 +231,7 @@ }); it('set traceId to log context', function () { - $span = Tracer::start('test span'); + $span = Tracer::newSpan('test span')->start(); $scope = $span->activate(); expect(Log::sharedContext())->toBe([]);