From c9977a3df49dca541b282b265c2ede85a86ff1a6 Mon Sep 17 00:00:00 2001 From: Juliano Costa Date: Mon, 29 Aug 2022 08:48:33 +0200 Subject: [PATCH 01/14] Add PHP quote service --- .env | 3 + .gitignore | 3 +- docker-compose.yml | 23 +++ src/quoteservice/.dockerignore | 4 + src/quoteservice/.gitignore | 7 + src/quoteservice/.htaccess | 19 +++ src/quoteservice/Dockerfile | 26 ++++ src/quoteservice/app/dependencies.php | 29 ++++ src/quoteservice/app/routes.php | 27 ++++ src/quoteservice/app/settings.php | 25 ++++ src/quoteservice/composer.json | 33 +++++ src/quoteservice/public/.htaccess | 34 +++++ src/quoteservice/public/index.php | 138 ++++++++++++++++++ .../src/Application/Settings/Settings.php | 22 +++ .../Settings/SettingsInterface.php | 13 ++ 15 files changed, 405 insertions(+), 1 deletion(-) create mode 100644 src/quoteservice/.dockerignore create mode 100644 src/quoteservice/.gitignore create mode 100644 src/quoteservice/.htaccess create mode 100644 src/quoteservice/Dockerfile create mode 100644 src/quoteservice/app/dependencies.php create mode 100644 src/quoteservice/app/routes.php create mode 100644 src/quoteservice/app/settings.php create mode 100644 src/quoteservice/composer.json create mode 100644 src/quoteservice/public/.htaccess create mode 100644 src/quoteservice/public/index.php create mode 100644 src/quoteservice/src/Application/Settings/Settings.php create mode 100644 src/quoteservice/src/Application/Settings/SettingsInterface.php diff --git a/.env b/.env index 4812abeaa5..ac611dba78 100644 --- a/.env +++ b/.env @@ -37,6 +37,9 @@ PAYMENT_SERVICE_ADDR=paymentservice:${PAYMENT_SERVICE_PORT} PRODUCT_CATALOG_SERVICE_PORT=3550 PRODUCT_CATALOG_SERVICE_ADDR=productcatalogservice:${PRODUCT_CATALOG_SERVICE_PORT} +QUOTE_SERVICE_PORT=8090 +QUOTE_SERVICE_ADDR=quoteservice:${QUOTE_SERVICE_PORT} + RECOMMENDATION_SERVICE_PORT=9001 RECOMMENDATION_SERVICE_ADDR=recommendationservice:${RECOMMENDATION_SERVICE_PORT} diff --git a/.gitignore b/.gitignore index 43b7af7dde..593dec9622 100644 --- a/.gitignore +++ b/.gitignore @@ -31,4 +31,5 @@ build src/frontend/protos next-env.d.ts src/frontend/cypress/videos -src/frontend/cypress/screenshots \ No newline at end of file +src/frontend/cypress/screenshots +vendor/ diff --git a/docker-compose.yml b/docker-compose.yml index d05e92cb03..69fe617ebd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -262,6 +262,28 @@ services: - otelcol logging: *logging + quoteservice: + image: ${IMAGE_NAME}:${IMAGE_VERSION}-quoteservice + container_name: quoteservice + build: + context: ./ + dockerfile: ./src/quoteservice/Dockerfile + ports: + # remove localhost port b4 merging + - "${QUOTE_SERVICE_PORT}:${QUOTE_SERVICE_PORT}" + environment: + #OTEL_EXPORTER_OTLP_TRACES_ENDPOINT # Not working for PHP + - QUOTE_SERVICE_PORT + - OTEL_SERVICE_NAME=quoteservice + - OTEL_EXPORTER_OTLP_ENDPOINT=otelcol:4317 + - OTEL_TRACES_SAMPLER=parentbased_always_on + - OTEL_TRACES_EXPORTER=otlp + - OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=grpc + - OTEL_PHP_TRACES_PROCESSOR=simple + depends_on: + - otelcol + logging: *logging + # RecommendationService recommendationservice: image: ${IMAGE_NAME}:${IMAGE_VERSION}-recommendationservice @@ -293,6 +315,7 @@ services: - "${SHIPPING_SERVICE_PORT}" environment: - SHIPPING_SERVICE_PORT + - QUOTE_SERVICE_ADDR - OTEL_EXPORTER_OTLP_TRACES_ENDPOINT - OTEL_SERVICE_NAME=shippingservice depends_on: diff --git a/src/quoteservice/.dockerignore b/src/quoteservice/.dockerignore new file mode 100644 index 0000000000..6a2aedc09f --- /dev/null +++ b/src/quoteservice/.dockerignore @@ -0,0 +1,4 @@ +.dockerignore +.idea +Dockerfile +vendor diff --git a/src/quoteservice/.gitignore b/src/quoteservice/.gitignore new file mode 100644 index 0000000000..63066a6e3f --- /dev/null +++ b/src/quoteservice/.gitignore @@ -0,0 +1,7 @@ +.idea/ +.vscode/ +/coverage/ +/vendor/ +/logs/* +!/logs/README.md +.phpunit.result.cache diff --git a/src/quoteservice/.htaccess b/src/quoteservice/.htaccess new file mode 100644 index 0000000000..c7552bf4d6 --- /dev/null +++ b/src/quoteservice/.htaccess @@ -0,0 +1,19 @@ +Options All -Indexes + + +order allow,deny +deny from all + + + + # Redirect to the public folder + RewriteEngine On + # RewriteBase / + RewriteRule ^$ public/ [L] + RewriteRule (.*) public/$1 [L] + + # Redirect to HTTPS + # RewriteEngine On + # RewriteCond %{HTTPS} off + # RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] + diff --git a/src/quoteservice/Dockerfile b/src/quoteservice/Dockerfile new file mode 100644 index 0000000000..1d418e3241 --- /dev/null +++ b/src/quoteservice/Dockerfile @@ -0,0 +1,26 @@ +FROM composer:2.4.1 AS build + +WORKDIR /tmp/ +COPY ./src/quoteservice/composer.json . + +RUN composer install \ + --ignore-platform-reqs \ + --no-interaction \ + --no-plugins \ + --no-scripts \ + --prefer-dist + +FROM php:8.1-apache-buster + +# install GRPC (required for the OTel exporter) +RUN apt-get -y update && apt install -y --no-install-recommends zlib1g-dev && \ + pecl install grpc && \ + docker-php-ext-enable grpc + +WORKDIR /var/www +COPY --from=build /tmp/vendor/ /var/www/vendor/ +COPY ./src/quoteservice/ /var/www + +EXPOSE 8090 + +ENTRYPOINT ["php", "-S", "0.0.0.0:8090", "-t", "public"] diff --git a/src/quoteservice/app/dependencies.php b/src/quoteservice/app/dependencies.php new file mode 100644 index 0000000000..9a948b5515 --- /dev/null +++ b/src/quoteservice/app/dependencies.php @@ -0,0 +1,29 @@ +addDefinitions([ + LoggerInterface::class => function (ContainerInterface $c) { + $settings = $c->get(SettingsInterface::class); + + $loggerSettings = $settings->get('logger'); + $logger = new Logger($loggerSettings['name']); + + $processor = new UidProcessor(); + $logger->pushProcessor($processor); + + $handler = new StreamHandler($loggerSettings['path'], $loggerSettings['level']); + $logger->pushHandler($handler); + + return $logger; + }, + ]); +}; diff --git a/src/quoteservice/app/routes.php b/src/quoteservice/app/routes.php new file mode 100644 index 0000000000..01db23ffaf --- /dev/null +++ b/src/quoteservice/app/routes.php @@ -0,0 +1,27 @@ +get('/getquote', function (Request $request, Response $response) { + $span = AbstractSpan::getCurrent(); + + # do the math here + $data = ['quote' => 32.50]; + + $span->addEvent('Received get quote request, processing it.'); + $span->setAttribute('app.quote.cost.total', $data['quote']); + + $payload = json_encode($data); + $response->getBody()->write($payload); + + $span->addEvent('Quote processed, response sent back'); + + return $response + ->withHeader('Content-Type', 'application/json'); + }); +}; diff --git a/src/quoteservice/app/settings.php b/src/quoteservice/app/settings.php new file mode 100644 index 0000000000..f1963d4127 --- /dev/null +++ b/src/quoteservice/app/settings.php @@ -0,0 +1,25 @@ +addDefinitions([ + SettingsInterface::class => function () { + return new Settings([ + 'displayErrorDetails' => true, // Should be set to false in production + 'logError' => false, + 'logErrorDetails' => false, + 'logger' => [ + 'name' => 'slim-app', + 'path' => 'php://stdout', + 'level' => Logger::DEBUG, + ], + ]); + } + ]); +}; diff --git a/src/quoteservice/composer.json b/src/quoteservice/composer.json new file mode 100644 index 0000000000..0d722d6825 --- /dev/null +++ b/src/quoteservice/composer.json @@ -0,0 +1,33 @@ +{ + "name": "openteletry-demo/quoteservice", + "description": "Quote Service part of OpenTelemetry Demo", + "license": "Apache-2.0", + "require": { + "php": "^7.4 || ^8.1", + "ext-json": "*", + "monolog/monolog": "^2.3", + "open-telemetry/opentelemetry": "dev-main", + "guzzlehttp/guzzle": "*", + "php-di/php-di": "^6.3", + "php-di/slim-bridge": "^3.2", + "php-http/guzzle7-adapter": "*", + "slim/psr7": "^1.5", + "slim/slim": "^4.9" + }, + "config": { + "process-timeout": 0, + "sort-packages": true, + "allow-plugins": { + "phpstan/extension-installer": true + } + }, + "autoload": { + "psr-4": { + "App\\": "src/" + } + }, + "scripts": { + "start": "php -S localhost:8080 -t public", + "test": "phpunit" + } +} diff --git a/src/quoteservice/public/.htaccess b/src/quoteservice/public/.htaccess new file mode 100644 index 0000000000..fe74ec5b20 --- /dev/null +++ b/src/quoteservice/public/.htaccess @@ -0,0 +1,34 @@ +Options All -Indexes + + +order allow,deny +deny from all + + + + RewriteEngine On + + # Redirect to HTTPS + # RewriteEngine On + # RewriteCond %{HTTPS} off + # RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] + + # Some hosts may require you to use the `RewriteBase` directive. + # Determine the RewriteBase automatically and set it as environment variable. + # If you are using Apache aliases to do mass virtual hosting or installed the + # project in a subdirectory, the base path will be prepended to allow proper + # resolution of the index.php file and to redirect to the correct URI. It will + # work in environments without path prefix as well, providing a safe, one-size + # fits all solution. But as you do not need it in this case, you can comment + # the following 2 lines to eliminate the overhead. + RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$ + RewriteRule ^(.*) - [E=BASE:%1] + + # If the above doesn't work you might need to set the `RewriteBase` directive manually, it should be the + # absolute physical path to the directory that contains this htaccess file. + # RewriteBase / + + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [QSA,L] + diff --git a/src/quoteservice/public/index.php b/src/quoteservice/public/index.php new file mode 100644 index 0000000000..6c9226ef74 --- /dev/null +++ b/src/quoteservice/public/index.php @@ -0,0 +1,138 @@ +create(); +ShutdownHandler::register([$tracerProvider, 'shutdown']); +$tracer = $tracerProvider->getTracer('io.opentelemetry.contrib.php'); + +$containerBuilder->addDefinitions([ + Tracer::class => $tracer, + Client::class => function () use ($tracer) { + $stack = HandlerStack::create(); + //a guzzle middleware to wrap http calls in a span, and inject trace headers + $stack->push(function (callable $handler) use ($tracer) { + return function (RequestInterface $request, array $options) use ($handler, $tracer): PromiseInterface { + $span = $tracer + ->spanBuilder(sprintf('%s %s', $request->getMethod(), $request->getUri())) + ->setSpanKind(SpanKind::KIND_CLIENT) + ->setAttribute('http.method', $request->getMethod()) + ->setAttribute('http.url', $request->getUri()) + ->startSpan(); + + $ctx = $span->storeInContext(Context::getCurrent()); + $carrier = []; + TraceContextPropagator::getInstance()->inject($carrier, null, $ctx); + //inject traceparent and tracestate headers + foreach ($carrier as $name => $value) { + $request = $request->withAddedHeader($name, $value); + } + + $promise = $handler($request, $options); + $promise->then(function (Response $response) use ($span) { + $span->setAttribute('http.status_code', $response->getStatusCode()) + ->setAttribute('http.response_content_length', $response->getHeaderLine('Content-Length') ?: $response->getBody()->getSize()) + ->setStatus($response->getStatusCode() < 500 ? StatusCode::STATUS_OK : StatusCode::STATUS_ERROR) + ->end(); + + return $response; + }, function (\Throwable $t) use ($span) { + $span->recordException($t)->setStatus(StatusCode::STATUS_ERROR)->end(); + + throw $t; + }); + + return $promise; + }; + }); + + return new Client(['handler' => $stack, 'http_errors' => false]); + }, +]); + +// Build PHP-DI Container instance +$container = $containerBuilder->build(); + +// Instantiate the app +AppFactory::setContainer($container); +$app = Bridge::create($container); +$callableResolver = $app->getCallableResolver(); + +// 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(); + +// Create Error Handler +$responseFactory = $app->getResponseFactory(); + +// Add Body Parsing Middleware +$app->addBodyParsingMiddleware(); + +// Add Error Middleware +$errorMiddleware = $app->addErrorMiddleware(true, true, true); + +// Run App +$app->run(); +$tracerProvider->shutdown(); diff --git a/src/quoteservice/src/Application/Settings/Settings.php b/src/quoteservice/src/Application/Settings/Settings.php new file mode 100644 index 0000000000..d0efaffdf4 --- /dev/null +++ b/src/quoteservice/src/Application/Settings/Settings.php @@ -0,0 +1,22 @@ +settings = $settings; + } + + /** + * @return mixed + */ + public function get(string $key = '') + { + return (empty($key)) ? $this->settings : $this->settings[$key]; + } +} diff --git a/src/quoteservice/src/Application/Settings/SettingsInterface.php b/src/quoteservice/src/Application/Settings/SettingsInterface.php new file mode 100644 index 0000000000..cfe3e3f984 --- /dev/null +++ b/src/quoteservice/src/Application/Settings/SettingsInterface.php @@ -0,0 +1,13 @@ + Date: Mon, 29 Aug 2022 08:57:15 +0200 Subject: [PATCH 02/14] Update line break --- src/quoteservice/Dockerfile | 52 ++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/quoteservice/Dockerfile b/src/quoteservice/Dockerfile index 1d418e3241..b46071cf7b 100644 --- a/src/quoteservice/Dockerfile +++ b/src/quoteservice/Dockerfile @@ -1,26 +1,26 @@ -FROM composer:2.4.1 AS build - -WORKDIR /tmp/ -COPY ./src/quoteservice/composer.json . - -RUN composer install \ - --ignore-platform-reqs \ - --no-interaction \ - --no-plugins \ - --no-scripts \ - --prefer-dist - -FROM php:8.1-apache-buster - -# install GRPC (required for the OTel exporter) -RUN apt-get -y update && apt install -y --no-install-recommends zlib1g-dev && \ - pecl install grpc && \ - docker-php-ext-enable grpc - -WORKDIR /var/www -COPY --from=build /tmp/vendor/ /var/www/vendor/ -COPY ./src/quoteservice/ /var/www - -EXPOSE 8090 - -ENTRYPOINT ["php", "-S", "0.0.0.0:8090", "-t", "public"] +FROM composer:2.4.1 AS build + +WORKDIR /tmp/ +COPY ./src/quoteservice/composer.json . + +RUN composer install \ + --ignore-platform-reqs \ + --no-interaction \ + --no-plugins \ + --no-scripts \ + --prefer-dist + +FROM php:8.1-apache-buster + +# install GRPC (required for the OTel exporter) +RUN apt-get -y update && apt install -y --no-install-recommends zlib1g-dev && \ + pecl install grpc && \ + docker-php-ext-enable grpc + +WORKDIR /var/www +COPY --from=build /tmp/vendor/ /var/www/vendor/ +COPY ./src/quoteservice/ /var/www + +EXPOSE 8090 + +ENTRYPOINT ["php", "-S", "0.0.0.0:8090", "-t", "public"] From 224c2d5d2882f468df5439918b4e748770cc7275 Mon Sep 17 00:00:00 2001 From: Juliano Costa Date: Mon, 29 Aug 2022 09:03:18 +0200 Subject: [PATCH 03/14] lint --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 69fe617ebd..26b0d6fa3c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -272,7 +272,7 @@ services: # remove localhost port b4 merging - "${QUOTE_SERVICE_PORT}:${QUOTE_SERVICE_PORT}" environment: - #OTEL_EXPORTER_OTLP_TRACES_ENDPOINT # Not working for PHP + # OTEL_EXPORTER_OTLP_TRACES_ENDPOINT # Not working for PHP - QUOTE_SERVICE_PORT - OTEL_SERVICE_NAME=quoteservice - OTEL_EXPORTER_OTLP_ENDPOINT=otelcol:4317 From db5279f6c5dc5c6f7fd3a6da7508747f2d32d12b Mon Sep 17 00:00:00 2001 From: "juliano.costa" Date: Mon, 29 Aug 2022 13:41:02 +0200 Subject: [PATCH 04/14] Clean-up --- src/quoteservice/.htaccess | 19 ------------- src/quoteservice/composer.json | 7 ----- src/quoteservice/public/.htaccess | 34 ------------------------ src/quoteservice/public/index.php | 44 ++----------------------------- 4 files changed, 2 insertions(+), 102 deletions(-) delete mode 100644 src/quoteservice/.htaccess delete mode 100644 src/quoteservice/public/.htaccess diff --git a/src/quoteservice/.htaccess b/src/quoteservice/.htaccess deleted file mode 100644 index c7552bf4d6..0000000000 --- a/src/quoteservice/.htaccess +++ /dev/null @@ -1,19 +0,0 @@ -Options All -Indexes - - -order allow,deny -deny from all - - - - # Redirect to the public folder - RewriteEngine On - # RewriteBase / - RewriteRule ^$ public/ [L] - RewriteRule (.*) public/$1 [L] - - # Redirect to HTTPS - # RewriteEngine On - # RewriteCond %{HTTPS} off - # RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] - diff --git a/src/quoteservice/composer.json b/src/quoteservice/composer.json index 0d722d6825..72d94dc8dd 100644 --- a/src/quoteservice/composer.json +++ b/src/quoteservice/composer.json @@ -14,13 +14,6 @@ "slim/psr7": "^1.5", "slim/slim": "^4.9" }, - "config": { - "process-timeout": 0, - "sort-packages": true, - "allow-plugins": { - "phpstan/extension-installer": true - } - }, "autoload": { "psr-4": { "App\\": "src/" diff --git a/src/quoteservice/public/.htaccess b/src/quoteservice/public/.htaccess deleted file mode 100644 index fe74ec5b20..0000000000 --- a/src/quoteservice/public/.htaccess +++ /dev/null @@ -1,34 +0,0 @@ -Options All -Indexes - - -order allow,deny -deny from all - - - - RewriteEngine On - - # Redirect to HTTPS - # RewriteEngine On - # RewriteCond %{HTTPS} off - # RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] - - # Some hosts may require you to use the `RewriteBase` directive. - # Determine the RewriteBase automatically and set it as environment variable. - # If you are using Apache aliases to do mass virtual hosting or installed the - # project in a subdirectory, the base path will be prepended to allow proper - # resolution of the index.php file and to redirect to the correct URI. It will - # work in environments without path prefix as well, providing a safe, one-size - # fits all solution. But as you do not need it in this case, you can comment - # the following 2 lines to eliminate the overhead. - RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$ - RewriteRule ^(.*) - [E=BASE:%1] - - # If the above doesn't work you might need to set the `RewriteBase` directive manually, it should be the - # absolute physical path to the directory that contains this htaccess file. - # RewriteBase / - - RewriteCond %{REQUEST_FILENAME} !-d - RewriteCond %{REQUEST_FILENAME} !-f - RewriteRule ^ index.php [QSA,L] - diff --git a/src/quoteservice/public/index.php b/src/quoteservice/public/index.php index 6c9226ef74..4fe879f493 100644 --- a/src/quoteservice/public/index.php +++ b/src/quoteservice/public/index.php @@ -35,52 +35,12 @@ $dependencies($containerBuilder); // Add OTel -$tracerProvider = (new TracerProviderFactory('example'))->create(); +$tracerProvider = (new TracerProviderFactory('quoteservice'))->create(); ShutdownHandler::register([$tracerProvider, 'shutdown']); $tracer = $tracerProvider->getTracer('io.opentelemetry.contrib.php'); $containerBuilder->addDefinitions([ - Tracer::class => $tracer, - Client::class => function () use ($tracer) { - $stack = HandlerStack::create(); - //a guzzle middleware to wrap http calls in a span, and inject trace headers - $stack->push(function (callable $handler) use ($tracer) { - return function (RequestInterface $request, array $options) use ($handler, $tracer): PromiseInterface { - $span = $tracer - ->spanBuilder(sprintf('%s %s', $request->getMethod(), $request->getUri())) - ->setSpanKind(SpanKind::KIND_CLIENT) - ->setAttribute('http.method', $request->getMethod()) - ->setAttribute('http.url', $request->getUri()) - ->startSpan(); - - $ctx = $span->storeInContext(Context::getCurrent()); - $carrier = []; - TraceContextPropagator::getInstance()->inject($carrier, null, $ctx); - //inject traceparent and tracestate headers - foreach ($carrier as $name => $value) { - $request = $request->withAddedHeader($name, $value); - } - - $promise = $handler($request, $options); - $promise->then(function (Response $response) use ($span) { - $span->setAttribute('http.status_code', $response->getStatusCode()) - ->setAttribute('http.response_content_length', $response->getHeaderLine('Content-Length') ?: $response->getBody()->getSize()) - ->setStatus($response->getStatusCode() < 500 ? StatusCode::STATUS_OK : StatusCode::STATUS_ERROR) - ->end(); - - return $response; - }, function (\Throwable $t) use ($span) { - $span->recordException($t)->setStatus(StatusCode::STATUS_ERROR)->end(); - - throw $t; - }); - - return $promise; - }; - }); - - return new Client(['handler' => $stack, 'http_errors' => false]); - }, + Tracer::class => $tracer ]); // Build PHP-DI Container instance From fae5509c42f47ec0aa390447096e3dd7ad7c5b7f Mon Sep 17 00:00:00 2001 From: Juliano Costa Date: Thu, 8 Sep 2022 09:23:55 +0200 Subject: [PATCH 05/14] Adjust quoteservice --- .gitignore | 1 + CHANGELOG.md | 2 ++ docs/manual_span_attributes.md | 7 ++++++ docs/service_table.md | 1 + docs/trace_service_features.md | 1 + src/quoteservice/README.md | 26 ++++++++++++++++++++++ src/quoteservice/app/routes.php | 39 ++++++++++++++++++++++++++++----- 7 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 src/quoteservice/README.md diff --git a/.gitignore b/.gitignore index 593dec9622..3bba855e1c 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,4 @@ next-env.d.ts src/frontend/cypress/videos src/frontend/cypress/screenshots vendor/ +composer.lock diff --git a/CHANGELOG.md b/CHANGELOG.md index dd495561b3..de8564719e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -89,3 +89,5 @@ significant modifications will be credited to OpenTelemetry Authors. ([#331](https://github.com/open-telemetry/opentelemetry-demo/pull/331)) * Add span events to shipping service ([#344](https://github.com/open-telemetry/opentelemetry-demo/pull/344)) +* Add PHP quote service +([#345](https://github.com/open-telemetry/opentelemetry-demo/pull/345)) diff --git a/docs/manual_span_attributes.md b/docs/manual_span_attributes.md index f70c6b7a5d..ef4114012a 100644 --- a/docs/manual_span_attributes.md +++ b/docs/manual_span_attributes.md @@ -96,6 +96,13 @@ This document contains the list of manual Span Attributes used throughout the de | `app.products.count` | number | Number of products in catalog | | `app.products_search.count` | number | Number of products returned in search | +## QuoteService + +| Name | Type | Description | +|-----------------------------|--------|----------------------| +| `app.quote.items.count` | number | Total items to ship | +| `app.quote.cost.total` | number | Total shipping quote | + ## RecommendationService | Name | Type | Description | diff --git a/docs/service_table.md b/docs/service_table.md index b5c6295880..d6a23a93a7 100644 --- a/docs/service_table.md +++ b/docs/service_table.md @@ -14,5 +14,6 @@ View [Service Graph](../README.md#architecture) to visualize request flows. | [loadgenerator](../src/loadgenerator/README.md) | Python/Locust | Continuously sends requests imitating realistic user shopping flows to the frontend. | | [paymentservice](../src/paymentservice/README.md) | JavaScript | Charges the given credit card info (mock) with the given amount and returns a transaction ID. | | [productcatalogservice](../src/productcatalogservice/README.md) | Go | Provides the list of products from a JSON file and ability to search products and get individual products. | +| [quoteservice](../src/quoteservice/README.md) | PHP | Calculates the shipping costs, based on the number of items to be shipped. | | [recommendationservice](../src/recommendationservice/README.md) | Python | Recommends other products based on what's given in the cart. | | [shippingservice](../src/shippingservice/README.md) | Rust | Gives shipping cost estimates based on the shopping cart. Ships items to the given address (mock). | diff --git a/docs/trace_service_features.md b/docs/trace_service_features.md index 15793e5aa5..59d857fc3d 100644 --- a/docs/trace_service_features.md +++ b/docs/trace_service_features.md @@ -17,5 +17,6 @@ Emoji Legend | Frontend | JavaScript | :100: | :100: | :100: | :no_bell: | :100: | :100: | | Payment | JavaScript | :100: | :100: | :100: | :no_bell: | :no_bell: | :100: | | Product Catalog | Go | :100: | :construction: | :100: | :no_bell: | :no_bell: | :no_bell: | +| Quote Service | PHP | :100: | :100: | :100: | :no_bell: | :no_bell: | :no_bell: | | Recommendation | Python | :100: | :100: | :100: | :no_bell: | :no_bell: | :no_bell: | | Shipping | Rust | :no_bell: | :100: | :100: | :100: | :no_bell: | :no_bell: | diff --git a/src/quoteservice/README.md b/src/quoteservice/README.md new file mode 100644 index 0000000000..844ca7f42b --- /dev/null +++ b/src/quoteservice/README.md @@ -0,0 +1,26 @@ +# Quote Service + +The Quote Service calculates the shipping costs, +based on the number of items to be shipped. +It is a PHP based service. + +## Build the service + +To build the quote service, run the following from root directory +of opentelemetry-demo + +```sh +docker compose build quoteservice +``` + +## Run the service + +Execute the below command to run the service. + +```sh +docker compose up quoteservice +``` + +In order to get traffic into the service you have to deploy +the whole opentelemetry-demo. +Please follow the root README to do so. diff --git a/src/quoteservice/app/routes.php b/src/quoteservice/app/routes.php index 01db23ffaf..6de082770c 100644 --- a/src/quoteservice/app/routes.php +++ b/src/quoteservice/app/routes.php @@ -2,19 +2,48 @@ declare(strict_types=1); use OpenTelemetry\API\Trace\AbstractSpan; +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 +{ + $quote = 0.0; + $childSpan = $tracer + ->spanBuilder('calculate-quote') + ->setSpanKind(SpanKind::KIND_INTERNAL) + ->startSpan(); + $childSpanScope = $childSpan->activate(); + $childSpan->addEvent('Calculating quote.'); + + try { + $numberOfItems = intval($jsonObject['numberOfItems']); + $quote = 8.90 * $numberOfItems; + + $childSpan->setAttribute('app.quote.items.count', $numberOfItems); + $childSpan->setAttribute('app.quote.cost.total', $quote); + } catch (Exception $exception) { + $childSpan->recordException($exception); + } finally { + $childSpan->addEvent('Quote calculated, returning its value.'); + $childSpan->end(); + $childSpanScope->detach(); + + return $quote; + } +} + return function (App $app) { - $app->get('/getquote', function (Request $request, Response $response) { + $app->post('/getquote', function (Request $request, Response $response, Tracer $tracer) { $span = AbstractSpan::getCurrent(); + $span->addEvent('Received get quote request, processing it.'); - # do the math here - $data = ['quote' => 32.50]; + $body = file_get_contents("php://input"); + $jsonObject = json_decode($body, true); - $span->addEvent('Received get quote request, processing it.'); - $span->setAttribute('app.quote.cost.total', $data['quote']); + $data = calculateQuote($jsonObject, $tracer); $payload = json_encode($data); $response->getBody()->write($payload); From 0a0d3e9ca13165b4331719cafcdfd94d0ba8bcbf Mon Sep 17 00:00:00 2001 From: Juliano Costa Date: Thu, 8 Sep 2022 09:27:23 +0200 Subject: [PATCH 06/14] Lint --- src/quoteservice/README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/quoteservice/README.md b/src/quoteservice/README.md index 844ca7f42b..19ed583dc1 100644 --- a/src/quoteservice/README.md +++ b/src/quoteservice/README.md @@ -1,7 +1,8 @@ # Quote Service The Quote Service calculates the shipping costs, -based on the number of items to be shipped. +based on the number of items to be shipped. + It is a PHP based service. ## Build the service @@ -21,6 +22,7 @@ Execute the below command to run the service. docker compose up quoteservice ``` -In order to get traffic into the service you have to deploy -the whole opentelemetry-demo. +In order to get traffic into the service you have to deploy +the whole opentelemetry-demo. + Please follow the root README to do so. From 49923b3f05e80f0321491224801107476decdcfe Mon Sep 17 00:00:00 2001 From: Juliano Costa Date: Thu, 8 Sep 2022 14:42:45 +0200 Subject: [PATCH 07/14] Clean up --- src/quoteservice/app/routes.php | 8 +++----- src/quoteservice/public/index.php | 6 ------ 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/quoteservice/app/routes.php b/src/quoteservice/app/routes.php index 6de082770c..937dfec063 100644 --- a/src/quoteservice/app/routes.php +++ b/src/quoteservice/app/routes.php @@ -15,8 +15,7 @@ function calculateQuote($jsonObject, Tracer $tracer): float ->spanBuilder('calculate-quote') ->setSpanKind(SpanKind::KIND_INTERNAL) ->startSpan(); - $childSpanScope = $childSpan->activate(); - $childSpan->addEvent('Calculating quote.'); + $childSpan->addEvent('Calculating quote'); try { $numberOfItems = intval($jsonObject['numberOfItems']); @@ -27,9 +26,8 @@ function calculateQuote($jsonObject, Tracer $tracer): float } catch (Exception $exception) { $childSpan->recordException($exception); } finally { - $childSpan->addEvent('Quote calculated, returning its value.'); + $childSpan->addEvent('Quote calculated, returning its value'); $childSpan->end(); - $childSpanScope->detach(); return $quote; } @@ -38,7 +36,7 @@ function calculateQuote($jsonObject, Tracer $tracer): float return function (App $app) { $app->post('/getquote', function (Request $request, Response $response, Tracer $tracer) { $span = AbstractSpan::getCurrent(); - $span->addEvent('Received get quote request, processing it.'); + $span->addEvent('Received get quote request, processing it'); $body = file_get_contents("php://input"); $jsonObject = json_decode($body, true); diff --git a/src/quoteservice/public/index.php b/src/quoteservice/public/index.php index 4fe879f493..f05520239a 100644 --- a/src/quoteservice/public/index.php +++ b/src/quoteservice/public/index.php @@ -3,18 +3,12 @@ use DI\Bridge\Slim\Bridge; use DI\ContainerBuilder; -use GuzzleHttp\Client; -use GuzzleHttp\HandlerStack; -use GuzzleHttp\Promise\PromiseInterface; use OpenTelemetry\API\Trace\Propagation\TraceContextPropagator; use OpenTelemetry\API\Trace\SpanKind; use OpenTelemetry\API\Trace\StatusCode; -use OpenTelemetry\Context\Context; use OpenTelemetry\SDK\Trace\Tracer; use OpenTelemetry\SDK\Trace\TracerProviderFactory; use OpenTelemetry\SDK\Common\Util\ShutdownHandler; -use Psr\Http\Message\RequestInterface; -use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Server\RequestHandlerInterface as RequestHandler; use Slim\Factory\AppFactory; From 88775e3a54c29400331f948829a7b4060389b650 Mon Sep 17 00:00:00 2001 From: Juliano Costa Date: Fri, 9 Sep 2022 11:37:35 +0200 Subject: [PATCH 08/14] Update src/quoteservice/Dockerfile Co-authored-by: Michael Maxwell --- src/quoteservice/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quoteservice/Dockerfile b/src/quoteservice/Dockerfile index b46071cf7b..9510882be3 100644 --- a/src/quoteservice/Dockerfile +++ b/src/quoteservice/Dockerfile @@ -21,6 +21,6 @@ WORKDIR /var/www COPY --from=build /tmp/vendor/ /var/www/vendor/ COPY ./src/quoteservice/ /var/www -EXPOSE 8090 +EXPOSE ${QUOTE_SERVICE_PORT} ENTRYPOINT ["php", "-S", "0.0.0.0:8090", "-t", "public"] From 509e19632c9a556ecc6051609c657036f8ee2689 Mon Sep 17 00:00:00 2001 From: Juliano Costa Date: Fri, 9 Sep 2022 12:09:30 +0200 Subject: [PATCH 09/14] Applying PR suggestions --- docker-compose.yml | 3 +-- src/quoteservice/app/routes.php | 2 +- src/quoteservice/composer.json | 20 ++++++++++---------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 3b404bf28f..8c16526161 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -301,8 +301,7 @@ services: context: ./ dockerfile: ./src/quoteservice/Dockerfile ports: - # remove localhost port b4 merging - - "${QUOTE_SERVICE_PORT}:${QUOTE_SERVICE_PORT}" + - "${QUOTE_SERVICE_PORT}" environment: # OTEL_EXPORTER_OTLP_TRACES_ENDPOINT # Not working for PHP - QUOTE_SERVICE_PORT diff --git a/src/quoteservice/app/routes.php b/src/quoteservice/app/routes.php index 937dfec063..834b07265e 100644 --- a/src/quoteservice/app/routes.php +++ b/src/quoteservice/app/routes.php @@ -38,7 +38,7 @@ function calculateQuote($jsonObject, Tracer $tracer): float $span = AbstractSpan::getCurrent(); $span->addEvent('Received get quote request, processing it'); - $body = file_get_contents("php://input"); + $body = $request->getBody()->getContents(); $jsonObject = json_decode($body, true); $data = calculateQuote($jsonObject, $tracer); diff --git a/src/quoteservice/composer.json b/src/quoteservice/composer.json index 72d94dc8dd..cc42fad246 100644 --- a/src/quoteservice/composer.json +++ b/src/quoteservice/composer.json @@ -3,16 +3,16 @@ "description": "Quote Service part of OpenTelemetry Demo", "license": "Apache-2.0", "require": { - "php": "^7.4 || ^8.1", - "ext-json": "*", - "monolog/monolog": "^2.3", + "php": "7.4 || 8.1", + "ext-json": "dev-main", + "monolog/monolog": "2.8.0", "open-telemetry/opentelemetry": "dev-main", - "guzzlehttp/guzzle": "*", - "php-di/php-di": "^6.3", - "php-di/slim-bridge": "^3.2", - "php-http/guzzle7-adapter": "*", - "slim/psr7": "^1.5", - "slim/slim": "^4.9" + "guzzlehttp/guzzle": "7.4.5", + "php-di/php-di": "6.4.0", + "php-di/slim-bridge": "3.2.0", + "php-http/guzzle7-adapter": "1.0.0", + "slim/psr7": "1.5", + "slim/slim": "4.10.0" }, "autoload": { "psr-4": { @@ -20,7 +20,7 @@ } }, "scripts": { - "start": "php -S localhost:8080 -t public", + "start": "php -S 0.0.0.0:8090 -t public", "test": "phpunit" } } From bffccfecea050688ef3861cdd779017e8e0c9ce8 Mon Sep 17 00:00:00 2001 From: Juliano Costa Date: Fri, 9 Sep 2022 12:09:42 +0200 Subject: [PATCH 10/14] Update src/quoteservice/Dockerfile Co-authored-by: Brett McBride --- src/quoteservice/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quoteservice/Dockerfile b/src/quoteservice/Dockerfile index 9510882be3..b99793077f 100644 --- a/src/quoteservice/Dockerfile +++ b/src/quoteservice/Dockerfile @@ -10,7 +10,7 @@ RUN composer install \ --no-scripts \ --prefer-dist -FROM php:8.1-apache-buster +FROM php:8.1-cli # install GRPC (required for the OTel exporter) RUN apt-get -y update && apt install -y --no-install-recommends zlib1g-dev && \ From 21898ecfaca0fe34f500c5289b4d785bedd218f9 Mon Sep 17 00:00:00 2001 From: Juliano Costa Date: Fri, 9 Sep 2022 12:11:14 +0200 Subject: [PATCH 11/14] Update src/quoteservice/app/routes.php Co-authored-by: Brett McBride --- src/quoteservice/app/routes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quoteservice/app/routes.php b/src/quoteservice/app/routes.php index 834b07265e..f3ead5ac47 100644 --- a/src/quoteservice/app/routes.php +++ b/src/quoteservice/app/routes.php @@ -23,7 +23,7 @@ function calculateQuote($jsonObject, Tracer $tracer): float $childSpan->setAttribute('app.quote.items.count', $numberOfItems); $childSpan->setAttribute('app.quote.cost.total', $quote); - } catch (Exception $exception) { + } catch (\Exception $exception) { $childSpan->recordException($exception); } finally { $childSpan->addEvent('Quote calculated, returning its value'); From d73964d61ee0b016085110af7577c655a033c641 Mon Sep 17 00:00:00 2001 From: Juliano Costa Date: Fri, 9 Sep 2022 12:16:00 +0200 Subject: [PATCH 12/14] Move addEvent --- src/quoteservice/app/routes.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/quoteservice/app/routes.php b/src/quoteservice/app/routes.php index f3ead5ac47..b33514ae13 100644 --- a/src/quoteservice/app/routes.php +++ b/src/quoteservice/app/routes.php @@ -23,12 +23,12 @@ function calculateQuote($jsonObject, Tracer $tracer): float $childSpan->setAttribute('app.quote.items.count', $numberOfItems); $childSpan->setAttribute('app.quote.cost.total', $quote); + + $childSpan->addEvent('Quote calculated, returning its value'); } catch (\Exception $exception) { $childSpan->recordException($exception); } finally { - $childSpan->addEvent('Quote calculated, returning its value'); $childSpan->end(); - return $quote; } } From 4e18d0fb09b4d56cc3ac6b9e1eb8150b518eba76 Mon Sep 17 00:00:00 2001 From: Juliano Costa Date: Mon, 12 Sep 2022 17:30:45 +0200 Subject: [PATCH 13/14] Add environment variables --- src/quoteservice/Dockerfile | 2 +- src/quoteservice/composer.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/quoteservice/Dockerfile b/src/quoteservice/Dockerfile index b99793077f..0bf75defde 100644 --- a/src/quoteservice/Dockerfile +++ b/src/quoteservice/Dockerfile @@ -23,4 +23,4 @@ COPY ./src/quoteservice/ /var/www EXPOSE ${QUOTE_SERVICE_PORT} -ENTRYPOINT ["php", "-S", "0.0.0.0:8090", "-t", "public"] +ENTRYPOINT php -S 0.0.0.0:${QUOTE_SERVICE_PORT} -t public diff --git a/src/quoteservice/composer.json b/src/quoteservice/composer.json index cc42fad246..a6c6ea09b2 100644 --- a/src/quoteservice/composer.json +++ b/src/quoteservice/composer.json @@ -20,7 +20,7 @@ } }, "scripts": { - "start": "php -S 0.0.0.0:8090 -t public", + "start": "php -S 0.0.0.0:${QUOTE_SERVICE_PORT} -t public", "test": "phpunit" } } From 04366be195866561cfa7de3ca011b7385a2acfdc Mon Sep 17 00:00:00 2001 From: Juliano Costa Date: Tue, 13 Sep 2022 14:53:29 +0200 Subject: [PATCH 14/14] Fixed OTel version, removed unused vars --- src/quoteservice/Dockerfile | 4 ++-- src/quoteservice/composer.json | 7 ++++++- src/quoteservice/public/index.php | 4 ---- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/quoteservice/Dockerfile b/src/quoteservice/Dockerfile index 0bf75defde..94704bf82a 100644 --- a/src/quoteservice/Dockerfile +++ b/src/quoteservice/Dockerfile @@ -14,8 +14,8 @@ FROM php:8.1-cli # install GRPC (required for the OTel exporter) RUN apt-get -y update && apt install -y --no-install-recommends zlib1g-dev && \ - pecl install grpc && \ - docker-php-ext-enable grpc + pecl install grpc protobuf && \ + docker-php-ext-enable grpc protobuf WORKDIR /var/www COPY --from=build /tmp/vendor/ /var/www/vendor/ diff --git a/src/quoteservice/composer.json b/src/quoteservice/composer.json index a6c6ea09b2..dadb58b69e 100644 --- a/src/quoteservice/composer.json +++ b/src/quoteservice/composer.json @@ -6,7 +6,7 @@ "php": "7.4 || 8.1", "ext-json": "dev-main", "monolog/monolog": "2.8.0", - "open-telemetry/opentelemetry": "dev-main", + "open-telemetry/opentelemetry": "0.0.15", "guzzlehttp/guzzle": "7.4.5", "php-di/php-di": "6.4.0", "php-di/slim-bridge": "3.2.0", @@ -22,5 +22,10 @@ "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 f05520239a..d840037178 100644 --- a/src/quoteservice/public/index.php +++ b/src/quoteservice/public/index.php @@ -43,7 +43,6 @@ // Instantiate the app AppFactory::setContainer($container); $app = Bridge::create($container); -$callableResolver = $app->getCallableResolver(); // Register middleware //middleware starts root span based on route pattern, sets status from http code @@ -78,9 +77,6 @@ $serverRequestCreator = ServerRequestCreatorFactory::create(); $request = $serverRequestCreator->createServerRequestFromGlobals(); -// Create Error Handler -$responseFactory = $app->getResponseFactory(); - // Add Body Parsing Middleware $app->addBodyParsingMiddleware();