Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 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()
);
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
Expand Up @@ -4,19 +4,24 @@

namespace OpenTelemetry\Tests\Propagation\Instana\Unit;

use OpenTelemetry\API\Baggage\Baggage;
use OpenTelemetry\API\Baggage\Metadata;
use OpenTelemetry\API\Trace\SpanContext;
use OpenTelemetry\API\Trace\SpanContextInterface;
use OpenTelemetry\API\Trace\SpanContextValidator;
use OpenTelemetry\API\Trace\TraceFlags;
use OpenTelemetry\Context\Context;

use OpenTelemetry\Context\ContextInterface;
use OpenTelemetry\Contrib\Propagation\Instana\InstanaMultiPropagator as InstanaMultiPropagator;
use OpenTelemetry\Context\Propagation\MultiTextMapPropagator;
use OpenTelemetry\Contrib\Propagation\Instana\InstanaPropagator;
use OpenTelemetry\API\Baggage\Propagation\BaggagePropagator;

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

final class InstanaMultiPropagatorTest extends TestCase
final class InstanaPropagatorTest extends TestCase
{
private const X_INSTANA_T = 'ff000000000000000000000000000041';
private const X_INSTANA_S = 'ff00000000000041';
Expand All @@ -27,13 +32,13 @@ final class InstanaMultiPropagatorTest extends TestCase
private $SPAN_ID;
private $SAMPLED;

private InstanaMultiPropagator $instanaMultiPropagator;
private InstanaPropagator $InstanaPropagator;

#[Override]
protected function setUp(): void
{
$this->instanaMultiPropagator = InstanaMultiPropagator::getInstance();
$instanaMultiFields = $this->instanaMultiPropagator->fields();
$this->InstanaPropagator = InstanaPropagator::getInstance();
$instanaMultiFields = $this->InstanaPropagator->fields();
$this->TRACE_ID = $instanaMultiFields[0];
$this->SPAN_ID = $instanaMultiFields[1];
$this->SAMPLED = $instanaMultiFields[2];
Expand All @@ -43,22 +48,22 @@ public function test_fields(): void
{
$this->assertSame(
['X-INSTANA-T', 'X-INSTANA-S', 'X-INSTANA-L'],
$this->instanaMultiPropagator->fields()
$this->InstanaPropagator->fields()
);
}

public function test_inject_empty(): void
{
$carrier = [];
$this->instanaMultiPropagator->inject($carrier);
$this->InstanaPropagator->inject($carrier);
$this->assertEmpty($carrier);
}

public function test_inject_invalid_context(): void
{
$carrier = [];
$this
->instanaMultiPropagator
->InstanaPropagator
->inject(
$carrier,
null,
Expand All @@ -78,7 +83,7 @@ public function test_inject_sampled_context(): void
{
$carrier = [];
$this
->instanaMultiPropagator
->InstanaPropagator
->inject(
$carrier,
null,
Expand All @@ -102,7 +107,7 @@ public function test_inject_non_sampled_context(): void
{
$carrier = [];
$this
->instanaMultiPropagator
->InstanaPropagator
->inject(
$carrier,
null,
Expand All @@ -126,7 +131,7 @@ public function test_inject_sampled_context_when_other_traceflags_set(): void
{
$carrier = [];
$this
->instanaMultiPropagator
->InstanaPropagator
->inject(
$carrier,
null,
Expand Down Expand Up @@ -156,7 +161,7 @@ public function test_extract_context_with_lowercase_headers(): void

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

Expand All @@ -170,6 +175,90 @@ public function test_extract_context_with_no_span_headers(): void
);
}

/**
* @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
);
}

/**
* @dataProvider sampledValueProvider
*/
Expand All @@ -183,7 +272,7 @@ public function test_extract_sampled_context($sampledValue): void

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

Expand All @@ -210,7 +299,7 @@ public function test_extract_non_sampled_context($sampledValue): void

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

Expand All @@ -237,7 +326,7 @@ public function test_extract_default_sampled_context($sampledValue): void

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

Expand All @@ -262,7 +351,7 @@ public function test_extract_invalid_sampled_context($sampledValue): void

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

Expand All @@ -286,7 +375,7 @@ public function test_extract_context_with_sampled_no_trace_and_span_headers(): v
'0000000000000000',
TraceFlags::SAMPLED
),
$this->getSpanContext($this->instanaMultiPropagator->extract($carrier))
$this->getSpanContext($this->InstanaPropagator->extract($carrier))
);
}

Expand All @@ -302,7 +391,7 @@ public function test_extract_context_with_no_trace_and_span_headers(): void
'0000000000000000',
TraceFlags::DEFAULT
),
$this->getSpanContext($this->instanaMultiPropagator->extract($carrier))
$this->getSpanContext($this->InstanaPropagator->extract($carrier))
);
}

Expand All @@ -313,9 +402,9 @@ public function test_extract_and_inject(): void
$this->SPAN_ID => self::X_INSTANA_S,
$this->SAMPLED => self::IS_SAMPLED,
];
$context = $this->instanaMultiPropagator->extract($extractCarrier);
$context = $this->InstanaPropagator->extract($extractCarrier);
$injectCarrier = [];
$this->instanaMultiPropagator->inject($injectCarrier, null, $context);
$this->InstanaPropagator->inject($injectCarrier, null, $context);
$this->assertSame($injectCarrier, $extractCarrier);
}

Expand All @@ -340,7 +429,7 @@ public function test_extract_leftpad_spand_id(): void

$this->assertEquals(
SpanContext::createFromRemoteParent('00000000000000004aaba1a52cf8ee09', '0007b5a2e4d86bd1', TraceFlags::SAMPLED),
$this->getSpanContext($this->instanaMultiPropagator->extract($carrier))
$this->getSpanContext($this->InstanaPropagator->extract($carrier))
);
}

Expand Down Expand Up @@ -403,7 +492,7 @@ private function assertInvalid(array $carrier): void
{
$this->assertSame(
Context::getCurrent(),
$this->instanaMultiPropagator->extract($carrier),
$this->InstanaPropagator->extract($carrier),
);
}

Expand Down
Loading