Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions src/Propagation/Instana/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
OpenTelemetry Instana Propagator
[![Releases](https://img.shields.io/badge/releases-purple)](https://github.com/opentelemetry-php/contrib-propagator-instana/releases)
[![Issues](https://img.shields.io/badge/issues-pink)](https://github.com/open-telemetry/opentelemetry-php/issues)
[![Source](https://img.shields.io/badge/source-contrib-green)](https://github.com/open-telemetry/opentelemetry-php-contrib/tree/main/src/Propagation/Instana)
[![Mirror](https://img.shields.io/badge/mirror-opentelemetry--php--contrib-blue)](https://github.com/opentelemetry-php/contrib-propagator-instana)
[![Latest Version](http://poser.pugx.org/open-telemetry/opentelemetry-propagation-instana/v/unstable)](https://packagist.org/packages/open-telemetry/opentelemetry-propagation-instana/)
[![Stable](http://poser.pugx.org/open-telemetry/opentelemetry-propagation-instana/v/stable)](https://packagist.org/packages/open-telemetry/opentelemetry-propagation-instana/)

The OpenTelemetry Propagator for Instana provides HTTP header propagation for systems that are using IBM Observability by Instana.
This is a read-only subtree split of https://github.com/open-telemetry/opentelemetry-php-contrib.

# OpenTelemetry Instana Propagator

The OpenTelemetry Propagator for Instana provides HTTP header propagation and Baggage propagation for systems that are using IBM Observability by Instana.
This propagator translates the Instana trace correlation headers (`X-INSTANA-T/X-INSTANA-S/X-INSTANA-L`) into the OpenTelemetry `SpanContext`, and vice versa.
It does not handle `TraceState`.

Expand All @@ -14,11 +23,17 @@ composer require open-telemetry/opentelemetry-propagation-instana
## Usage

```
$propagator = InstanaMultiPropagator::getInstance();
$propagator = InstanaPropagator::getInstance();
```

Both of the above have extract and inject methods available to extract and inject respectively into the header.

For Baggage propagation, use opentelemetry's MultiTextMapPropagator, and pass the array list of propagators i.e Instana and Baggage propagator as below.

```
$propagator = new MultiTextMapPropagator(InstantPropagator::getInstance(), BaggagePropagator::getInstance());
```

## Propagator Details

There are three headers that the propagator handles: `X-INSTANA-T` (the trace ID), `X-INSTANA-S` (the parent span ID), and `X-INSTANA-L` (the sampling level).
Expand Down
6 changes: 4 additions & 2 deletions src/Propagation/Instana/_register.php
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
<?php

declare(strict_types=1);
use OpenTelemetry\Contrib\Propagation\Instana\InstanaMultiPropagator;

use OpenTelemetry\Contrib\Propagation\Instana\InstanaPropagator;
use OpenTelemetry\SDK\Registry;

if (!class_exists(Registry::class)) {
return;
}

Registry::registerTextMapPropagator(
'instana',
InstanaMultiPropagator::getInstance()
InstanaPropagator::getInstance()
);
3 changes: 3 additions & 0 deletions src/Propagation/Instana/phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
<testsuite name="unit">
<directory>tests/Unit</directory>
</testsuite>
<testsuite name="integration">
<directory>tests/Integration</directory>
</testsuite>
</testsuites>

</phpunit>
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
* "instana" http headers used for trace context propagation across service
* boundaries.
*/
final class InstanaMultiPropagator implements TextMapPropagatorInterface
final class InstanaPropagator implements TextMapPropagatorInterface
{
/**
* The X-INSTANA-T header is required and is encoded as 32 lower-hex characters.
Expand Down Expand Up @@ -115,7 +115,6 @@ public function extract($carrier, ?PropagationGetterInterface $getter = null, ?C
if (($traceId === '' && $spanId === '') && $level !== null) {
return (new NonRecordingSpan($spanContext))
->storeInContext($context);

} elseif (!$spanContext->isValid()) {
return $context;
}
Expand Down Expand Up @@ -161,7 +160,7 @@ private static function extractImpl($carrier, PropagationGetterInterface $getter
}

if ($spanId && strlen($spanId) < 16) {
$spanId = str_pad($spanId, 16, '0', STR_PAD_LEFT);
$spanId = str_pad($spanId, 16, '0', STR_PAD_LEFT);
}

return SpanContext::createFromRemoteParent(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
<?php

declare(strict_types=1);

namespace OpenTelemetry\Tests\Propagation\Instana\Integration;

use OpenTelemetry\API\Baggage\Baggage;
use OpenTelemetry\API\Baggage\Metadata;
use OpenTelemetry\API\Baggage\Propagation\BaggagePropagator;
use OpenTelemetry\API\Trace\SpanContext;
use OpenTelemetry\API\Trace\SpanContextInterface;
use OpenTelemetry\API\Trace\TraceFlags;

use OpenTelemetry\Context\Context;
use OpenTelemetry\Context\ContextInterface;
use OpenTelemetry\Context\Propagation\MultiTextMapPropagator;
use OpenTelemetry\Contrib\Propagation\Instana\InstanaPropagator;

use OpenTelemetry\SDK\Trace\Span;
use Override;
use PHPUnit\Framework\TestCase;

final class InstanaMultiPropagatorTest extends TestCase
{
private const X_INSTANA_T = 'ff000000000000000000000000000041';
private const X_INSTANA_S = 'ff00000000000041';

private $TRACE_ID;
private $SPAN_ID;
private $SAMPLED;

private InstanaPropagator $InstanaPropagator;

#[Override]
protected function setUp(): void
{
$this->InstanaPropagator = InstanaPropagator::getInstance();
$instanaMultiFields = $this->InstanaPropagator->fields();
$this->TRACE_ID = $instanaMultiFields[0];
$this->SPAN_ID = $instanaMultiFields[1];
$this->SAMPLED = $instanaMultiFields[2];
}

/**
* @dataProvider sampledValueProvider
*/
public function test_extract_sampled_context_with_baggage($sampledValue): void
{
$carrier = [
$this->TRACE_ID => self::X_INSTANA_T,
$this->SPAN_ID => self::X_INSTANA_S,
$this->SAMPLED => $sampledValue,
'baggage' => 'user_id=12345,request_id=abcde',
];
$propagator = new MultiTextMapPropagator([InstanaPropagator::getInstance(), BaggagePropagator::getInstance()]);
$context = $propagator->extract($carrier);

$this->assertEquals(
SpanContext::createFromRemoteParent(self::X_INSTANA_T, self::X_INSTANA_S, TraceFlags::SAMPLED),
$this->getSpanContext($this->InstanaPropagator->extract($carrier))
);

// Verify baggage
$baggage = Baggage::fromContext($context);
$this->assertEquals('12345', $baggage->getValue('user_id'));
$this->assertEquals('abcde', $baggage->getValue('request_id'));

$arr = [];

foreach ($baggage->getAll() as $key => $value) {
$arr[$key] = $value->getValue();
}

$this->assertEquals(
['user_id' => '12345', 'request_id' => 'abcde'],
$arr
);
}

/**
* @dataProvider sampledValueProvider
*/
public function test_extract_sampled_context_with_baggage_but_instana_propagator($sampledValue): void
{
$carrier = [
$this->TRACE_ID => self::X_INSTANA_T,
$this->SPAN_ID => self::X_INSTANA_S,
$this->SAMPLED => $sampledValue,
'baggage' => 'user_id=12345,request_id=abcde',
];
$context = $this->InstanaPropagator->extract($carrier);

$this->assertEquals(
SpanContext::createFromRemoteParent(self::X_INSTANA_T, self::X_INSTANA_S, TraceFlags::SAMPLED),
$this->getSpanContext($this->InstanaPropagator->extract($carrier))
);

// Verify baggage is not propagated
$baggage = Baggage::fromContext($context);
$this->assertNull($baggage->getValue('user_id'));
$this->assertNull($baggage->getValue('request_id'));

}

public function test_baggage_inject(): void
{
$carrier = [];

$propagator = new MultiTextMapPropagator([InstanaPropagator::getInstance(), BaggagePropagator::getInstance()]);

$propagator->inject(
$carrier,
null,
Context::getRoot()->withContextValue(
Baggage::getBuilder()
->set('nometa', 'nometa-value')
->set('meta', 'meta-value', new Metadata('somemetadata; someother=foo'))
->build()
)
);

$this->assertSame(
['baggage' => 'nometa=nometa-value,meta=meta-value;somemetadata; someother=foo'],
$carrier
);
}

public static function sampledValueProvider(): array
{
return [
'String sampled value' => ['1'],
'Boolean(lower string) sampled value' => ['true'],
'Boolean(upper string) sampled value' => ['TRUE'],
'Boolean(camel string) sampled value' => ['True'],
];
}

private function getSpanContext(ContextInterface $context): SpanContextInterface
{
return Span::fromContext($context)->getContext();
}

}
Loading
Loading