In this article, Integrate OpenTelemetry for PHP Application with Manual Instrumentation. OpenTelemetry is a powerful framework that enables observability by collecting, processing, and exporting telemetry data such as traces and logs. Manual instrumentation allows you to directly control which parts of your application are monitored, offering detailed insights into application performance.
Table of Contents
Prerequisites
Before you start, ensure you have the following installed on your system.
- AWS Account with Ubuntu 24.04 LTS EC2 Instance.
- PHP, PECL, composer installed.
Step #1:Set Up Ubuntu EC2 Instance
First update the package list.
sudo apt update
Installs the command-line interface for PHP 8.3.
sudo apt install php8.3-cli
Verify the installation.
php -v
Install PECL to install tools needed for PHP extension development.
sudo apt install php-pear php8.3-dev
Download and install Composer. Composer is a dependency manager for PHP that simplifies managing libraries.
curl -sS https://getcomposer.org/installer | php
Move the Composer binary to a directory in /usr/local/bin/, making it accessible globally.
sudo mv composer.phar /usr/local/bin/composer
Checks the version of Composer to verify the installation.
composer -v
Install Build Tools which are required for building PECL extensions.
sudo apt-get install gcc make autoconf
Step #2:Create Your PHP Project with Slim Framework
Create a new project directory.
mkdir opentelemetry-php-example
Navigate to the directory.
cd opentelemetry-php-example
Initialize a new Composer project, specifying Slim as a dependency.
composer init --no-interaction --require slim/slim:"^4" --require slim/psr7:"^1"
Install the dependencies defined in composer.json using following command.
composer update
Create an index.php file that contains a simple Slim application.
nano index.php
add the following code into it.
<?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();
Explanation of the code:
- Imports and Autoloading:
- This imports necessary classes and loads dependencies installed with Composer.
- Create Application:
- Initializes a new Slim application instance. The
$app
variable is now the application object, which will manage routes and handle HTTP requests.
- Initializes a new Slim application instance. The
- Define the
/rolldice
Route:- Defines a route (
/rolldice
) that generates a random integer between 1 and 6, writes it to the response, and sends it back to the client.
- Defines a route (
- Run the Application:
- Starts the application and listens for incoming requests.
Now, start the built-in PHP server to test your application using following command.
php -S 0.0.0.0:8080
Open http://<Public-IP-Address>:8080/rolldice in your browser. You should see a random number between 1 and 6.
Step #3:Integrate OpenTelemetry for PHP Application with Manual Instrumentation to get Trace data
First install the OpenTelemetry SDK.
composer require open-telemetry/sdk
Modify index.php to add OpenTelemetry manual tracing.
nano index.php
add the following code into it.
<?php
use OpenTelemetry\API\Globals;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
require __DIR__ . '/vendor/autoload.php';
$tracer = Globals::tracerProvider()->getTracer('demo');
$app = AppFactory::create();
$app->get('/rolldice', function (Request $request, Response $response) use ($tracer) {
$span = $tracer
->spanBuilder('manual-span')
->startSpan();
$result = random_int(1,6);
$response->getBody()->write(strval($result));
$span
->addEvent('rolled dice', ['result' => $result])
->end();
return $response;
});
$app->run();
Explanation of the code:
- Imports and Autoloading:
- Imports necessary classes from OpenTelemetry, Slim, and PSR-7.
Globals
: Provides access to OpenTelemetry’s global tracer.ResponseInterface
andServerRequestInterface
: Define standard structures for handling HTTP requests and responses in PHP.AppFactory
: Used to create a Slim application instance.
- Autoloading: The require statement includes Composer’s autoload file, loading all dependencies specified in composer.json.
- Imports necessary classes from OpenTelemetry, Slim, and PSR-7.
- Create Application:
- This initializes a new Slim application instance using
AppFactory
. The$app
variable now holds the application object that will manage routes and handle HTTP requests.
- This initializes a new Slim application instance using
- Define the /rolldice Route:
- Defines a route (
/rolldice
) that listens for GET requests. - Manual Tracing with OpenTelemetry:
spanBuilder
creates a new span (manual-span
) to capture trace data for this request.startSpan()
begins the span, recording this operation in the trace.- Rolls a Dice:
random_int(1,6)
generates a random number from 1 to 6, simulating a dice roll. - Returns the Result: The result is written to the response body using
write()
, andaddEvent()
logs the event within the trace, capturing the result as additional data. end()
closes the span, marking the end of this traced operation.
- The final response is sent to the client with the dice roll result.
- Defines a route (
- Run the Application:
- Starts the php application and begins listening for incoming requests. Slim routes them to their corresponding handlers, which process the request and return a response.
Run the php application with OpenTelemetry environment variables to enable tracing output to the console.
env OTEL_PHP_AUTOLOAD_ENABLED=true \
OTEL_TRACES_EXPORTER=console \
OTEL_METRICS_EXPORTER=none \
OTEL_LOGS_EXPORTER=none \
php -S 0.0.0.0:8080
Access http://<Public-IP-Address>:8080/rolldice to view trace information in the console. The OpenTelemetry SDK should capture trace details for the /rolldice
route, indicating the span and event data.
Step #4:Integrate OpenTelemetry logging with Monolog
Install Monolog and OpenTelemetry logger dependencies.
composer require monolog \ monolog open-telemetry \ opentelemetry-logger-monolog
Modify index.php to add logging functionality using Monolog with OpenTelemetry
nano index.php
Add the following code into it.
<?php
use Monolog\Logger;
use OpenTelemetry\API\Globals;
use OpenTelemetry\Contrib\Logs\Monolog\Handler;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Log\LogLevel;
use Slim\Factory\AppFactory;
require __DIR__ . '/vendor/autoload.php';
$loggerProvider = Globals::loggerProvider();
$handler = new Handler(
$loggerProvider,
LogLevel::INFO
);
$monolog = new Logger('otel-php-monolog', [$handler]);
$app = AppFactory::create();
$app->get('/rolldice', function (Request $request, Response $response) use ($monolog) {
$result = random_int(1,6);
$response->getBody()->write(strval($result));
$monolog->info('dice rolled', ['result' => $result]);
return $response;
});
$app->run();
Explanation of the code:
- Imports and Autoloading:
- Imports necessary classes for logging, OpenTelemetry, HTTP messaging, and Slim:
Logger
: Monolog’s main class for logging events.Globals
andHandler
: Access to OpenTelemetry’s global logger provider and a handler to integrate OpenTelemetry with Monolog.ResponseInterface
andServerRequestInterface
: Define HTTP request and response structures for handling them in Slim.LogLevel
: Provides log severity levels, such asINFO
.AppFactory
: Used to create the Slim application instance.
- Autoloading: Loads dependencies specified in
composer.json
through Composer’s autoloader.
- Imports necessary classes for logging, OpenTelemetry, HTTP messaging, and Slim:
- Set Up Logging:
- Initialize OpenTelemetry Logger Provider: Retrieves the global logger provider from OpenTelemetry.
- Create a Handler for Monolog:
Handler
: Sets up a bridge between OpenTelemetry and Monolog.LogLevel::INFO
: Defines the minimum log level to capture (INFO and above).
- Set Up Monolog Logger:
Logger
: A Monolog instance is created, with OpenTelemetry’s handler attached.- The logger name
otel-php-monolog
will label all logs generated by this instance.
- Define the /rolldice Route:
- Defines a route (
/rolldice
) that listens for GET requests. - Simulates a Dice Roll:
random_int(1,6)
: Generates a random number from 1 to 6, simulating a dice roll.- Logs the Dice Roll:
info()
logs the result at INFO level, with a messagedice rolled
and attaches the dice roll result as a context property. - Returns the Response: The dice roll result is written to the response body, which is then returned to the client.
- Defines a route (
- Run the Application:
- Starts the php application and begins listening for incoming requests. Slim handles routing to the appropriate handler, which processes the request and returns a response with the dice roll result.
Run the php application again, with environment variables configured for logging.
env OTEL_PHP_AUTOLOAD_ENABLED=true \
OTEL_TRACES_EXPORTER=console \
OTEL_METRICS_EXPORTER=none \
OTEL_LOGS_EXPORTER=console \
php -S 0.0.0.0:8080
Access http://<Public-IP-Address>:8080/rolldice. The console should display log messages that capture the dice roll results, as well as any trace data generated by OpenTelemetry.
Conclusion:
In this article, we successfully integrated OpenTelemetry with manual instrumentation in a PHP application using the Slim framework. We demonstrated how to enable manual tracing and logging, which provides valuable observability insights without requiring extensive changes to your existing codebase. By capturing detailed trace and log information, OpenTelemetry helps enhance application monitoring, making it easier to identify issues and optimize performance.
Related Articles:
Integrate OpenTelemetry for PHP Application with Zero-Code Instrumentation
Reference: