Skip to content

Commit da5f909

Browse files
Add baggage propagation in instana (#370)
* Initial commit to add Instana Propagator * Adding Instana project in to github actions * Updated Readme with usage and addressed review comments * Addressed review comments * Removed extra new lines * Fixed style * Updated Path for Instana Class * Update src/Propagation/Instana/composer.json Co-authored-by: Chris Lightfoot-Wild <[email protected]> * Updated override attribute for extract inject and fields attribute * Support Baggage propagation to the Instana propagator * Fixed formatting from previous PR * Fixed static analysis faliure * Updated readme with releases links * Removed Custom Instana propagator for baggage propagation since multitextmappropagator will suffice the same * Moved baggage Unit testcases to Integration testcases --------- Co-authored-by: Chris Lightfoot-Wild <[email protected]>
1 parent 3f003f3 commit da5f909

File tree

6 files changed

+194
-31
lines changed

6 files changed

+194
-31
lines changed

src/Propagation/Instana/README.md

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
1-
OpenTelemetry Instana Propagator
1+
[![Releases](https://img.shields.io/badge/releases-purple)](https://github.com/opentelemetry-php/contrib-propagator-instana/releases)
2+
[![Issues](https://img.shields.io/badge/issues-pink)](https://github.com/open-telemetry/opentelemetry-php/issues)
3+
[![Source](https://img.shields.io/badge/source-contrib-green)](https://github.com/open-telemetry/opentelemetry-php-contrib/tree/main/src/Propagation/Instana)
4+
[![Mirror](https://img.shields.io/badge/mirror-opentelemetry--php--contrib-blue)](https://github.com/opentelemetry-php/contrib-propagator-instana)
5+
[![Latest Version](http://poser.pugx.org/open-telemetry/opentelemetry-propagation-instana/v/unstable)](https://packagist.org/packages/open-telemetry/opentelemetry-propagation-instana/)
6+
[![Stable](http://poser.pugx.org/open-telemetry/opentelemetry-propagation-instana/v/stable)](https://packagist.org/packages/open-telemetry/opentelemetry-propagation-instana/)
27

3-
The OpenTelemetry Propagator for Instana provides HTTP header propagation for systems that are using IBM Observability by Instana.
8+
This is a read-only subtree split of https://github.com/open-telemetry/opentelemetry-php-contrib.
9+
10+
# OpenTelemetry Instana Propagator
11+
12+
The OpenTelemetry Propagator for Instana provides HTTP header propagation and Baggage propagation for systems that are using IBM Observability by Instana.
413
This propagator translates the Instana trace correlation headers (`X-INSTANA-T/X-INSTANA-S/X-INSTANA-L`) into the OpenTelemetry `SpanContext`, and vice versa.
514
It does not handle `TraceState`.
615

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

1625
```
17-
$propagator = InstanaMultiPropagator::getInstance();
26+
$propagator = InstanaPropagator::getInstance();
1827
```
1928

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

31+
For Baggage propagation, use opentelemetry's MultiTextMapPropagator, and pass the array list of propagators i.e Instana and Baggage propagator as below.
32+
33+
```
34+
$propagator = new MultiTextMapPropagator(InstantPropagator::getInstance(), BaggagePropagator::getInstance());
35+
```
36+
2237
## Propagator Details
2338

2439
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).
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
<?php
22

33
declare(strict_types=1);
4-
use OpenTelemetry\Contrib\Propagation\Instana\InstanaMultiPropagator;
4+
5+
use OpenTelemetry\Contrib\Propagation\Instana\InstanaPropagator;
56
use OpenTelemetry\SDK\Registry;
67

78
if (!class_exists(Registry::class)) {
89
return;
910
}
11+
1012
Registry::registerTextMapPropagator(
1113
'instana',
12-
InstanaMultiPropagator::getInstance()
14+
InstanaPropagator::getInstance()
1315
);

src/Propagation/Instana/phpunit.xml.dist

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@
3939
<testsuite name="unit">
4040
<directory>tests/Unit</directory>
4141
</testsuite>
42+
<testsuite name="integration">
43+
<directory>tests/Integration</directory>
44+
</testsuite>
4245
</testsuites>
4346

4447
</phpunit>

src/Propagation/Instana/src/InstanaMultiPropagator.php renamed to src/Propagation/Instana/src/InstanaPropagator.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
* "instana" http headers used for trace context propagation across service
2222
* boundaries.
2323
*/
24-
final class InstanaMultiPropagator implements TextMapPropagatorInterface
24+
final class InstanaPropagator implements TextMapPropagatorInterface
2525
{
2626
/**
2727
* The X-INSTANA-T header is required and is encoded as 32 lower-hex characters.
@@ -115,7 +115,6 @@ public function extract($carrier, ?PropagationGetterInterface $getter = null, ?C
115115
if (($traceId === '' && $spanId === '') && $level !== null) {
116116
return (new NonRecordingSpan($spanContext))
117117
->storeInContext($context);
118-
119118
} elseif (!$spanContext->isValid()) {
120119
return $context;
121120
}
@@ -161,7 +160,7 @@ private static function extractImpl($carrier, PropagationGetterInterface $getter
161160
}
162161

163162
if ($spanId && strlen($spanId) < 16) {
164-
$spanId = str_pad($spanId, 16, '0', STR_PAD_LEFT);
163+
$spanId = str_pad($spanId, 16, '0', STR_PAD_LEFT);
165164
}
166165

167166
return SpanContext::createFromRemoteParent(
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OpenTelemetry\Tests\Propagation\Instana\Integration;
6+
7+
use OpenTelemetry\API\Baggage\Baggage;
8+
use OpenTelemetry\API\Baggage\Metadata;
9+
use OpenTelemetry\API\Baggage\Propagation\BaggagePropagator;
10+
use OpenTelemetry\API\Trace\SpanContext;
11+
use OpenTelemetry\API\Trace\SpanContextInterface;
12+
use OpenTelemetry\API\Trace\TraceFlags;
13+
14+
use OpenTelemetry\Context\Context;
15+
use OpenTelemetry\Context\ContextInterface;
16+
use OpenTelemetry\Context\Propagation\MultiTextMapPropagator;
17+
use OpenTelemetry\Contrib\Propagation\Instana\InstanaPropagator;
18+
19+
use OpenTelemetry\SDK\Trace\Span;
20+
use Override;
21+
use PHPUnit\Framework\TestCase;
22+
23+
final class InstanaMultiPropagatorTest extends TestCase
24+
{
25+
private const X_INSTANA_T = 'ff000000000000000000000000000041';
26+
private const X_INSTANA_S = 'ff00000000000041';
27+
28+
private $TRACE_ID;
29+
private $SPAN_ID;
30+
private $SAMPLED;
31+
32+
private InstanaPropagator $InstanaPropagator;
33+
34+
#[Override]
35+
protected function setUp(): void
36+
{
37+
$this->InstanaPropagator = InstanaPropagator::getInstance();
38+
$instanaMultiFields = $this->InstanaPropagator->fields();
39+
$this->TRACE_ID = $instanaMultiFields[0];
40+
$this->SPAN_ID = $instanaMultiFields[1];
41+
$this->SAMPLED = $instanaMultiFields[2];
42+
}
43+
44+
/**
45+
* @dataProvider sampledValueProvider
46+
*/
47+
public function test_extract_sampled_context_with_baggage($sampledValue): void
48+
{
49+
$carrier = [
50+
$this->TRACE_ID => self::X_INSTANA_T,
51+
$this->SPAN_ID => self::X_INSTANA_S,
52+
$this->SAMPLED => $sampledValue,
53+
'baggage' => 'user_id=12345,request_id=abcde',
54+
];
55+
$propagator = new MultiTextMapPropagator([InstanaPropagator::getInstance(), BaggagePropagator::getInstance()]);
56+
$context = $propagator->extract($carrier);
57+
58+
$this->assertEquals(
59+
SpanContext::createFromRemoteParent(self::X_INSTANA_T, self::X_INSTANA_S, TraceFlags::SAMPLED),
60+
$this->getSpanContext($this->InstanaPropagator->extract($carrier))
61+
);
62+
63+
// Verify baggage
64+
$baggage = Baggage::fromContext($context);
65+
$this->assertEquals('12345', $baggage->getValue('user_id'));
66+
$this->assertEquals('abcde', $baggage->getValue('request_id'));
67+
68+
$arr = [];
69+
70+
foreach ($baggage->getAll() as $key => $value) {
71+
$arr[$key] = $value->getValue();
72+
}
73+
74+
$this->assertEquals(
75+
['user_id' => '12345', 'request_id' => 'abcde'],
76+
$arr
77+
);
78+
}
79+
80+
/**
81+
* @dataProvider sampledValueProvider
82+
*/
83+
public function test_extract_sampled_context_with_baggage_but_instana_propagator($sampledValue): void
84+
{
85+
$carrier = [
86+
$this->TRACE_ID => self::X_INSTANA_T,
87+
$this->SPAN_ID => self::X_INSTANA_S,
88+
$this->SAMPLED => $sampledValue,
89+
'baggage' => 'user_id=12345,request_id=abcde',
90+
];
91+
$context = $this->InstanaPropagator->extract($carrier);
92+
93+
$this->assertEquals(
94+
SpanContext::createFromRemoteParent(self::X_INSTANA_T, self::X_INSTANA_S, TraceFlags::SAMPLED),
95+
$this->getSpanContext($this->InstanaPropagator->extract($carrier))
96+
);
97+
98+
// Verify baggage is not propagated
99+
$baggage = Baggage::fromContext($context);
100+
$this->assertNull($baggage->getValue('user_id'));
101+
$this->assertNull($baggage->getValue('request_id'));
102+
103+
}
104+
105+
public function test_baggage_inject(): void
106+
{
107+
$carrier = [];
108+
109+
$propagator = new MultiTextMapPropagator([InstanaPropagator::getInstance(), BaggagePropagator::getInstance()]);
110+
111+
$propagator->inject(
112+
$carrier,
113+
null,
114+
Context::getRoot()->withContextValue(
115+
Baggage::getBuilder()
116+
->set('nometa', 'nometa-value')
117+
->set('meta', 'meta-value', new Metadata('somemetadata; someother=foo'))
118+
->build()
119+
)
120+
);
121+
122+
$this->assertSame(
123+
['baggage' => 'nometa=nometa-value,meta=meta-value;somemetadata; someother=foo'],
124+
$carrier
125+
);
126+
}
127+
128+
public static function sampledValueProvider(): array
129+
{
130+
return [
131+
'String sampled value' => ['1'],
132+
'Boolean(lower string) sampled value' => ['true'],
133+
'Boolean(upper string) sampled value' => ['TRUE'],
134+
'Boolean(camel string) sampled value' => ['True'],
135+
];
136+
}
137+
138+
private function getSpanContext(ContextInterface $context): SpanContextInterface
139+
{
140+
return Span::fromContext($context)->getContext();
141+
}
142+
143+
}

0 commit comments

Comments
 (0)