-
Notifications
You must be signed in to change notification settings - Fork 192
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* adding LocalRootSpan class this is based on Java's implementation, /~https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/v2.3.0/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/LocalRootSpan.java and adds the ability to identify and locate the "local root span" in a trace. The local root span is the top-level active span which has either an invalid or remote parent. It's tracked automatically as part of making a span active, either via `Span::activate()` or `Span::storeInContext()`, and can be retrieved in a couple of ways, but most easily via `LocalRootSpan::current()`. * remove redundant local root span check * move context key to api * internal * adding example * mark LocalRootSpan as experimental * adding an example of local root span usage * style, fix broken build
- Loading branch information
Showing
8 changed files
with
284 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
use OpenTelemetry\API\Trace\LocalRootSpan; | ||
use OpenTelemetry\API\Trace\Span; | ||
use OpenTelemetry\API\Trace\SpanKind; | ||
use OpenTelemetry\SDK\Common\Util\ShutdownHandler; | ||
use OpenTelemetry\SDK\Propagation\PropagatorFactory; | ||
use OpenTelemetry\SDK\Trace\TracerProviderFactory; | ||
|
||
putenv('OTEL_TRACES_EXPORTER=console'); | ||
putenv('OTEL_PHP_DETECTORS=none'); | ||
|
||
require_once __DIR__ . '/../../../vendor/autoload.php'; | ||
|
||
$provider = (new TracerProviderFactory())->create(); | ||
$propagator = (new PropagatorFactory())->create(); | ||
ShutdownHandler::register([$provider, 'shutdown']); | ||
$tracer = $provider->getTracer('example'); | ||
|
||
//start and activate a root span | ||
$root = $tracer | ||
->spanBuilder('root') | ||
->setSpanKind(SpanKind::KIND_SERVER) | ||
->startSpan(); | ||
$rootScope = $root->activate(); | ||
|
||
//start and activate a child span | ||
$child = $tracer | ||
->spanBuilder('child') | ||
->startSpan(); | ||
$childScope = $child->activate(); | ||
|
||
//update the name of the root span | ||
LocalRootSpan::current()->updateName('updated')->setAttribute('my-attr', true); | ||
|
||
//end spans and detach contexts | ||
$child->end(); | ||
$childScope->detach(); | ||
$root->end(); | ||
$rootScope->detach(); |
58 changes: 58 additions & 0 deletions
58
examples/traces/features/local_root_span_with_remote_parent.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
/** | ||
* @see https://opentelemetry.io/docs/specs/semconv/messaging/messaging-spans/#consumer-spans | ||
*/ | ||
|
||
use OpenTelemetry\API\Trace\LocalRootSpan; | ||
use OpenTelemetry\API\Trace\Span; | ||
use OpenTelemetry\API\Trace\SpanContext; | ||
use OpenTelemetry\API\Trace\SpanKind; | ||
use OpenTelemetry\Context\Context; | ||
use OpenTelemetry\SDK\Common\Util\ShutdownHandler; | ||
use OpenTelemetry\SDK\Propagation\PropagatorFactory; | ||
use OpenTelemetry\SDK\Trace\TracerProviderFactory; | ||
|
||
putenv('OTEL_TRACES_EXPORTER=console'); | ||
putenv('OTEL_PHP_DETECTORS=none'); | ||
|
||
require_once __DIR__ . '/../../../vendor/autoload.php'; | ||
|
||
$provider = (new TracerProviderFactory())->create(); | ||
$propagator = (new PropagatorFactory())->create(); | ||
ShutdownHandler::register([$provider, 'shutdown']); | ||
$tracer = $provider->getTracer('example'); | ||
|
||
// “Receive” spans SHOULD be created for operations of passing messages to the application when those operations are initiated by the application code (pull-based scenarios). | ||
$root = $tracer | ||
->spanBuilder('receive') | ||
->setSpanKind(SpanKind::KIND_CONSUMER) | ||
->startSpan(); | ||
|
||
$rootScope = $root | ||
->storeInContext(Context::getCurrent()) | ||
->activate(); | ||
assert(LocalRootSpan::fromContext(Context::getCurrent()) === $root); | ||
|
||
$root->addLink(SpanContext::createFromRemoteParent('fabebb164f22d4afc51df50d9a3ff629', '87c6836d8610ac6d', 768)); | ||
|
||
// “Process” spans MAY be created in addition to “Receive” spans for pull-based scenarios for operations of processing messages. | ||
$child = $tracer | ||
->spanBuilder('process') | ||
->startSpan(); | ||
$childScope = $child | ||
//->storeInContext($remoteContext) // preserve remote baggage etc. | ||
->storeInContext(Context::getCurrent()) | ||
->activate(); | ||
$child->setAttribute('local_root', LocalRootSpan::current() === Span::getCurrent()); | ||
|
||
try { | ||
assert(LocalRootSpan::current() === $root); | ||
assert(LocalRootSpan::current() !== Span::getCurrent()); | ||
} finally { | ||
$root->end(); | ||
$child->end(); | ||
$childScope->detach(); | ||
$rootScope->detach(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace OpenTelemetry\API\Trace; | ||
|
||
use OpenTelemetry\Context\Context; | ||
use OpenTelemetry\Context\ContextInterface; | ||
use OpenTelemetry\Context\ContextKeyInterface; | ||
|
||
/** | ||
* @experimental | ||
*/ | ||
class LocalRootSpan | ||
{ | ||
/** | ||
* Retrieve the local root span. This is the root-most active span which has | ||
* a remote or invalid parent. | ||
* If there is no active local root span, then an invalid span is returned. | ||
* @experimental | ||
*/ | ||
public static function current(): SpanInterface | ||
{ | ||
return self::fromContext(Context::getCurrent()); | ||
} | ||
|
||
/** | ||
* Retrieve the local root span from a Context. | ||
* @experimental | ||
*/ | ||
public static function fromContext(ContextInterface $context): SpanInterface | ||
{ | ||
return $context->get(self::key()) ?? Span::getInvalid(); | ||
} | ||
|
||
/** | ||
* @internal | ||
*/ | ||
public static function store(ContextInterface $context, SpanInterface $span): ContextInterface | ||
{ | ||
return $context->with(self::key(), $span); | ||
} | ||
|
||
/** | ||
* @internal | ||
*/ | ||
public static function key(): ContextKeyInterface | ||
{ | ||
static $key; | ||
|
||
return $key ??= Context::createKey(self::class); | ||
} | ||
|
||
/** | ||
* @internal | ||
*/ | ||
public static function isLocalRoot(ContextInterface $parentContext): bool | ||
{ | ||
$spanContext = Span::fromContext($parentContext)->getContext(); | ||
|
||
return !$spanContext->isValid() || $spanContext->isRemote(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace OpenTelemetry\Tests\Integration\SDK; | ||
|
||
use OpenTelemetry\API\Trace\LocalRootSpan; | ||
use OpenTelemetry\API\Trace\Span; | ||
use OpenTelemetry\API\Trace\SpanInterface; | ||
use OpenTelemetry\Context\Context; | ||
use OpenTelemetry\SDK\Trace\TracerProvider; | ||
use PHPUnit\Framework\Attributes\CoversNothing; | ||
use PHPUnit\Framework\TestCase; | ||
|
||
#[CoversNothing] | ||
class LocalRootSpanTest extends TestCase | ||
{ | ||
private SpanInterface $span; | ||
|
||
public function setUp(): void | ||
{ | ||
$tracerProvider = new TracerProvider(); | ||
$this->span = $tracerProvider->getTracer('test')->spanBuilder('my-local-root-span')->startSpan(); | ||
} | ||
|
||
public function test_active_root_span_is_local_root(): void | ||
{ | ||
$scope = $this->span->activate(); | ||
|
||
try { | ||
$this->assertSame($this->span, LocalRootSpan::current()); | ||
} finally { | ||
$scope->detach(); | ||
} | ||
$this->assertSame(Span::getInvalid(), LocalRootSpan::current(), 'root span ended, a local root span does not exist'); | ||
} | ||
|
||
public function test_root_span_stored_in_context_is_local_root(): void | ||
{ | ||
$root = Context::getRoot(); | ||
Context::storage()->attach($this->span->storeInContext($root)); | ||
$this->assertSame($this->span, LocalRootSpan::current()); | ||
$scope = Context::storage()->scope(); | ||
$this->assertNotNull($scope); | ||
$this->assertSame($this->span, Span::fromContext($scope->context())); | ||
$scope->detach(); | ||
$this->assertSame(Span::getInvalid(), LocalRootSpan::current(), 'root span ended, a local root span does not exist'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace OpenTelemetry\Tests\Unit\API\Trace; | ||
|
||
use OpenTelemetry\API\Trace\LocalRootSpan; | ||
use OpenTelemetry\API\Trace\Span; | ||
use OpenTelemetry\API\Trace\SpanContext; | ||
use OpenTelemetry\Context\Context; | ||
use PHPUnit\Framework\Attributes\CoversClass; | ||
use PHPUnit\Framework\TestCase; | ||
|
||
#[CoversClass(LocalRootSpan::class)] | ||
class LocalRootSpanTest extends TestCase | ||
{ | ||
public function test_span_with_remote_parent_is_local_root(): void | ||
{ | ||
$context = Context::getRoot()->with( | ||
LocalRootSpan::key(), | ||
Span::wrap( | ||
SpanContext::createFromRemoteParent( | ||
'00000000000000000000000000000001', | ||
'0000000000000002', | ||
) | ||
) | ||
); | ||
$this->assertTrue(LocalRootSpan::isLocalRoot($context)); | ||
} | ||
|
||
public function test_get_local_root_span(): void | ||
{ | ||
$span = Span::getInvalid(); | ||
$context = LocalRootSpan::store(Context::getCurrent(), $span); | ||
$scope = $context->activate(); | ||
|
||
try { | ||
$this->assertSame($span, LocalRootSpan::fromContext($context)); | ||
$this->assertSame($span, LocalRootSpan::current()); | ||
} finally { | ||
$scope->detach(); | ||
} | ||
} | ||
|
||
public function test_get_local_root_span_when_not_set(): void | ||
{ | ||
$context = Context::getRoot(); | ||
$scope = $context->activate(); | ||
|
||
try { | ||
$this->assertFalse(LocalRootSpan::fromContext($context)->getContext()->isValid()); | ||
$this->assertFalse(LocalRootSpan::current()->getContext()->isValid()); | ||
$this->assertSame(Span::getInvalid(), LocalRootSpan::current()); | ||
} finally { | ||
$scope->detach(); | ||
} | ||
} | ||
} |