open-telemetry / opentelemetry-php

The OpenTelemetry PHP Library
https://opentelemetry.io/docs/instrumentation/php/
Apache License 2.0
751 stars 186 forks source link

Multi span traces #546

Closed markvdlaan93 closed 2 years ago

markvdlaan93 commented 2 years ago

Currently, I try to create a single trace with multiple spans. Is this something that is supported at the moment? I've tried to explicitly call the storeInContext method but that doesn't seem to work. This will create a separate trace per span. My code looks like this:



use OpenTelemetry\Contrib\OtlpHttp\Exporter as OtlpHttpExporter;
use OpenTelemetry\Sdk\Trace\Clock;
use OpenTelemetry\Context\Context;
use OpenTelemetry\Sdk\Trace\Sampler\AlwaysOnSampler;
use OpenTelemetry\Sdk\Trace\SamplingResult;
use OpenTelemetry\Sdk\Trace\SpanProcessor\BatchSpanProcessor;
use OpenTelemetry\Sdk\Trace\TracerProvider;
use GuzzleHttp\Client;
use Illuminate\Foundation\Http\Events\RequestHandled;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Event;
use Nyholm\Psr7\Factory\Psr17Factory;
use OpenTelemetry\API\Baggage\BaggageBuilder;
use OpenTelemetry\API\Trace\SpanContextKey;
use OpenTelemetry\API\Trace\SpanKind;
use OpenTelemetry\Sdk\Trace\Attributes;
use OpenTelemetry\SDK\Trace\SystemClock;

$sampler = new AlwaysOnSampler();
$parentContext = new Context(new SpanContextKey('request_id'), '12345678');
$samplingResult = $sampler->shouldSample(
    $parentContext,
    md5((string) microtime(true)),
    'my.sampler',
    SpanKind::KIND_SERVER
);

$factory = new Psr17Factory();
$otlpExporter = new OtlpHttpExporter(new Client(), $factory, $factory);

if (SamplingResult::RECORD_AND_SAMPLE === $samplingResult->getDecision()) {
    $spanProcessors = [new BatchSpanProcessor($otlpExporter, SystemClock::getInstance())];
    $traceProvider = new TracerProvider($spanProcessors, $sampler);
    $otlpTracer = $traceProvider->getTracer('io.opentelemetry.contrib.php');

    $spanName = 'my.span';
    $spanBuilder = $otlpTracer->spanBuilder($spanName);
    $spanBuilder->setParent($parentContext);

    $span = $spanBuilder->startSpan();
    $span->storeInContext($parentContext);

    $attributes = new Attributes(['test' => 'test']);
    $span->setAttributes($attributes);

    $span->activate();
    $span->end();

    $secondSpan = $spanBuilder->startSpan();
    $secondSpan->storeInContext($parentContext);

    $attributes = new Attributes(['test2' => 'test2']);
    $secondSpan->setAttributes($attributes);

    $secondSpan->activate();
    $secondSpan->end();
}
tidal commented 2 years ago

Currently, I try to create a single trace with multiple spans. Is this something that is supported at the moment?

Yes, it is. Take a look at this example:


/**
 * Create the Tracer
 */
$tracerProvider = new TracerProvider(
    new SimpleSpanProcessor(new OtlpHttpExporter),
    new AlwaysOnSampler()
);
$tracer = $tracerProvider->getTracer();
/**
 * Create some tracing data
 */
echo 'Start Logging ...' . PHP_EOL;
$rootSpan = $tracer->spanBuilder('root')->startSpan();
$rootSpan->activate();

$spans = [];

for ($i = 0; $i < 5; $i++) {
    usleep(200000);

    $span = $tracer->spanBuilder('log.span' . ($i + 1))->startSpan();

    usleep(20000);

    $spans[] = $span;
}

$spans = array_reverse($spans);
foreach ($spans as $span) {
    usleep(200000);
    $span->end();
}

$rootSpan->end();
echo 'Finished!' . PHP_EOL;
markvdlaan93 commented 2 years ago

Thanks for the example. The crucial thing that I was missing was the order of the end calls. The last child span end must be called first. Quite logical if you think about it but maybe good to add this example somewhere so that it is clear for other how to implement this feature.

bobstrecansky commented 2 years ago

Thanks for the report @markvdlaan93 ! Will be happy to merge a PR if you open one adding this example.

markvdlaan93 commented 2 years ago

@bobstrecansky Okay sure. Somewhere this week, I'll open a PR.

stale[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] commented 2 years ago

This issue has been automatically closed because it has not had recent activity, but it can be reopened. Thank you for your contributions.