Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TraceResponse propagator #143

Merged
merged 1 commit into from
Apr 11, 2023
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
1 change: 1 addition & 0 deletions .github/workflows/php.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ jobs:
'Instrumentation/PDO',
'Instrumentation/Symfony',
'Instrumentation/Laravel',
'Propagation/TraceResponse',
'Symfony'
]
exclude:
Expand Down
2 changes: 2 additions & 0 deletions .gitsplit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ splits:
target: "https://${GH_TOKEN}@github.com/opentelemetry-php/context-swoole.git"
- prefix: "src/AutoInstrumentationInstaller"
target: "https://${GH_TOKEN}@github.com/opentelemetry-php/contrib-instrumentation-installer.git"
- prefix: "src/Propagation/TraceResponse"
target: "https://${GH_TOKEN}@github.com/opentelemetry-php/contrib-propagator-traceresponse.git"

# List of references to split (defined as regexp)
origins:
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
"OpenTelemetry\\Contrib\\Symfony\\": "src/Symfony/src",
"OpenTelemetry\\Contrib\\Instrumentation\\Psr15\\": "src/Instrumentation/Psr15/src",
"OpenTelemetry\\Contrib\\Instrumentation\\Slim\\": "src/Instrumentation/Slim/src",
"OpenTelemetry\\Contrib\\Instrumentation\\Wordpress\\": "src/Instrumentation/Wordpress/src"
"OpenTelemetry\\Contrib\\Instrumentation\\Wordpress\\": "src/Instrumentation/Wordpress/src",
"OpenTelemetry\\Contrib\\Propagation\\TraceResponse\\": "src/Propagation/TraceResponse/src"
}
},
"config": {
Expand Down
43 changes: 43 additions & 0 deletions src/Propagation/TraceResponse/.php-cs-fixer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php
$finder = PhpCsFixer\Finder::create()
->exclude('vendor')
->exclude('var/cache')
->in(__DIR__);

$config = new PhpCsFixer\Config();
return $config->setRules([
'concat_space' => ['spacing' => 'one'],
'declare_equal_normalize' => ['space' => 'none'],
'is_null' => true,
'modernize_types_casting' => true,
'ordered_imports' => true,
'php_unit_construct' => true,
'single_line_comment_style' => true,
'yoda_style' => false,
'@PSR2' => true,
'array_syntax' => ['syntax' => 'short'],
'blank_line_after_opening_tag' => true,
'blank_line_before_statement' => true,
'cast_spaces' => true,
'declare_strict_types' => true,
'function_typehint_space' => true,
'include' => true,
'lowercase_cast' => true,
'new_with_braces' => true,
'no_extra_blank_lines' => true,
'no_leading_import_slash' => true,
'echo_tag_syntax' => true,
'no_unused_imports' => true,
'no_useless_else' => true,
'no_useless_return' => true,
'phpdoc_order' => true,
'phpdoc_scalar' => true,
'phpdoc_types' => true,
'short_scalar_cast' => true,
'single_blank_line_before_namespace' => true,
'single_quote' => true,
'trailing_comma_in_multiline' => true,
])
->setRiskyAllowed(true)
->setFinder($finder);

56 changes: 56 additions & 0 deletions src/Propagation/TraceResponse/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# OpenTelemetry TraceResponse Propagator

**Note:** This package is experimental as `traceresponse` is currently an editors' draft.

This package provides a [Trace Context HTTP Response Headers Format](https://w3c.github.io/trace-context/#trace-context-http-response-headers-format)
propagator to inject the current span context into Response datastructures.

The main goal is to allow client-side technology (Real User Monitoring, HTTP Clients) to record
the server side context in order to allow referencing it.

## Requirements

* OpenTelemetry SDK and exporters (required to actually export traces)

Optional:
* OpenTelemetry extension (Some instrumentations can automatically use the `TraceResponsePropagator`)

## Usage

Assuming there is an active `SpanContext`, you can inject it into your response as follows:

```php
// your framework probably provides a datastructure to model HTTP responses
// and allows you to hook into the end of a request / listen to a matching event.
$response = new Response();

// get the current scope, bail out if none
$scope = Context::storage()->scope();
if (null === $scope) {
return;
}

// create a PropagationSetterInterface that knows how to inject response headers
$propagationSetter = new class implements OpenTelemetry\Context\Propagation\PropagationSetterInterface {
public function set(&$carrier, string $key, string $value) : void {
$carrier->headers->set($key, $value);
}
};
$propagator = new TraceResponseProgator();
$propagator->inject($response, $propagationSetter, $scope->context());
```

## Installation via composer

```bash
$ composer require open-telemetry/opentelemetry-propagation-traceresponse
```

## Installing dependencies and executing tests

From TraceResponse subdirectory:

```bash
$ composer install
$ ./vendor/bin/phpunit tests
```
39 changes: 39 additions & 0 deletions src/Propagation/TraceResponse/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "open-telemetry/opentelemetry-propagation-traceresponse",
cedricziel marked this conversation as resolved.
Show resolved Hide resolved
"description": "OpenTelemetry traceresponse propagator.",
"keywords": ["opentelemetry", "otel", "open-telemetry", "propagator", "traceresponse"],
"type": "library",
"homepage": "https://opentelemetry.io/docs/php",
"readme": "./README.md",
"license": "Apache-2.0",
"minimum-stability": "dev",
"prefer-stable": true,
"require": {
"php": "^7.0|^8.0",
"open-telemetry/context": "^1.0"
},
"autoload": {
"psr-4": {
"OpenTelemetry\\Contrib\\Propagation\\TraceResponse\\": "src/"
}
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3",
"phan/phan": "^5.0",
"phpstan/phpstan": "^1.1",
"phpstan/phpstan-phpunit": "^1.0",
"psalm/plugin-phpunit": "^0.16",
"open-telemetry/sdk": "^1.0",
"phpunit/phpunit": "^9.5",
"vimeo/psalm": "^4.0",
"symfony/http-client": "^5.4|^6.0",
"guzzlehttp/promises": "^1.5",
"php-http/message-factory": "^1.0",
"nyholm/psr7": "^1.5"
},
"config": {
"allow-plugins": {
"php-http/discovery": true
}
}
}
9 changes: 9 additions & 0 deletions src/Propagation/TraceResponse/phpstan.neon.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
includes:
- vendor/phpstan/phpstan-phpunit/extension.neon

parameters:
tmpDir: var/cache/phpstan
level: 5
paths:
- src
- tests
44 changes: 44 additions & 0 deletions src/Propagation/TraceResponse/phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>

<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.5/phpunit.xsd"
backupGlobals="false"
backupStaticAttributes="false"
cacheResult="false"
colors="false"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
forceCoversAnnotation="false"
processIsolation="false"
stopOnError="false"
stopOnFailure="false"
stopOnIncomplete="false"
stopOnSkipped="false"
stopOnRisky="false"
timeoutForSmallTests="1"
timeoutForMediumTests="10"
timeoutForLargeTests="60"
verbose="true">

<coverage processUncoveredFiles="true" disableCodeCoverageIgnore="false">
<include>
<directory>src</directory>
</include>
</coverage>

<php>
<ini name="date.timezone" value="UTC" />
<ini name="display_errors" value="On" />
<ini name="display_startup_errors" value="On" />
<ini name="error_reporting" value="E_ALL" />
</php>

<testsuites>
<testsuite name="unit">
<directory>tests/Unit</directory>
</testsuite>
</testsuites>

</phpunit>
15 changes: 15 additions & 0 deletions src/Propagation/TraceResponse/psalm.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0"?>
<psalm
errorLevel="3"
cacheDirectory="var/cache/psalm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd">
<projectFiles>
<directory name="src"/>
<directory name="tests"/>
</projectFiles>
<plugins>
<pluginClass class="Psalm\PhpUnitPlugin\Plugin"/>
</plugins>
</psalm>
24 changes: 24 additions & 0 deletions src/Propagation/TraceResponse/src/ResponsePropagator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace OpenTelemetry\Contrib\Propagation\TraceResponse;

use OpenTelemetry\Context\ContextInterface;
use OpenTelemetry\Context\Propagation\PropagationSetterInterface;

/**
* This propagator type is used to inject the trace-context into HTTP responses.
*/
interface ResponsePropagator
{
/**
* Injects specific values from the provided {@see ContextInterface} into the provided carrier
* via an {@see PropagationSetterInterface}.
*
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/context/api-propagators.md#textmap-inject
*
* @param mixed $carrier
*/
public function inject(&$carrier, PropagationSetterInterface $setter = null, ContextInterface $context = null): void;
}
50 changes: 50 additions & 0 deletions src/Propagation/TraceResponse/src/TraceResponsePropagator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

declare(strict_types=1);

namespace OpenTelemetry\Contrib\Propagation\TraceResponse;

use OpenTelemetry\API\Trace\Span;
use OpenTelemetry\Context\Context;
use OpenTelemetry\Context\ContextInterface;
use OpenTelemetry\Context\Propagation\ArrayAccessGetterSetter;
use OpenTelemetry\Context\Propagation\PropagationSetterInterface;

/**
* Provides a ResponsePropagator for the Trace Context HTTP Response Headers Format
*
* @see https://w3c.github.io/trace-context/#trace-context-http-response-headers-format
*/
final class TraceResponsePropagator implements ResponsePropagator
{
const IS_SAMPLED = '1';
const NOT_SAMPLED = '0';
const SUPPORTED_VERSION = '00';
const TRACERESPONSE = 'traceresponse';

public function fields(): array
{
return [
self::TRACERESPONSE,
];
}

public function inject(&$carrier, ?PropagationSetterInterface $setter = null, ?ContextInterface $context = null): void
{
$setter = $setter ?? ArrayAccessGetterSetter::getInstance();
$context = $context ?? Context::getCurrent();
$spanContext = Span::fromContext($context)->getContext();

if (!$spanContext->isValid()) {
return;
}

$traceId = $spanContext->getTraceId();
$spanId = $spanContext->getSpanId();

$samplingFlag = $spanContext->isSampled() ? self::IS_SAMPLED : self::NOT_SAMPLED;

$header = self::SUPPORTED_VERSION . '-' . $traceId . '-' . $spanId . '-' . $samplingFlag;
$setter->set($carrier, self::TRACERESPONSE, $header);
}
}
Loading