Skip to content

Commit b2b7bb1

Browse files
authored
Add traceresponse propagator (#143)
- Cleanup dependencies - Add PHPStan config and clean code - Allow PHP 7 compatible symfony/http-client - Add TraceResponse to .gitsplit - Fix test method casing
0 parents  commit b2b7bb1

File tree

9 files changed

+404
-0
lines changed

9 files changed

+404
-0
lines changed

.php-cs-fixer.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
$finder = PhpCsFixer\Finder::create()
3+
->exclude('vendor')
4+
->exclude('var/cache')
5+
->in(__DIR__);
6+
7+
$config = new PhpCsFixer\Config();
8+
return $config->setRules([
9+
'concat_space' => ['spacing' => 'one'],
10+
'declare_equal_normalize' => ['space' => 'none'],
11+
'is_null' => true,
12+
'modernize_types_casting' => true,
13+
'ordered_imports' => true,
14+
'php_unit_construct' => true,
15+
'single_line_comment_style' => true,
16+
'yoda_style' => false,
17+
'@PSR2' => true,
18+
'array_syntax' => ['syntax' => 'short'],
19+
'blank_line_after_opening_tag' => true,
20+
'blank_line_before_statement' => true,
21+
'cast_spaces' => true,
22+
'declare_strict_types' => true,
23+
'function_typehint_space' => true,
24+
'include' => true,
25+
'lowercase_cast' => true,
26+
'new_with_braces' => true,
27+
'no_extra_blank_lines' => true,
28+
'no_leading_import_slash' => true,
29+
'echo_tag_syntax' => true,
30+
'no_unused_imports' => true,
31+
'no_useless_else' => true,
32+
'no_useless_return' => true,
33+
'phpdoc_order' => true,
34+
'phpdoc_scalar' => true,
35+
'phpdoc_types' => true,
36+
'short_scalar_cast' => true,
37+
'single_blank_line_before_namespace' => true,
38+
'single_quote' => true,
39+
'trailing_comma_in_multiline' => true,
40+
])
41+
->setRiskyAllowed(true)
42+
->setFinder($finder);
43+

README.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# OpenTelemetry TraceResponse Propagator
2+
3+
**Note:** This package is experimental as `traceresponse` is currently an editors' draft.
4+
5+
This package provides a [Trace Context HTTP Response Headers Format](https://w3c.github.io/trace-context/#trace-context-http-response-headers-format)
6+
propagator to inject the current span context into Response datastructures.
7+
8+
The main goal is to allow client-side technology (Real User Monitoring, HTTP Clients) to record
9+
the server side context in order to allow referencing it.
10+
11+
## Requirements
12+
13+
* OpenTelemetry SDK and exporters (required to actually export traces)
14+
15+
Optional:
16+
* OpenTelemetry extension (Some instrumentations can automatically use the `TraceResponsePropagator`)
17+
18+
## Usage
19+
20+
Assuming there is an active `SpanContext`, you can inject it into your response as follows:
21+
22+
```php
23+
// your framework probably provides a datastructure to model HTTP responses
24+
// and allows you to hook into the end of a request / listen to a matching event.
25+
$response = new Response();
26+
27+
// get the current scope, bail out if none
28+
$scope = Context::storage()->scope();
29+
if (null === $scope) {
30+
return;
31+
}
32+
33+
// create a PropagationSetterInterface that knows how to inject response headers
34+
$propagationSetter = new class implements OpenTelemetry\Context\Propagation\PropagationSetterInterface {
35+
public function set(&$carrier, string $key, string $value) : void {
36+
$carrier->headers->set($key, $value);
37+
}
38+
};
39+
$propagator = new TraceResponseProgator();
40+
$propagator->inject($response, $propagationSetter, $scope->context());
41+
```
42+
43+
## Installation via composer
44+
45+
```bash
46+
$ composer require open-telemetry/opentelemetry-propagation-traceresponse
47+
```
48+
49+
## Installing dependencies and executing tests
50+
51+
From TraceResponse subdirectory:
52+
53+
```bash
54+
$ composer install
55+
$ ./vendor/bin/phpunit tests
56+
```

composer.json

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"name": "open-telemetry/opentelemetry-propagation-traceresponse",
3+
"description": "OpenTelemetry traceresponse propagator.",
4+
"keywords": ["opentelemetry", "otel", "open-telemetry", "propagator", "traceresponse"],
5+
"type": "library",
6+
"homepage": "https://opentelemetry.io/docs/php",
7+
"readme": "./README.md",
8+
"license": "Apache-2.0",
9+
"minimum-stability": "dev",
10+
"prefer-stable": true,
11+
"require": {
12+
"php": "^7.0|^8.0",
13+
"open-telemetry/context": "^1.0"
14+
},
15+
"autoload": {
16+
"psr-4": {
17+
"OpenTelemetry\\Contrib\\Propagation\\TraceResponse\\": "src/"
18+
}
19+
},
20+
"require-dev": {
21+
"friendsofphp/php-cs-fixer": "^3",
22+
"phan/phan": "^5.0",
23+
"phpstan/phpstan": "^1.1",
24+
"phpstan/phpstan-phpunit": "^1.0",
25+
"psalm/plugin-phpunit": "^0.16",
26+
"open-telemetry/sdk": "^1.0",
27+
"phpunit/phpunit": "^9.5",
28+
"vimeo/psalm": "^4.0",
29+
"symfony/http-client": "^5.4|^6.0",
30+
"guzzlehttp/promises": "^1.5",
31+
"php-http/message-factory": "^1.0",
32+
"nyholm/psr7": "^1.5"
33+
},
34+
"config": {
35+
"allow-plugins": {
36+
"php-http/discovery": true
37+
}
38+
}
39+
}

phpstan.neon.dist

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
includes:
2+
- vendor/phpstan/phpstan-phpunit/extension.neon
3+
4+
parameters:
5+
tmpDir: var/cache/phpstan
6+
level: 5
7+
paths:
8+
- src
9+
- tests

phpunit.xml.dist

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
3+
<phpunit
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.5/phpunit.xsd"
6+
backupGlobals="false"
7+
backupStaticAttributes="false"
8+
cacheResult="false"
9+
colors="false"
10+
convertErrorsToExceptions="true"
11+
convertNoticesToExceptions="true"
12+
convertWarningsToExceptions="true"
13+
forceCoversAnnotation="false"
14+
processIsolation="false"
15+
stopOnError="false"
16+
stopOnFailure="false"
17+
stopOnIncomplete="false"
18+
stopOnSkipped="false"
19+
stopOnRisky="false"
20+
timeoutForSmallTests="1"
21+
timeoutForMediumTests="10"
22+
timeoutForLargeTests="60"
23+
verbose="true">
24+
25+
<coverage processUncoveredFiles="true" disableCodeCoverageIgnore="false">
26+
<include>
27+
<directory>src</directory>
28+
</include>
29+
</coverage>
30+
31+
<php>
32+
<ini name="date.timezone" value="UTC" />
33+
<ini name="display_errors" value="On" />
34+
<ini name="display_startup_errors" value="On" />
35+
<ini name="error_reporting" value="E_ALL" />
36+
</php>
37+
38+
<testsuites>
39+
<testsuite name="unit">
40+
<directory>tests/Unit</directory>
41+
</testsuite>
42+
</testsuites>
43+
44+
</phpunit>

psalm.xml.dist

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0"?>
2+
<psalm
3+
errorLevel="3"
4+
cacheDirectory="var/cache/psalm"
5+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
6+
xmlns="https://getpsalm.org/schema/config"
7+
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd">
8+
<projectFiles>
9+
<directory name="src"/>
10+
<directory name="tests"/>
11+
</projectFiles>
12+
<plugins>
13+
<pluginClass class="Psalm\PhpUnitPlugin\Plugin"/>
14+
</plugins>
15+
</psalm>

src/ResponsePropagator.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OpenTelemetry\Contrib\Propagation\TraceResponse;
6+
7+
use OpenTelemetry\Context\ContextInterface;
8+
use OpenTelemetry\Context\Propagation\PropagationSetterInterface;
9+
10+
/**
11+
* This propagator type is used to inject the trace-context into HTTP responses.
12+
*/
13+
interface ResponsePropagator
14+
{
15+
/**
16+
* Injects specific values from the provided {@see ContextInterface} into the provided carrier
17+
* via an {@see PropagationSetterInterface}.
18+
*
19+
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/context/api-propagators.md#textmap-inject
20+
*
21+
* @param mixed $carrier
22+
*/
23+
public function inject(&$carrier, PropagationSetterInterface $setter = null, ContextInterface $context = null): void;
24+
}

src/TraceResponsePropagator.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OpenTelemetry\Contrib\Propagation\TraceResponse;
6+
7+
use OpenTelemetry\API\Trace\Span;
8+
use OpenTelemetry\Context\Context;
9+
use OpenTelemetry\Context\ContextInterface;
10+
use OpenTelemetry\Context\Propagation\ArrayAccessGetterSetter;
11+
use OpenTelemetry\Context\Propagation\PropagationSetterInterface;
12+
13+
/**
14+
* Provides a ResponsePropagator for the Trace Context HTTP Response Headers Format
15+
*
16+
* @see https://w3c.github.io/trace-context/#trace-context-http-response-headers-format
17+
*/
18+
final class TraceResponsePropagator implements ResponsePropagator
19+
{
20+
const IS_SAMPLED = '1';
21+
const NOT_SAMPLED = '0';
22+
const SUPPORTED_VERSION = '00';
23+
const TRACERESPONSE = 'traceresponse';
24+
25+
public function fields(): array
26+
{
27+
return [
28+
self::TRACERESPONSE,
29+
];
30+
}
31+
32+
public function inject(&$carrier, ?PropagationSetterInterface $setter = null, ?ContextInterface $context = null): void
33+
{
34+
$setter = $setter ?? ArrayAccessGetterSetter::getInstance();
35+
$context = $context ?? Context::getCurrent();
36+
$spanContext = Span::fromContext($context)->getContext();
37+
38+
if (!$spanContext->isValid()) {
39+
return;
40+
}
41+
42+
$traceId = $spanContext->getTraceId();
43+
$spanId = $spanContext->getSpanId();
44+
45+
$samplingFlag = $spanContext->isSampled() ? self::IS_SAMPLED : self::NOT_SAMPLED;
46+
47+
$header = self::SUPPORTED_VERSION . '-' . $traceId . '-' . $spanId . '-' . $samplingFlag;
48+
$setter->set($carrier, self::TRACERESPONSE, $header);
49+
}
50+
}

0 commit comments

Comments
 (0)