Instrument your PHP application with OpenTelemetry to report trace data to Cloud Monitor 2.0. After instrumentation, you can monitor application topology, traces, abnormal transactions, slow transactions, and SQL analysis.
Background
OpenTelemetry for PHP supports automatic and manual instrumentation. The PHP version requirements are as follows:
-
Automatic instrumentation: Requires PHP 8.0 or later, with PHP, Composer, and PECL installed.
-
Manual instrumentation: Requires PHP 7.4 or later, with PHP, Composer, and PECL installed.
The following frameworks support automatic instrumentation. For a complete list, see the official OpenTelemetry documentation.
Step 1: Get endpoint information
Log on to the Cloud Monitor 2.0 console, and select a workspace. In the left navigation pane, click Integration Center.
-
In the server-side application area, click the PHP card. Set instrumentation type to manual installation and set export protocol to OpenTelemetry.
-
In the Parameter Configurations area, click Click to get next to LicenseKey. Then, select the instrumentation type, connection type, and export protocol as needed. Enter the service name, version, and deployment environment.
The integration code, including the endpoint and LicenseKey, is generated at the bottom of the page based on your configurations.
Install the gRPC extension and related OpenTelemetry dependencies:
pecl install grpc # This build step takes a long time and may produce a large amount of output in the console. 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-grpcConfigure OTLP reporting with environment variables and run the application. Replace
OTEL_EXPORTER_OTLP_ENDPOINTandOTEL_EXPORTER_OTLP_HEADERSwith your actual endpoint and authentication information:env OTEL_PHP_AUTOLOAD_ENABLED=true \ OTEL_SERVICE_NAME= \ OTEL_LOGS_EXPORTER=none \ OTEL_EXPORTER_OTLP_PROTOCOL=grpc \ OTEL_EXPORTER_OTLP_ENDPOINT=https://proj-xtrace-a13xxx7-cn-hangzhou.cn-hangzhou-intranet \ OTEL_EXPORTER_OTLP_HEADERS="x-arms-license-key=gcxxx,x-arms-project=proj-xtrace-a13" \ OTEL_PROPAGATORS=baggage,tracecontext \ php -S localhost:8080Verify that the application is running:
curl http://localhost:8080/rolldice
Automatic instrumentation (recommended)
-
Create a PHP application that uses the Slim framework.
This example builds a simple web application. Skip this step if you already have one.
-
Initialize the application.
mkdir <service name> && cd <service name> composer init \ --no-interaction \ --stability beta \ --require slim/slim:"^4" \ --require slim/psr7:"^1" composer update -
Write the application code.
Create an
index.phpfile in the<service name>directory and add the following content. This code simulates a dice roll 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(); -
Now that the application is complete, run the following command to start it. The access URL is
http://localhost:8080/rolldice.php -S localhost:8080
-
-
Build the OpenTelemetry PHP plugin.
-
Install the required tools to build the OpenTelemetry PHP plugin.
# Linux(apt) sudo apt-get install gcc make autoconf # macOS brew install gcc make autoconf -
Use PECL to build the OpenTelemetry PHP plugin.
pecl install opentelemetry -
Enable the OpenTelemetry PHP plugin by adding the following content to your
php.inifile.Note: If the PHP extension build in the previous step outputs
Extension opentelemetry enabled in php.ini, the plugin is already enabled. Skip this step.[opentelemetry] extension=opentelemetry.so -
Verify that the OpenTelemetry PHP plugin is enabled.
php --ri opentelemetry # Expected output opentelemetry opentelemetry support => enabled extension version => 1.0.0 # The version may vary.
-
-
Add the additional dependencies required for automatic instrumentation.
pecl install grpc # This build step takes a long time and may produce a large amount of output in the console. 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-grpc -
Run the application.
-
Run the following command to start the application.
HTTP reporting
env OTEL_PHP_AUTOLOAD_ENABLED=true \ OTEL_SERVICE_NAME=<service name> \ OTEL_LOGS_EXPORTER=none \ OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf \ OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=<traces.endpoint> \ OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=<metrics.endpoint> \ OTEL_EXPORTER_OTLP_HEADERS="x-arms-license-key=<license-key>,x-arms-project=<arms-project>,x-cms-workspace=<workspace>" \ OTEL_PROPAGATORS=baggage,tracecontext \ php -S localhost:8080gRPC reporting
env OTEL_PHP_AUTOLOAD_ENABLED=true \ OTEL_SERVICE_NAME=<service name> \ OTEL_LOGS_EXPORTER=none \ OTEL_EXPORTER_OTLP_PROTOCOL=grpc \ OTEL_EXPORTER_OTLP_ENDPOINT=<endpoint> \ OTEL_EXPORTER_OTLP_HEADERS="x-arms-license-key=<license-key>,x-arms-project=<arms-project>,x-cms-workspace=<workspace>" \ OTEL_PROPAGATORS=baggage,tracecontext \ php -S localhost:8080 -
Send a request to the application. The OpenTelemetry PHP plugin automatically generates a trace and reports it to Cloud Monitor 2.0.
curl http://localhost:8080/rolldice
-
Manual instrumentation
-
Create a PHP application that uses the Slim framework.
This example builds a simple web application. Skip this step if you already have one.
-
Initialize the application.
mkdir <service name> && cd <service name> composer init \ --no-interaction \ --stability beta \ --require slim/slim:"^4" \ --require slim/psr7:"^1" composer update -
Write the application code.
Create an
index.phpfile in the<service name>directory and add the following content. This code simulates a dice roll 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(); -
Now that the application is complete, run the following command to start it. The access URL is
http://localhost:8080/rolldice.php -S localhost:8080
-
-
Install the dependencies required for the OpenTelemetry PHP SDK.
-
Install a PHP HTTP client library to report trace data.
composer require guzzlehttp/guzzle -
Install the OpenTelemetry PHP SDK.
composer require open-telemetry/opentelemetry
-
-
Create an OpenTelemetry initialization utility file.
Create an
opentelemetry_util.phpfile in the application directory and add the following code:HTTP reporting
Replace the placeholders in the following code with the endpoint information that you obtained in Step 1.
<?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. This must be done when the PHP application starts. function initOpenTelemetry() { // 1. Set OpenTelemetry resource information. $resource = ResourceInfoFactory::emptyResource()->merge(ResourceInfo::create(Attributes::create([ ResourceAttributes::SERVICE_NAME => '<service name>', // service name, required. ResourceAttributes::HOST_NAME => '${hostName}', // hostname, optional. 'acs.cms.workspace' => '<workspace>' // workspace name. ]))); // 2. Optional: Create a SpanExporter to output spans to the console. // $spanExporter = new SpanExporter( // (new StreamTransportFactory())->create('php://stdout', 'application/json') // ); $headers = [ 'x-arms-license-key' => "<license-key>", 'x-arms-project' => "<arms-project>", 'x-cms-workspace' => "<workspace>" ]; // 2. Create a SpanExporter to report spans over HTTP. $transport = (new OtlpHttpTransportFactory())->create('<endpoint>','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 on exit to ensure all spans are exported. ->buildAndRegisterGlobal(); // Register the tracerProvider globally. } ?>gRPC reporting
Replace the placeholders in the following code with the endpoint information that you obtained in Step 1.
<?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. This must be done when the PHP application starts. function initOpenTelemetry() { // 1. Set OpenTelemetry resource information. $resource = ResourceInfoFactory::emptyResource()->merge(ResourceInfo::create(Attributes::create([ ResourceAttributes::SERVICE_NAME => '<service name>', // service name, required. ResourceAttributes::HOST_NAME => '${hostName}', // hostname, optional. 'acs.cms.workspace' => '<workspace>' // workspace name. ]))); // 2. Optional: Create a SpanExporter to output spans to the console. // $spanExporter = new SpanExporter( // (new StreamTransportFactory())->create('php://stdout', 'application/json') // ); $headers = [ 'x-arms-license-key' => "<license-key>", 'x-arms-project' => "<arms-project>", 'x-cms-workspace' => "<workspace>" ]; // 2. Create a SpanExporter to report spans over gRPC. $transport = (new GrpcTransportFactory())->create('<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 on exit to ensure all spans are exported. ->buildAndRegisterGlobal(); // Register the tracerProvider globally. } ?> -
Modify the PHP application code.
Modify the code in the index.php file that you created in Step 1 to call the initOpenTelemetry method, which initializes OpenTelemetry and creates a Span. The complete code is as follows:
<?php use OpenTelemetry\API\Common\Instrumentation\Globals; use OpenTelemetry\SDK\Common\Attribute\Attributes; use OpenTelemetry\SDK\Trace\TracerProvider; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; use Slim\Factory\AppFactory; require __DIR__ . '/vendor/autoload.php'; require __DIR__ . '/opentelemetry_util.php'; // Initialize OpenTelemetry. This includes setting the service name, trace export method, and trace reporting endpoint, and creating a global TracerProvider. initOpenTelemetry(); $app = AppFactory::create(); /** * 1. API function: Simulates rolling a die and returns a random integer from 1 to 6. * This demonstrates how to create a span, set an attribute, add an event, and add an event with attributes. */ $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 an attribute for the span. $span->setAttribute("http.method", "GET"); // Add an event to the span. $span->addEvent("Init"); // Add an event with attributes. $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; }); /** * 2. API function: Simulates rolling two dice and returns two random integers from 1 to 6. * This demonstrates how to create nested spans. */ $app->get('/rolltwodices', function (Request $request, Response $response) { // Get the tracer. $tracer = \OpenTelemetry\API\Globals::tracerProvider()->getTracer('my-tracer'); // Create the parent 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; }); /** * 3. API function: Simulates an API error. * This demonstrates how to use a span to record the status when a code 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 a code exception. 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; } }); $app->run(); -
Run the following command to start the application.
php -S localhost:8080Access the application. Your code creates a trace and reports it to Cloud Monitor 2.0.
curl http://localhost:8080/rolldice
View monitoring data
Log on to the Cloud Monitor 2.0 console, and select a workspace. In the left navigation pane, choose .
-
On the Application List page, click the target service name to view its monitoring details. For more information, see Application Monitoring.