After you instrument an application with OpenTelemetry and report traces to Managed Service for OpenTelemetry, Managed Service for OpenTelemetry starts monitoring the application. You can view monitoring data such as application topology, call stacks, abnormal transactions, slow transactions, and SQL analysis. This topic describes how to automatically or manually instrument a PHP application with OpenTelemetry and report data.
Prerequisites
Background information
OpenTelemetry PHP supports automatic and manual instrumentation. The following PHP versions are required:
Automatic instrumentation: PHP 8.0 or later
Manual instrumentation: PHP 7.4 or later
The following is a list of frameworks that support automatic instrumentation. For a complete list, see the OpenTelemetry official documentation.
Demo
Sample code repository: php-opentelemetry-demo
Automatically instrument an application and report traces using the OpenTelemetry PHP extension
The auto-demo is a dice-rolling game application built on the PHP Slim web framework. It uses OpenTelemetry to automatically instrument the application, creating traces, spans, and other trace data. This provides non-intrusive tracing for the PHP application.
In addition to the Slim framework, OpenTelemetry supports automatic instrumentation for many other frameworks. For a complete list, see the official documentation.
Prerequisites
PHP, Composer, and PECL are installed. The PHP version must be 8.0 or later.
Procedure
Create the dice-rolling application.
Initialize the project.
mkdir <project-name> && cd <project-name> composer init \ --no-interaction \ --stability beta \ --require slim/slim:"^4" \ --require slim/psr7:"^1" composer updateWrite the application code.
In the <project-name> folder, create an index.php file and add the following content.
This code simulates a dice-rolling game and returns a random number from 1 to 6.
<?php use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; use Slim\Factory\AppFactory; require __DIR__ . '/vendor/autoload.php'; $app = AppFactory::create(); $app->get('/rolldice', function (Request $request, Response $response) { $result = random_int(1,6); $response->getBody()->write(strval($result)); return $response; }); $app->run();The application is now complete. Run the
php -S localhost:8080command to start the application. You can access it athttp://localhost:8080/rolldice.
Build the OpenTelemetry PHP extension.
Download the tools required to build the OpenTelemetry PHP extension.
macOS
brew install gcc make autoconfLinux (apt)
sudo apt-get install gcc make autoconf
Use PECL to build the OpenTelemetry PHP extension.
pecl install opentelemetryNote that the last few lines of the output for a successful build are similar to the following (the path may vary):
Build process completed successfully Installing '/opt/homebrew/Cellar/php/8.2.8/pecl/20220829/opentelemetry.so' install ok: channel://pecl.php.net/opentelemetry-1.0.0beta6 Extension opentelemetry enabled in php.ini(Optional) Enable the OpenTelemetry PHP extension.
If the output from the previous step includes
Extension opentelemetry enabled in php.ini, the extension is already enabled. Skip this step.Add the following content to the php.ini file:
[opentelemetry] extension=opentelemetry.soVerify that the extension is built and enabled.
Method 1:
php -m | grep opentelemetryExpected output:
opentelemetryMethod 2
php --ri opentelemetryExpected output:
opentelemetry opentelemetry support => enabled extension version => 1.0.0beta6
Add the dependencies required for automatic instrumentation of the dice-rolling application with OpenTelemetry PHP.
# This step takes a long time to build and prints a lot of content to the console. pecl install grpc composer config allow-plugins.php-http/discovery false composer require \ open-telemetry/sdk \ open-telemetry/opentelemetry-auto-slim \ open-telemetry/exporter-otlp \ php-http/guzzle7-adapter \ open-telemetry/transport-grpcopen-telemetry/sdk: The OpenTelemetry PHP software development kit (SDK).
open-telemetry/opentelemetry-auto-slim: The automatic instrumentation plugin for the Slim framework in OpenTelemetry PHP.
open-telemetry/exporter-otlp: The dependency required to report data over the OpenTelemetry Protocol (OTLP).
Run the application.
Run the following command.
env OTEL_PHP_AUTOLOAD_ENABLED=true \ OTEL_SERVICE_NAME=<your-service-name> \ OTEL_TRACES_EXPORTER=otlp \ OTEL_METRICS_EXPORTER=none \ OTEL_LOGS_EXPORTER=none \ OTEL_EXPORTER_OTLP_PROTOCOL=grpc \ OTEL_EXPORTER_OTLP_ENDPOINT=<endpoint> \ OTEL_EXPORTER_OTLP_HEADERS=Authentication=<token> \ OTEL_PROPAGATORS=baggage,tracecontext \ php -S localhost:8080<your-service-name>: The application name, such as
php-demo.<endpoint>: The gRPC endpoint obtained in the Prerequisites section, such as
http://tracing-analysis-dc-hz.aliyuncs.com:8090.<token>: The authentication token obtained in the Prerequisites section.
Access the following URL in a browser.
http://localhost:8080/rolldiceEach time you access this page, OpenTelemetry automatically creates a trace and reports it to Alibaba Cloud Managed Service for OpenTelemetry.
You can view trace data.
Log on to the Managed Service for OpenTelemetry console. On the Applications page, find the application named
<your-service-name>, such as php-demo. Click the application name to open the application details page and view the call stack.
Manually instrument an application and report traces using the OpenTelemetry PHP SDK
The manual-demo is a dice-rolling game application built on the PHP Slim web framework. It uses the OpenTelemetry PHP SDK to manually instrument the application. This process involves creating spans and setting their properties, events, and statuses in the code to implement custom tracing for the PHP application.
If automatic instrumentation with the OpenTelemetry PHP extension does not meet your needs, or if you want to add custom business instrumentation, you can use manual instrumentation to report traces.
Prerequisites
PHP, Composer, and PECL are installed. The PHP version must be 7.4 or later.
Procedure
Create the dice-rolling application.
Initialize the project.
mkdir <project-name> && cd <project-name> composer init \ --no-interaction \ --stability beta \ --require slim/slim:"^4" \ --require slim/psr7:"^1" composer updateWrite the application code.
In the <project-name> folder, create an index.php file and add the following content.
This code simulates a dice-rolling game and returns a random number from 1 to 6.
<?php use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; use Slim\Factory\AppFactory; require __DIR__ . '/vendor/autoload.php'; $app = AppFactory::create(); $app->get('/rolldice', function (Request $request, Response $response) { $result = random_int(1,6); $response->getBody()->write(strval($result)); return $response; }); $app->run();The application is now complete. Run the
php -S localhost:8080command to start the application. You can access it athttp://localhost:8080/rolldice.
Import the dependencies required for the OpenTelemetry PHP SDK.
gRPC reporting
Download the PHP HTTP client library to report traces.
composer require guzzlehttp/guzzleDownload the OpenTelemetry PHP SDK.
composer require \ open-telemetry/sdk \ open-telemetry/exporter-otlpDownload the dependencies required to report data using gRPC.
pecl install grpc # If you have already downloaded gRPC, you can skip this step. composer require open-telemetry/transport-grpc
HTTP reporting
Download the PHP HTTP client library to report traces.
composer require guzzlehttp/guzzleDownload the OpenTelemetry PHP SDK.
composer require \ open-telemetry/sdk \ open-telemetry/exporter-otlp
Write the OpenTelemetry initialization utility class.
In the same folder as the index.php file, create an opentelemetry_util.php file.
Add the following code to the file.
gRPC reporting
<?php use OpenTelemetry\API\Common\Instrumentation\Globals; use OpenTelemetry\API\Trace\Propagation\TraceContextPropagator; use OpenTelemetry\Contrib\Otlp\SpanExporter; use OpenTelemetry\SDK\Common\Attribute\Attributes; use OpenTelemetry\SDK\Common\Export\Stream\StreamTransportFactory; use OpenTelemetry\SDK\Resource\ResourceInfo; use OpenTelemetry\SDK\Resource\ResourceInfoFactory; use OpenTelemetry\SDK\Sdk; use OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler; use OpenTelemetry\SDK\Trace\Sampler\ParentBased; use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor; use OpenTelemetry\SDK\Trace\SpanProcessor\BatchSpanProcessorBuilder; use OpenTelemetry\SDK\Trace\TracerProvider; use OpenTelemetry\SemConv\ResourceAttributes; use OpenTelemetry\Contrib\Grpc\GrpcTransportFactory; use OpenTelemetry\Contrib\Otlp\OtlpUtil; use OpenTelemetry\API\Signals; // OpenTelemetry initialization configuration (must be done when the PHP application is initialized). function initOpenTelemetry() { // 1. Set the OpenTelemetry resource information. $resource = ResourceInfoFactory::emptyResource()->merge(ResourceInfo::create(Attributes::create([ ResourceAttributes::SERVICE_NAME => '<your-service-name>', # Application name, required. ResourceAttributes::HOST_NAME => '<your-host-name>' # Hostname, optional. ]))); // 2. (Optional) Create a SpanExporter to output spans to the console. // $spanExporter = new SpanExporter( // (new StreamTransportFactory())->create('php://stdout', 'application/json') // ); // 2. Create a SpanExporter to report spans over gRPC. $headers = [ 'Authentication' => "<your-token>", ]; $transport = (new GrpcTransportFactory())->create('<grpc-endpoint>' . OtlpUtil::method(Signals::TRACE), 'application/x-protobuf', $headers); $spanExporter = new SpanExporter($transport); // 3. Create a global TracerProvider to create tracers. $tracerProvider = TracerProvider::builder() ->addSpanProcessor( (new BatchSpanProcessorBuilder($spanExporter))->build() ) ->setResource($resource) ->setSampler(new ParentBased(new AlwaysOnSampler())) ->build(); Sdk::builder() ->setTracerProvider($tracerProvider) ->setPropagator(TraceContextPropagator::getInstance()) ->setAutoShutdown(true) // Automatically shut down the tracerProvider after the PHP program exits to ensure all traces are reported. ->buildAndRegisterGlobal(); // Add the tracerProvider to the global scope. } ?><your-service-name>: The application name.
<your-host-name>: The hostname.
<your-token>: The authentication token for reporting data over gRPC.
<grpc-endpoint>: The endpoint for reporting data over gRPC.
HTTP reporting
<?php use OpenTelemetry\API\Common\Instrumentation\Globals; use OpenTelemetry\API\Trace\Propagation\TraceContextPropagator; use OpenTelemetry\Contrib\Otlp\SpanExporter; use OpenTelemetry\SDK\Common\Attribute\Attributes; use OpenTelemetry\SDK\Common\Export\Stream\StreamTransportFactory; use OpenTelemetry\SDK\Resource\ResourceInfo; use OpenTelemetry\SDK\Resource\ResourceInfoFactory; use OpenTelemetry\SDK\Sdk; use OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler; use OpenTelemetry\SDK\Trace\Sampler\ParentBased; use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor; use OpenTelemetry\SDK\Trace\SpanProcessor\BatchSpanProcessorBuilder; use OpenTelemetry\SDK\Trace\TracerProvider; use OpenTelemetry\SemConv\ResourceAttributes; use OpenTelemetry\Contrib\Otlp\OtlpHttpTransportFactory; use OpenTelemetry\SDK\Common\Export\TransportFactoryInterface; // OpenTelemetry initialization configuration (must be done when the PHP application is initialized). function initOpenTelemetry() { // 1. Set the OpenTelemetry resource information. $resource = ResourceInfoFactory::emptyResource()->merge(ResourceInfo::create(Attributes::create([ ResourceAttributes::SERVICE_NAME => '<your-service-name>', # Application name, required. ResourceAttributes::HOST_NAME => '<your-host-name>' # Hostname, optional. ]))); // 2. (Optional) Create a SpanExporter to output spans to the console. // $spanExporter = new SpanExporter( // (new StreamTransportFactory())->create('php://stdout', 'application/json') // ); // 2. Create a SpanExporter to report spans over HTTP. $transport = (new OtlpHttpTransportFactory())->create('<http-endpoint>','application/x-protobuf'); $spanExporter = new SpanExporter($transport); // 3. Create a global TracerProvider to create tracers. $tracerProvider = TracerProvider::builder() ->addSpanProcessor( (new BatchSpanProcessorBuilder($spanExporter))->build() ) ->setResource($resource) ->setSampler(new ParentBased(new AlwaysOnSampler())) ->build(); Sdk::builder() ->setTracerProvider($tracerProvider) ->setPropagator(TraceContextPropagator::getInstance()) ->setAutoShutdown(true) // Automatically shut down the tracerProvider after the PHP program exits to ensure all traces are reported. ->buildAndRegisterGlobal(); // Add the tracerProvider to the global scope. } ?><your-service-name>: The application name.
<your-host-name>: The hostname.
<http-endpoint>: The endpoint for reporting data over HTTP.
Modify the application code to create spans using the OpenTelemetry API.
In the index.php file, import the required packages.
<?php use OpenTelemetry\API\Common\Instrumentation\Globals; use OpenTelemetry\SDK\Common\Attribute\Attributes; use OpenTelemetry\SDK\Trace\TracerProvider; require __DIR__ . '/opentelemetry_util.php';Call the initOpenTelemetry method to complete the initialization. The OpenTelemetry initialization must be configured when the PHP application starts.
// Initialize OpenTelemetry. This includes setting the application name, trace export method, and trace reporting endpoint, and creating a global TraceProvider. initOpenTelemetry();Create a span in the rolldice interface.
/** * 1. Interface function: Simulates rolling a die and returns a random positive integer from 1 to 6. * Also demonstrates how to create a span, set properties, set events, and set events with properties. */ $app->get('/rolldice', function (Request $request, Response $response) { // Get the tracer. $tracer = \OpenTelemetry\API\Globals::tracerProvider()->getTracer('my-tracer'); // Create a span. $span = $tracer->spanBuilder("/rolldice")->startSpan(); // Set a property for the span. $span->setAttribute("http.method", "GET"); // Set an event for the span. $span->addEvent("Init"); // Set an event with properties. $eventAttributes = Attributes::create([ "key1" => "value", "key2" => 3.14159, ]); // Business logic. $result = random_int(1,6); $response->getBody()->write(strval($result)); $span->addEvent("End"); // End the span. $span->end(); return $response; });Create a nested span.
Create a new rolltwodices interface to simulate rolling two dice and return two random integers from 1 to 6.
The following code shows how to create a nested span.
$app->get('/rolltwodices', function (Request $request, Response $response) { // Get the tracer. $tracer = \OpenTelemetry\API\Globals::tracerProvider()->getTracer('my-tracer'); // Create a span. $parentSpan = $tracer->spanBuilder("/rolltwodices/parent")->startSpan(); $scope = $parentSpan->activate(); $value1 = random_int(1,6); $childSpan = $tracer->spanBuilder("/rolltwodices/parent/child")->startSpan(); // Business logic. $value2 = random_int(1,6); $result = "dice1: " . $value1 . ", dice2: " . $value2; // End the spans. $childSpan->end(); $parentSpan->end(); $scope->detach(); $response->getBody()->write(strval($result)); return $response; });Use a span to record exceptions that occur in the code.
Create a new error interface to simulate an interface exception.
The following code shows how to use a span to record the status when an exception occurs.
$app->get('/error', function (Request $request, Response $response) { // Get the tracer. $tracer = \OpenTelemetry\API\Globals::tracerProvider()->getTracer('my-tracer'); // Create a span. $span3 = $tracer->spanBuilder("/error")->startSpan(); try { // Simulate an exception in the code. throw new \Exception('exception!'); } catch (\Throwable $t) { // Set the span status to error. $span3->setStatus(\OpenTelemetry\API\Trace\StatusCode::STATUS_ERROR, "exception in span3!"); // Record the exception stack trace. $span3->recordException($t, ['exception.escaped' => true]); } finally { $span3->end(); $response->getBody()->write("error"); return $response; } });
Run the application.
Run the following command
php -S localhost:8080Access the following URLs in a browser:
http://localhost:8080/rolldice http://localhost:8080/rolltwodices http://localhost:8080/errorEach time you access a page, OpenTelemetry creates a trace and reports it to Alibaba Cloud Managed Service for OpenTelemetry.
View the trace data.
Log on to the Managed Service for OpenTelemetry console. On the Applications page, find the application named
<your-service-name>, such as php-manual-demo. Click the application name to open the application details page and view the call stack.
