diff --git a/CHANGELOG.md b/CHANGELOG.md index 16a932afb1..221072e941 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -156,3 +156,5 @@ significant modifications will be credited to OpenTelemetry Authors. ([#617](https://github.com/open-telemetry/opentelemetry-demo/pull/617)) * Use `frontend-web` as service name for browser/web requests ([#628](https://github.com/open-telemetry/opentelemetry-demo/pull/628)) +* Update `quoteservice` to use opentelemetry-php beta release +([#644](https://github.com/open-telemetry/opentelemetry-demo/pull/644)) diff --git a/docker-compose.yml b/docker-compose.yml index f870a5b895..2dc178135d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -435,14 +435,10 @@ services: ports: - "${QUOTE_SERVICE_PORT}" environment: - # OTEL_EXPORTER_OTLP_TRACES_ENDPOINT # Not working for PHP + - OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://otelcol:4318/v1/traces + - OTEL_PHP_AUTOLOAD_ENABLED=true - QUOTE_SERVICE_PORT - OTEL_SERVICE_NAME=quoteservice - - OTEL_EXPORTER_OTLP_ENDPOINT=http://otelcol:4318 - - OTEL_TRACES_SAMPLER=parentbased_always_on - - OTEL_TRACES_EXPORTER=otlp - - OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=http/protobuf - - OTEL_PHP_TRACES_PROCESSOR=simple depends_on: - otelcol logging: *logging diff --git a/docs/services/quoteservice.md b/docs/services/quoteservice.md index 213cd9781a..d4b32fa5d6 100644 --- a/docs/services/quoteservice.md +++ b/docs/services/quoteservice.md @@ -15,64 +15,44 @@ The PHP instrumentation may vary when using a different framework. ### Initializing Tracing -The OpenTelemetry SDK is initialized from `index`. +In this demo, the OpenTelemetry SDK has been automatically created as part +of SDK autoloading, which happens as part of composer autoloading. -```php - $tracerProvider = (new TracerProviderFactory('quoteservice'))->create(); - ShutdownHandler::register([$tracerProvider, 'shutdown']); - $tracer = $tracerProvider->getTracer('io.opentelemetry.contrib.php'); +This is enabled by setting the environment variable `OTEL_PHP_AUTOLOAD_ENABLED=true`. - $containerBuilder->addDefinitions([ - Tracer::class => $tracer - ]); +```php + require __DIR__ . '/../vendor/autoload.php'; ``` -You should call `$tracerProvider->shutdown()` when your service is shutdown to -ensure all spans are exported. +There are multiple ways to create or obtain a `Tracer`, in this example we +obtain one from the global tracer provider which was initialized above, as +part of SDK autoloading: -### Adding HTTP instrumentation +```php + $tracer = Globals::tracerProvider()->getTracer('manual-instrumentation'); +``` -This service receives HTTP requests, which are instrumented in the middleware. +### Manually creating spans -The middleware starts root span based on route pattern, sets span status -from http code. +Creating a span manually can be done via a `Tracer`. The span will be default +be a child of the active span in the current execution context: ```php - $app->add(function (Request $request, RequestHandler $handler) use ($tracer) { - $parent = TraceContextPropagator::getInstance()->extract($request->getHeaders()); - $routeContext = RouteContext::fromRequest($request); - $route = $routeContext->getRoute(); - $root = $tracer->spanBuilder($route->getPattern()) - ->setStartTimestamp((int) ($request->getServerParams()['REQUEST_TIME_FLOAT'] * 1e9)) - ->setParent($parent) - ->setSpanKind(SpanKind::KIND_SERVER) - ->startSpan(); - $scope = $root->activate(); - - try { - $response = $handler->handle($request); - $root->setStatus($response->getStatusCode() < 500 ? StatusCode::STATUS_OK : StatusCode::STATUS_ERROR); - } finally { - $root->end(); - $scope->detach(); - } - - return $response; - }); + $span = Globals::tracerProvider() + ->getTracer('manual-instrumentation') + ->spanBuilder('calculate-quote') + ->setSpanKind(SpanKind::KIND_INTERNAL) + ->startSpan(); + /* calculate quote */ + $span->end(); ``` -This is enough to get a new span every time a new request is received by the service. - -Note that the `root` span is created with `setParent($parent)` which is coming from -the request headers. This is required to ensure Context Propagation. - ### Add span attributes -Within the definition of routes, you can get current span using -`OpenTelemetry\API\Trace\AbstractSpan`. +You can obtain the current span using `OpenTelemetry\API\Trace\Span`. ```php - $span = AbstractSpan::getCurrent(); + $span = Span::getCurrent(); ``` Adding attributes to a span is accomplished using `setAttribute` on the span diff --git a/src/quoteservice/Dockerfile b/src/quoteservice/Dockerfile index 780dd7a92e..5606f176b2 100644 --- a/src/quoteservice/Dockerfile +++ b/src/quoteservice/Dockerfile @@ -11,9 +11,14 @@ RUN composer install \ --no-dev \ --prefer-dist -FROM php:8.1-apache +FROM php:8.2-apache -RUN docker-php-ext-install opcache +ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/ +RUN chmod +x /usr/local/bin/install-php-extensions \ + && install-php-extensions \ + opcache \ + protobuf \ + open-telemetry/opentelemetry-php-instrumentation@1.0.0beta1 WORKDIR /var/www COPY --from=build /tmp/vendor/ ./vendor/ diff --git a/src/quoteservice/README.md b/src/quoteservice/README.md index a94d7a97df..7e555e69c1 100644 --- a/src/quoteservice/README.md +++ b/src/quoteservice/README.md @@ -3,7 +3,7 @@ The Quote Service calculates the shipping costs, based on the number of items to be shipped. -It is a PHP based service. +It is a PHP based service, using a combination of automatic and manual instrumentation. ## Docker Build diff --git a/src/quoteservice/app/routes.php b/src/quoteservice/app/routes.php index e6e86025ee..aafad789cf 100644 --- a/src/quoteservice/app/routes.php +++ b/src/quoteservice/app/routes.php @@ -1,25 +1,28 @@ getTracer('manual-instrumentation') ->spanBuilder('calculate-quote') ->setSpanKind(SpanKind::KIND_INTERNAL) ->startSpan(); $childSpan->addEvent('Calculating quote'); try { + if (!array_key_exists('numberOfItems', $jsonObject)) { + throw new \InvalidArgumentException('numberOfItems not provided'); + } $numberOfItems = intval($jsonObject['numberOfItems']); - $quote = 8.90 * $numberOfItems; + $quote = round(8.90 * $numberOfItems, 2); $childSpan->setAttribute('app.quote.items.count', $numberOfItems); $childSpan->setAttribute('app.quote.cost.total', $quote); @@ -34,14 +37,14 @@ function calculateQuote($jsonObject, Tracer $tracer): float } return function (App $app) { - $app->post('/getquote', function (Request $request, Response $response, Tracer $tracer) { - $span = AbstractSpan::getCurrent(); + $app->post('/getquote', function (Request $request, Response $response) { + $span = Span::getCurrent(); $span->addEvent('Received get quote request, processing it'); $body = $request->getBody()->getContents(); $jsonObject = json_decode($body, true); - $data = calculateQuote($jsonObject, $tracer); + $data = calculateQuote($jsonObject); $payload = json_encode($data); $response->getBody()->write($payload); diff --git a/src/quoteservice/composer.json b/src/quoteservice/composer.json index dadb58b69e..182fd91c73 100644 --- a/src/quoteservice/composer.json +++ b/src/quoteservice/composer.json @@ -2,11 +2,15 @@ "name": "openteletry-demo/quoteservice", "description": "Quote Service part of OpenTelemetry Demo", "license": "Apache-2.0", + "minimum-stability": "beta", "require": { - "php": "7.4 || 8.1", - "ext-json": "dev-main", + "php": ">= 8.2", + "ext-json": "*", "monolog/monolog": "2.8.0", - "open-telemetry/opentelemetry": "0.0.15", + "open-telemetry/sdk": "1.0.0beta1", + "open-telemetry/exporter-otlp": "1.0.0beta1", + "open-telemetry/opentelemetry-auto-slim": "1.0.0beta3", + "open-telemetry/opentelemetry-auto-psr15": "1.0.0beta2", "guzzlehttp/guzzle": "7.4.5", "php-di/php-di": "6.4.0", "php-di/slim-bridge": "3.2.0", @@ -19,10 +23,6 @@ "App\\": "src/" } }, - "scripts": { - "start": "php -S 0.0.0.0:${QUOTE_SERVICE_PORT} -t public", - "test": "phpunit" - }, "config": { "allow-plugins": { "phpstan/extension-installer": true diff --git a/src/quoteservice/public/index.php b/src/quoteservice/public/index.php index ff13e771bf..3a3e98f17b 100644 --- a/src/quoteservice/public/index.php +++ b/src/quoteservice/public/index.php @@ -17,17 +17,7 @@ use DI\Bridge\Slim\Bridge; use DI\ContainerBuilder; -use OpenTelemetry\API\Trace\Propagation\TraceContextPropagator; -use OpenTelemetry\API\Trace\SpanKind; -use OpenTelemetry\API\Trace\StatusCode; -use OpenTelemetry\SDK\Trace\Tracer; -use OpenTelemetry\SDK\Trace\TracerProviderFactory; -use OpenTelemetry\SDK\Common\Util\ShutdownHandler; -use Psr\Http\Message\ServerRequestInterface as Request; -use Psr\Http\Server\RequestHandlerInterface as RequestHandler; use Slim\Factory\AppFactory; -use Slim\Factory\ServerRequestCreatorFactory; -use Slim\Routing\RouteContext; require __DIR__ . '/../vendor/autoload.php'; @@ -42,15 +32,6 @@ $dependencies = require __DIR__ . '/../app/dependencies.php'; $dependencies($containerBuilder); -// Add OTel -$tracerProvider = (new TracerProviderFactory('quoteservice'))->create(); -ShutdownHandler::register([$tracerProvider, 'shutdown']); -$tracer = $tracerProvider->getTracer('io.opentelemetry.contrib.php'); - -$containerBuilder->addDefinitions([ - Tracer::class => $tracer -]); - // Build PHP-DI Container instance $container = $containerBuilder->build(); @@ -59,38 +40,12 @@ $app = Bridge::create($container); // Register middleware -//middleware starts root span based on route pattern, sets status from http code -$app->add(function (Request $request, RequestHandler $handler) use ($tracer) { - $parent = TraceContextPropagator::getInstance()->extract($request->getHeaders()); - $routeContext = RouteContext::fromRequest($request); - $route = $routeContext->getRoute(); - $root = $tracer->spanBuilder($route->getPattern()) - ->setStartTimestamp((int) ($request->getServerParams()['REQUEST_TIME_FLOAT'] * 1e9)) - ->setParent($parent) - ->setSpanKind(SpanKind::KIND_SERVER) - ->startSpan(); - $scope = $root->activate(); - - try { - $response = $handler->handle($request); - $root->setStatus($response->getStatusCode() < 500 ? StatusCode::STATUS_OK : StatusCode::STATUS_ERROR); - } finally { - $root->end(); - $scope->detach(); - } - - return $response; -}); $app->addRoutingMiddleware(); // Register routes $routes = require __DIR__ . '/../app/routes.php'; $routes($app); -// Create Request object from globals -$serverRequestCreator = ServerRequestCreatorFactory::create(); -$request = $serverRequestCreator->createServerRequestFromGlobals(); - // Add Body Parsing Middleware $app->addBodyParsingMiddleware(); @@ -99,4 +54,3 @@ // Run App $app->run(); -$tracerProvider->shutdown();