Skip to content

Commit

Permalink
Transition W3C Trace Context Test Service to Vanilla PHP (#695)
Browse files Browse the repository at this point in the history
* test: Transition W3C trace-context test to vanilla PHP

* chore: Rename trace context test script

* chore: Improve symfony-cli setup

* chore: Cleanup

* fix: Add executable perm to trace ctx test setup
  • Loading branch information
yuktea authored Jun 24, 2022
1 parent 0e4ad52 commit 5c3109a
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 160 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ style:
deptrac:
$(DC_RUN_PHP) env XDEBUG_MODE=off vendor/bin/deptrac --formatter=table --report-uncovered --no-cache
w3c-test-service:
@docker-compose -f docker-compose.w3cTraceContext.yaml run --rm php ./tests/TraceContext/W3CTestService/symfony-setup
@docker-compose -f docker-compose.w3cTraceContext.yaml run --rm php ./tests/TraceContext/W3CTestService/trace-context-test.sh
semconv:
./script/semantic-conventions/semconv.sh
split:
Expand Down
1 change: 0 additions & 1 deletion docker-compose.w3cTraceContext.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,3 @@ services:
environment:
XDEBUG_MODE: ${XDEBUG_MODE:-off}
XDEBUG_CONFIG: ${XDEBUG_CONFIG:-''}

76 changes: 0 additions & 76 deletions tests/TraceContext/W3CTestService/TestController.php

This file was deleted.

109 changes: 77 additions & 32 deletions tests/TraceContext/W3CTestService/index.php
Original file line number Diff line number Diff line change
@@ -1,40 +1,85 @@
<?php

declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
require __DIR__ . '/../../../vendor/autoload.php';
require __DIR__ . '/trace-context-handler.php';

use App\Kernel;
use Nyholm\Psr7\Request;
use Nyholm\Psr7\Response;
use OpenTelemetry\Contrib\Jaeger\Exporter as JaegerExporter;
use OpenTelemetry\SDK\Trace\SpanProcessor\BatchSpanProcessor;
use OpenTelemetry\SDK\Trace\TracerProvider;
use Symfony\Component\Dotenv\Dotenv;
use Psr\Http\Client\ClientExceptionInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Symfony\Component\HttpClient\Psr18Client;
use Symfony\Component\HttpFoundation\Request;

(new Dotenv())->bootEnv(dirname(__DIR__) . '/.env');

$httpClient = new Psr18Client();

$tracer = (new TracerProvider([
new BatchSpanProcessor(
new JaegerExporter(
'W3C Trace-Context Test Service',
'http://localhost:9412/api/v2/spans',
$httpClient,
$httpClient,
$httpClient,
)
),
]))->getTracer('W3C Trace-Context Test Service');

$request = Request::createFromGlobals();
$span = $tracer->spanBuilder($request->getUri())->startSpan();
$spanScope = $span->activate();

$kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);

$span->end();
$spanScope->detach();

main();

function main(): void
{
$httpClient = new Psr18Client();
$request = parseRequestFromGlobals();
$tracer = (new TracerProvider(
[
new BatchSpanProcessor(
new JaegerExporter(
'W3C Trace-Context Test Service',
'http://localhost:9412/api/v2/spans',
$httpClient,
$httpClient,
$httpClient,
),
),
],
))->getTracer('W3C Trace-Context Test Service');

try {
$response = handleTraceContext($request, $tracer, $httpClient);
} catch (ClientExceptionInterface $e) {
$response = new Response(500, [], $e->getMessage());
}

sendResponse($response);
}

function parseRequestFromGlobals(): RequestInterface
{
// Method
$method = $_SERVER['REQUEST_METHOD'];

// URI
$uri = $_SERVER['REQUEST_URI'];

// Build headers
$headers = [];
foreach ($_SERVER as $key => $value) {
if (strpos($key, 'HTTP_') === 0) {
$headers[substr($key, 5)] = $value;
}
}

$body = file_get_contents('php://input');

return new Request($method, $uri, $headers, $body);
}

/**
* @param ResponseInterface $response
* @return void
*/
function sendResponse(ResponseInterface $response)
{
// Status line
header(sprintf('HTTP/%s %d %s', $response->getProtocolVersion(), $response->getStatusCode(), $response->getReasonPhrase()));

// Headers
foreach ($response->getHeaders() as $name => $values) {
foreach ($values as $value) {
header(sprintf('%s: %s', $name, $value), false);
}
}

// Response body
echo $response->getBody();
}
50 changes: 0 additions & 50 deletions tests/TraceContext/W3CTestService/symfony-setup

This file was deleted.

67 changes: 67 additions & 0 deletions tests/TraceContext/W3CTestService/trace-context-handler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

declare(strict_types=1);

use Nyholm\Psr7\Request;
use Nyholm\Psr7\Response;
use OpenTelemetry\API\Trace\Propagation\TraceContextPropagator;
use OpenTelemetry\API\Trace\TracerInterface;
use OpenTelemetry\Context\Context;
use OpenTelemetry\Context\Propagation\ArrayAccessGetterSetter;
use OpenTelemetry\Context\Propagation\SanitizeCombinedHeadersPropagationGetter;
use Psr\Http\Client\ClientExceptionInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Symfony\Component\HttpClient\Psr18Client;

/**
* @param RequestInterface $serviceRequest
* @param TracerInterface $tracer
* @param Psr18Client $httpClient
* @throws ClientExceptionInterface
* @return ResponseInterface
*/
function handleTraceContext(RequestInterface $serviceRequest, TracerInterface $tracer, Psr18Client $httpClient): ResponseInterface
{
if ($serviceRequest->getMethod() !== 'POST') {
return new Response(400, [], 'Only POST requests are allowed');
}

$traceCtxPropagator = TraceContextPropagator::getInstance();
$propagationGetter = new SanitizeCombinedHeadersPropagationGetter(new ArrayAccessGetterSetter());

try {
$context = $traceCtxPropagator->extract($serviceRequest->getHeaders(), $propagationGetter);
} catch (InvalidArgumentException $th) {
$context = Context::getCurrent();
}

$body = json_decode((string) $serviceRequest->getBody(), true);
if (! is_array($body)) {
return new Response(400, [], 'Invalid JSON');
}

foreach ($body as $case) {
$headers = ['content-type' => 'application/json'];
$url = $case['url'];
$arguments = $case['arguments'];

$span = $tracer->spanBuilder($url)->setParent($context)->startSpan();
$context = $span->storeInContext($context);
$scope = $context->activate();

$traceCtxPropagator->inject($headers, null, $context);

$serviceRequest = new Request('POST', $url, $headers, json_encode($arguments));
$httpClient->sendRequest($serviceRequest);

$span->end();
$scope->detach();
}

return new Response(
200,
['content-type' => 'text/html'],
'Subsequent calls from the service have been dispatched',
);
}
25 changes: 25 additions & 0 deletions tests/TraceContext/W3CTestService/trace-context-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env bash
set -x

function install_symfony() {
curl -1sLf 'https://dl.cloudsmith.io/public/symfony/stable/setup.alpine.sh' | bash >/dev/null
apk add symfony-cli
}

cd "tests/TraceContext/W3CTestService" || { echo "error: could not cd into the W3CTestService directory."; exit 1; }

# Install Symfony: we will use the Symfony server as the built-in PHP server doesn't play well with duplicate headers
install_symfony

# Start the test service in the background
symfony server:start -d --port=8001 --no-tls

# Setup dependencies for the trace-context test
apk add --no-cache py3-pip py3-aiohttp

# Fetch the latest trace-context tests
rm -rf trace-context
git clone https://github.com/w3c/trace-context.git

# Run the test
python3 "trace-context/test/test.py" http://127.0.0.1:8001/test

0 comments on commit 5c3109a

Please sign in to comment.