From 13ce2da243d14ff396eefa6ae0780785a302273b Mon Sep 17 00:00:00 2001 From: Kishan Sangani <93989268+kishannsangani@users.noreply.github.com> Date: Wed, 29 Jun 2022 19:11:08 +0530 Subject: [PATCH] Updated Laravel and Symfony quickstarts (#696) * Updated laravel-quickstart.md * Updated symfony-quickstart.md * Replaced setStatus with recordException in the child span * Removed TODO comment * Changes from PR 701 by DrLuke --- README.md | 4 +- docs/laravel-quickstart.md | 63 ++++++--- docs/symfony-quickstart.md | 280 ------------------------------------- 3 files changed, 45 insertions(+), 302 deletions(-) delete mode 100644 docs/symfony-quickstart.md diff --git a/README.md b/README.md index 729a58d0..f34c32ce 100644 --- a/README.md +++ b/README.md @@ -337,7 +337,9 @@ The easy way to test the example out with docker and docker-compose is: ## User Quickstarts * [Exploring OpenTelemetry in Laravel Applications](./docs/laravel-quickstart.md) -* [Exploring OpenTelemetry in Symfony Applications](./docs/symfony-quickstart.md) + +## Framework integrations +* [Symfony SDK Bundle](https://github.com/open-telemetry/opentelemetry-php-contrib/tree/main/src/Symfony/OtelSdkBundle) is the recommended way to use opentelemetry-php with symfony ## Versioning diff --git a/docs/laravel-quickstart.md b/docs/laravel-quickstart.md index 5acc8598..cca05746 100644 --- a/docs/laravel-quickstart.md +++ b/docs/laravel-quickstart.md @@ -14,7 +14,7 @@ To follow this guide you will need: * [Docker](https://docs.docker.com/get-docker/) for bundling our visualization tools. We have setup instructions for docker on this project's [readme](https://github.com/open-telemetry/opentelemetry-php#development). -This example uses Laravel version 8.40. +This example uses Laravel version `9.1` and OpenTelemetry PHP SDK version `0.0.11`. > ⚠ This example is only intended to introduce how OpenTelemetry can be used in a Laravel application. The > example code is not suited for production applications, and must not be consulted for any code that goes into @@ -46,12 +46,17 @@ and `psr/http-factory-implementation` before requiring the opentelemetry-php pac By default, the Laravel framework utilizes `guzzlehttp/guzzle` and this satisfies `psr/http-client-implementation`, so we need to require the `guzzlehttp/psr7` to meet the `psr/http-factory-implementation` requirement. Let's -run `composer require guzzlehttp/psr7:2.0.0-rc1`. +run `composer require guzzlehttp/psr7:2.1`. -Note: We are specifying `2.0.0-rc1` as that is the release for `guzzlehttp/psr7` that includes HTTP factories as at the +Note: We are specifying `2.1` as that is the release for `guzzlehttp/psr7` that includes HTTP factories as at the time of writing this guide. -Next, let's run `composer require open-telemetry/opentelemetry` to pull in the openTelemetry-php package. +Starting from version `v.0.0.4`, opentelemetry-php package also requires `php-http/async-client-implementation`. Any +client implementation would work, but for this example, let's go ahead with `php-http/guzzle7-adapter`. Run +`composer require php-http/guzzle7-adapter` to install `php-http/guzzle7-adapter`. + +Next, let's run `composer require open-telemetry/opentelemetry` to pull in the openTelemetry-php package. It is worthy +of note that this command pulls in the last stable release for the library. ## Step 3 - Bundle Zipkin and Jaeger into the Application @@ -122,27 +127,25 @@ To use open-telemetry specific classes within our application we have to import the `use` keyword. This is what our list of open-telemetry imported classes should look like: ```php +use GuzzleHttp\Client; +use GuzzleHttp\Psr7\HttpFactory; use OpenTelemetry\API\Trace\AbstractSpan; use OpenTelemetry\API\Trace\StatusCode; use OpenTelemetry\API\Trace\TracerInterface; -use Illuminate\Http\Request; use OpenTelemetry\Contrib\Jaeger\Exporter as JaegerExporter; use OpenTelemetry\Contrib\Zipkin\Exporter as ZipkinExporter; use OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler; +use OpenTelemetry\SDK\Trace\SpanProcessor\BatchSpanProcessor; use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor; use OpenTelemetry\SDK\Trace\TracerProvider; -use GuzzleHttp\Client; -use GuzzleHttp\Psr7\HttpFactory; ``` Remember that these imports should go side by side with the default class imports that come with the `index.php` file. Next, we create a sample recording trace using the [AlwaysOnSampler](https://github.com/open-telemetry/opentelemetry-php/blob/main/sdk/Trace/Sampler/AlwaysOnSampler.php) -class, just before the app instance is created like below: - -Since we are looking to export traces to both Zipkin and Jaeger, we configure a tracer with exporters for both the -services; +class, which is default. Since we are looking to export traces to both Zipkin and Jaeger, we configure a tracer with exporters for both the +services just before the app instance is created like below; ```php $httpClient = new Client(); @@ -159,7 +162,7 @@ $tracer = (new TracerProvider( $httpFactory, ), ), - new SimpleSpanProcessor( + new BatchSpanProcessor( new OpenTelemetry\Contrib\Zipkin\Exporter( 'Hello World Web Server Zipkin', 'http://localhost:9411/api/v2/spans', @@ -233,7 +236,8 @@ Route::get('/hello', [HelloController::class, 'index']); ``` The above snippet routes every GET request from the `/hello` route on the browser to an index method within -the `HelloController` class. For now, this method does not exist, so we have to add it to our controller as follows: +the `HelloController` class. For now, this method does not exist, so we have to add it to our controller in +`app\Http\Controllers\HelloController.php` as follows: ```php public function index(){ @@ -245,16 +249,29 @@ Let's confirm that everything works well by visiting the `/hello` route on our b ![](https://user-images.githubusercontent.com/22311928/115635323-5c145d80-a303-11eb-869f-6fe18f7f01a4.png) -Now that we have the `index` method working, we can simulate adding an exception event to our trace as follows: +Now that we have the `index` method working, let's make changes to the existing rootSpan and create an exception in a +child span of the rootSpan. We can do the same as follows: + +- Import the required functions on top of the file: ```php -/** @var TracerInterface $tracer */ -global $tracer; +use OpenTelemetry\API\Trace\AbstractSpan; +use OpenTelemetry\API\Trace\StatusCode; +use OpenTelemetry\SDK\Trace\TracerProvider; +``` + +- Put the below snippet in `index()` function before the `return` statement: + +```php +/** @var TracerProvider $tracer */ +$tracer = TracerProvider::getDefaultTracer(); if ($tracer) { /** @var Span $span */ $span = AbstractSpan::getCurrent(); $span->setAttribute('foo', 'bar'); + $span->setAttribute('Application', 'Laravel'); + $span->setAttribute('foo', 'bar1'); $span->updateName('New name'); $childSpan = $tracer->spanBuilder('Child span')->startSpan(); @@ -262,18 +279,22 @@ if ($tracer) { try { throw new \Exception('Exception Example'); } catch (\Exception $exception) { - $childSpan->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); + $childSpan->recordException($exception); } $childSpan->end(); $childScope->detach(); } ``` -In the above snippet we change the span name and attributes for our trace, we also add an exception event to the -span. +In the above snippet, we set two new attributes for the current span, and then change the value for one of the attribute +and the trace reflects the latest value. We also change the name of our current span and add an exception event to the +child span. -We need to reload our `http://127.0.0.1:8000/hello` route, then navigate to Zipkin like before, to see that our span -name gets updated to `new name` and our `Exception Example` is visible. +* Point to note: all the variables in `index.php` are available in this file. But we use inbuilt functions to get `$tracer` +rather than using the global variables. + +We need to reload our `http://127.0.0.1:8000/hello` route, then navigate to Zipkin and Jaeger like before, to see that our +span name gets updated to `new name` and our `Exception Example` is visible. ![image](https://user-images.githubusercontent.com/22311928/115635324-5cacf400-a303-11eb-947d-cf8205c0e93b.png) diff --git a/docs/symfony-quickstart.md b/docs/symfony-quickstart.md deleted file mode 100644 index 9754b99b..00000000 --- a/docs/symfony-quickstart.md +++ /dev/null @@ -1,280 +0,0 @@ -# Exploring Opentelemetry in Symfony Applications - -## Introduction - -As a developer, you might be wondering how OpenTelemetry could be beneficial to you. Without practical examples, the -usefulness of distributed tracing can be difficult to grasp for persons without a cloud or site reliability engineering -background. This user guide shows how OpenTelemetry could be useful to gain insights into exceptions happening within an -application. This example uses the OpenTelemetry PHP library integrated into a Symfony application, bundled with Jaeger -and Zipkin, for visualizing data. - -> ⚠ This example is only intended to introduce how OpenTelemetry can be used in a Symfony application. The -> example code is not suited for production applications, and must not be consulted for any code that goes into -> production. - -## Prerequisites - -To follow this guide you will need: - -* PHP Installed, this example uses PHP 7.4. -* [Composer](https://getcomposer.org/download/) for dependency management. -* [Symfony CLI](https://symfony.com/download) for managing your Symfony application. -* [Docker](https://docs.docker.com/get-docker/) for bundling our visualization tools. We have set up instructions for - docker on this project's [readme](https://github.com/open-telemetry/opentelemetry-php#development). - -This example uses Symfony version 5.2 . - -## Step 1 - Creating a Symfony Application - -Create a Symfony application by running the command `symfony new my_project_name`. We are calling this -example `otel-php-symfony-basic-example`, so the command is as follows; - -`symfony new otel-php-symfony-basic-example` . - -## Step 2 - Require and Test Symfony Dependencies - -To define our routes within our controller methods, let's require the Doctrine annotation library by running the -command `composer require doctrine/annotations`. - -We can test that routes defined within Controllers work by creating a `HelloController.php` file within -the `src\Controller` folder as follows: - -```php -getTracer('Hello World Symfony Web Server'); -``` - -Next we create a span from our tracer; - -```php -$request = Request::createFromGlobals(); -$span = $tracer->spanBuilder($request->getUri())->startSpan(); -$spanScope = $span->activate(); -``` - -Finally, we end the active spans and detach the span scope by adding the following block at the end of -the `index.php` file; - -```php -$span->end(); -$spanScope->detach(); -``` - -Let's confirm that we can see exported traces on both Zipkin and Jaeger. To do that we need to -reload `http://127.0.0.1:8000/hello` or any other route on our symfony server; - -![image](https://user-images.githubusercontent.com/22311928/115637070-43a64200-a307-11eb-8abb-80f19285ef01.png) - -We also need reload both Zipkin and Jaeger on our browser, using the URLs `http://localhost:9411/` -and `http://localhost:16686/`. Do ensure that both your symfony server and docker instance are running for this step. - -For Jaeger under service, you should see a `Hello World Web Server Jaeger` service, go ahead and click find traces to -see exported traces. - -) -![image](https://user-images.githubusercontent.com/22311928/115637071-443ed880-a307-11eb-8521-78c803dcd623.png) - -Once we click on `Find Traces` you should be able to see traces like below: - -![image](https://user-images.githubusercontent.com/22311928/115637073-44d76f00-a307-11eb-9e80-aa8f152577a8.png) - -We can click on a trace to get more information about the trace. - -![image](https://user-images.githubusercontent.com/22311928/115637075-44d76f00-a307-11eb-8d8e-5bf559bd2bf6.png) - -For Zipkin, we can visualize our trace by clicking on `Run Query` - -![image](https://user-images.githubusercontent.com/22311928/115637078-45700580-a307-11eb-9867-aa0c1a69f9fe.png) - -Since resources in Symfony's `public\index.php` file are available to the entire application, we can use any of the -already instantiated tracers within `HelloController`. In addition to the tracers, we can also utilize associated -properties, methods and events. - -Let's try using the `addEvent` method, to capture errors within our controller as follows: - -```php -/** @var TracerInterface $tracer */ -global $tracer; -if ($tracer) { - /** @var Span $span */ - $span = AbstractSpan::getCurrent(); - - $span->setAttribute('foo', 'bar'); - $span->updateName('New name'); - - $childSpan = $tracer->spanBuilder('Child span')->startSpan(); - $childScope = $childSpan->activate(); - try { - throw new \Exception('Exception Example'); - } catch (\Exception $exception) { - $childSpan->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); - } - $childSpan->end(); - $childScope->detach(); -} -``` - -In the above snippet we change the span name and attributes for our trace, we also add an exception event to the -span. - -We need to reload our `http://127.0.0.1:8000/hello` route, then navigate to Zipkin like before to see that our span name -gets updated to `new name` and our `Exception Example` is visible - -![image](https://user-images.githubusercontent.com/22311928/115637079-46089c00-a307-11eb-9d9d-b5c0f941baeb.png) - -## Summary - -With the above example we have been able to instrument a Symfony application using the OpenTelemetry php library. You -can fork the example project [here](https://github.com/prondubuisi/otel-php-symfony-basic-example). You can also check -out the original test application [here](https://github.com/dkarlovi/opentelemetry-php-user-test).