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
This commit is contained in:
parent
06d74a737e
commit
13ce2da243
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|||
|
||||

|
||||
|
||||
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.
|
||||
|
||||

|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
class HelloController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* @Route("/hello", name="hello")
|
||||
*/
|
||||
public function index(): Response
|
||||
{
|
||||
return new Response('Hello World');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To check out the routes available in our current project run `php bin/console debug:router`.
|
||||
|
||||

|
||||
|
||||
Let's confirm that our application works by running the command `symfony server:start`.
|
||||
|
||||

|
||||
|
||||
You can navigate to `http://127.0.0.1:8000/hello` route to see the `Hello world` response returned from the
|
||||
HelloController index method above.
|
||||
|
||||

|
||||
|
||||
## Step 3 - Require the OpenTelemetry PHP Library
|
||||
|
||||
Starting from version `v.0.0.2`, the open-telemetry php package allows users to use their preferred HTTP layers for
|
||||
exporting traces. The benefit of this is that users can reuse already existing HTTP configurations for their
|
||||
applications. Hence, there is need to require packages that satisfy both `psr/http-client-implementation`
|
||||
and `psr/http-factory-implementation` before requiring the opentelemetry-php package.
|
||||
|
||||
To satisfy these requirements, we'll use the `guzzlehttp/guzzle` to satisfy the `psr/http-client-implementation` and
|
||||
`guzzlehttp/psr7` to satisfy the `psr/http-factory-implementation`;
|
||||
|
||||
```bash
|
||||
composer require guzzlehttp/guzzle
|
||||
composer require guzzlehttp/psr7
|
||||
```
|
||||
|
||||
Finally, we require the OpenTelemetry PHP library;
|
||||
|
||||
```bash
|
||||
composer require opentelemetry/opentelemetry-php
|
||||
```
|
||||
|
||||
It is worthy of note that this command pulls in the last stable release for the library.
|
||||
|
||||
## Step 4 - Bundle Zipkin and Jaeger into the Application
|
||||
|
||||
To visualize traces from our application, we have to bundle open source tracing tools [Zipkin](https://zipkin.io/)
|
||||
and [Jaeger](https://www.jaegertracing.io/) into our application using docker.
|
||||
|
||||
Let's add a `docker-compose.yaml` file in the root of our project with the content as follows:
|
||||
|
||||
```yaml
|
||||
version: '3.7'
|
||||
services:
|
||||
zipkin:
|
||||
image: openzipkin/zipkin-slim
|
||||
ports:
|
||||
- "9411:9411"
|
||||
jaeger:
|
||||
image: jaegertracing/all-in-one
|
||||
environment:
|
||||
COLLECTOR_ZIPKIN_HOST_PORT: 9412 # Before version 1.22.0 use COLLECTOR_ZIPKIN_HTTP_PORT
|
||||
ports:
|
||||
- "9412:9412"
|
||||
- "16686:16686"
|
||||
```
|
||||
|
||||
To confirm that docker is installed and running on our system, we can run the hello world docker example using the
|
||||
command `docker run -it --rm hello-world`. If everything works well, run `docker-compose up -d` to pull in Zipkin and
|
||||
Jaeger. This might take some time, depending on your internet connection speed.
|
||||
|
||||

|
||||
|
||||
We can confirm that Zipkin is up by navigating to `http://localhost:9411/` on our browser. For Jaeger, navigating
|
||||
to `http://localhost:16686/` on our browser should display the Jaeger home page.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
Now it is time to utilize our OpenTelemetry PHP Library to export traces to both Zipkin and Jaeger.
|
||||
|
||||
## Step 5 - Instrument Symfony Application
|
||||
|
||||
The entry point for all Symfony applications is the `index.php` file located in the `public` folder. Let's navigate
|
||||
to `public\index.php` to see what is happening. It is worthy of note that resources(namespaces, classes, variables)
|
||||
created within the `index.php` file are available within the entire application, by default the index file imports all
|
||||
autoloaded classes within the vendor folder. It also imports contents of the `.env` file. The other parts of
|
||||
the `index.php` file enable debugging as well as support request and response resolution using the application kernel.
|
||||
|
||||
To use open-telemetry specific classes we have to import them at the top of our index file, using the `use` keyword.
|
||||
This is what our imports look like:
|
||||
|
||||
```php
|
||||
use App\Kernel;
|
||||
use OpenTelemetry\API\Trace\AbstractSpan;
|
||||
use OpenTelemetry\API\Trace\StatusCode;
|
||||
use OpenTelemetry\API\Trace\TracerInterface;
|
||||
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\SimpleSpanProcessor;
|
||||
use OpenTelemetry\SDK\Trace\TracerProvider;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
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.
|
||||
|
||||
Since we are looking to export traces to both Zipkin and Jaeger, we configure a tracer with trace exporters for both the
|
||||
services. The tracer needs a sampler to decide whether to record a trace or not. We use the `AlwaysOnSampler` here to
|
||||
ensure that all traces are recorded.
|
||||
|
||||
```php
|
||||
$httpClient = new Client();
|
||||
$httpFactory = new HttpFactory();
|
||||
|
||||
$tracer = (new TracerProvider(
|
||||
[
|
||||
new SimpleSpanProcessor(
|
||||
new OpenTelemetry\Contrib\Jaeger\Exporter(
|
||||
'Hello World Web Server Jaeger',
|
||||
'http://localhost:9412/api/v2/spans',
|
||||
$httpClient,
|
||||
$httpFactory,
|
||||
$httpFactory,
|
||||
),
|
||||
),
|
||||
new SimpleSpanProcessor(
|
||||
new OpenTelemetry\Contrib\Zipkin\Exporter(
|
||||
'Hello World Web Server Zipkin',
|
||||
'http://localhost:9411/api/v2/spans',
|
||||
$httpClient,
|
||||
$httpFactory,
|
||||
$httpFactory,
|
||||
),
|
||||
),
|
||||
],
|
||||
new AlwaysOnSampler(),
|
||||
))->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;
|
||||
|
||||

|
||||
|
||||
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.
|
||||
|
||||
)
|
||||

|
||||
|
||||
Once we click on `Find Traces` you should be able to see traces like below:
|
||||
|
||||

|
||||
|
||||
We can click on a trace to get more information about the trace.
|
||||
|
||||

|
||||
|
||||
For Zipkin, we can visualize our trace by clicking on `Run Query`
|
||||
|
||||

|
||||
|
||||
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
|
||||
|
||||

|
||||
|
||||
## 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).
|
||||
Loading…
Reference in New Issue