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

update quoteservice to opentelemetry-php beta #644

Merged
merged 7 commits into from
Dec 21, 2022
Merged
Show file tree
Hide file tree
Changes from 4 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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,5 @@ significant modifications will be credited to OpenTelemetry Authors.
([#617](https:/open-telemetry/opentelemetry-demo/pull/617))
* Use `frontend-web` as service name for browser/web requests
([#628](https:/open-telemetry/opentelemetry-demo/pull/628))
* Update `quoteservice` to use opentelemetry-php beta release
([#644](https:/open-telemetry/opentelemetry-demo/pull/644))
8 changes: 2 additions & 6 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
66 changes: 23 additions & 43 deletions docs/services/quoteservice.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 7 additions & 2 deletions src/quoteservice/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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:/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/[email protected]

WORKDIR /var/www
COPY --from=build /tmp/vendor/ ./vendor/
Expand Down
2 changes: 1 addition & 1 deletion src/quoteservice/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
19 changes: 11 additions & 8 deletions src/quoteservice/app/routes.php
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
<?php
declare(strict_types=1);

use OpenTelemetry\API\Trace\AbstractSpan;
use OpenTelemetry\API\Common\Instrumentation\Globals;
use OpenTelemetry\API\Trace\Span;
use OpenTelemetry\API\Trace\SpanKind;
use OpenTelemetry\SDK\Trace\Tracer;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\App;

function calculateQuote($jsonObject, Tracer $tracer): float
function calculateQuote($jsonObject): float
{
$quote = 0.0;
$childSpan = $tracer
$childSpan = Globals::tracerProvider()->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);
Expand All @@ -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);
Expand Down
14 changes: 7 additions & 7 deletions src/quoteservice/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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
Expand Down
46 changes: 0 additions & 46 deletions src/quoteservice/public/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -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();

Expand All @@ -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();

Expand All @@ -99,4 +54,3 @@

// Run App
$app->run();
$tracerProvider->shutdown();