Best Practices for Observability of OpenTelemetry PHP Services¶
Preface¶
This article describes how to integrate PHP services into Guance based on GuanceCloud/opentelemetry-php-instrumentation, and supplement logs, PHP-FPM metrics, and Profiling to form a directly deployable observability solution.
This solution is suitable for common deployment modes such as PHP-FPM, CLI Worker, Supervisor, and PHP processes inside containers. Trace data is preferably reported via DataKit 4317 port using OTLP gRPC; during debugging and troubleshooting, you can temporarily switch to HTTP OTLP via 9529/otel to quickly verify whether the trace is working.
Environment Information¶
- System environment: Linux
- Development language: PHP 8.2
- Deployment mode: PHP-FPM / CLI
- APM extension:
GuanceCloud/opentelemetry-php-instrumentation 1.3.1-gtrace - Collector: DataKit
Goals¶
- Application trace integration
- Application log integration
- PHP-FPM metrics integration
- Profiling integration (optional)
Integration Plan¶
Notes on the GuanceCloud Fork¶
The integration method in this article is based on GuanceCloud/opentelemetry-php-instrumentation, which is a fork of the official OpenTelemetry repository.
Two boundaries must be clearly stated:
- The extension source can use the release assets from the
GuanceCloudfork - The
composer requirepackagesopen-telemetry/sdk,open-telemetry/exporter-otlp,open-telemetry/opentelemetry-auto-*are still the official PHP packages
In other words, the current fork mainly modifies the PHP extension layer, and does not mean that the entire PHP SDK, exporter, and auto-instrumentation ecosystem has been forked.
Component List¶
To implement OpenTelemetry PHP, at least the following components are required:
- DataKit: responsible for receiving traces, logs, metrics, and profile data
- PHP
opentelemetryextension: responsible for auto-instrumentation capabilities - OpenTelemetry PHP SDK: responsible for data construction and export
- OTLP Exporter: responsible for reporting to DataKit via
gRPCorHTTP - Instrumentation library for the corresponding framework or component: responsible for automatic instrumentation of Laravel, Slim, Symfony, PDO, Guzzle, etc.
Among these, installing the opentelemetry extension alone is not enough; the project must also install SDK + exporter + corresponding auto-instrumentation packages. Otherwise, even if the extension is loaded successfully, complete trace data cannot be formed.
Prerequisites¶
Install DataKit¶
The host must first install DataKit and ensure that 127.0.0.1:4317 or 127.0.0.1:9529 is accessible from the host.
Enable the OpenTelemetry Collector¶
Go to the DataKit installation directory, copy the sample configuration, and restart DataKit:
mkdir -p /usr/local/datakit/conf.d/opentelemetry
cp /usr/local/datakit/conf.d/samples/opentelemetry.conf.sample \
/usr/local/datakit/conf.d/opentelemetry/opentelemetry.conf
systemctl restart datakit
Check whether DataKit is running normally:
Warning
If the application sends data to http://127.0.0.1:9529/otel/v1/traces and receives a 404 response, the problem is usually not on the PHP side but that the opentelemetry input of DataKit is not actually enabled. First, check whether opentelemetry.conf exists and has taken effect after DataKit restarted.
Trace Integration¶
1. Install and Enable the OTEL Extension¶
According to the official OpenTelemetry zero-code documentation, the shortest path should prioritize "system package" or "image installation" instead of compilation from the start.
The recommended order is as follows:
- Linux package manager installation
- Docker image installation
- Use
peclonly if the host already has it - Source code compilation as a last resort
Warning
Do not assume that the Linux host will always have pecl. For example, the host used for verification in this article, as of 2026-07-30, actually had phpize but not pecl.
Also note that yum install php-pecl-opentelemetry or pecl install opentelemetry usually installs the official upstream extension, not the gtrace version from the GuanceCloud fork. If your goal is to verify or deliver 1.3.1-gtrace, the installation source must be changed to the release assets of the GuanceCloud fork or your internal build artifacts.
If your distribution has a ready-made package, install it directly.
For CentOS/RHEL, you can use the official Remi repository method:
yum update -y
yum install -y epel-release yum-utils
yum install -y http://rpms.remirepo.net/enterprise/remi-release-7.rpm
yum-config-manager --enable remi-php81
yum install -y php php-pecl-opentelemetry
php --ri opentelemetry
For Alpine, you can directly install the APK package:
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories
apk add php php81-pecl-opentelemetry@testing
php --ri opentelemetry
For official Docker PHP images:
If the host already has pecl, you can directly execute:
If the host does not have pecl, choose one of the following methods:
- Provide the
opentelemetry.somatching the PHP version directly from the platform side - Install using the system package manager
- Install via
install-php-extensionsinside the container image
For the GuanceCloud fork, the currently recommended enterprise deployment methods are:
- Windows: Use the pre-packaged zip assets in the release directly
- Linux: Build the
opentelemetry.sofor the corresponding PHP minor version via CI, then distribute it uniformly through operations or an artifact repository
This ensures that the installed version is indeed the gtrace version, not the official upstream extension.
For Windows:
- Download the zip package matching the current PHP minor version,
ts/nts, and compiler from theGuanceCloud/opentelemetry-php-instrumentationRelease page - Place
php_opentelemetry.dllinto the PHPext/directory - Enable the extension in
php.ini
Regardless of the method used, when selecting the extension package, you must strictly match the following conditions:
- PHP minor version, e.g.,
8.1/8.2/8.3/8.4 ts/nts- Platform and compiler
- The PHP binary corresponding to the target runtime mode
Enable the extension in php.ini:
Confirm that the extension is loaded:
2. Install SDK and Auto-Instrumentation Dependencies¶
The key point from the official documentation is: installing the extension alone does not generate traces. The project must also install SDK + exporter + instrumentation libraries.
Using Slim + PSR-18 as an example, the minimum dependencies are as follows:
composer config allow-plugins.php-http/discovery false
composer require \
open-telemetry/sdk \
open-telemetry/exporter-otlp \
php-http/guzzle7-adapter \
nyholm/psr7
If your application is not Slim but another framework or component, install the corresponding auto-instrumentation package according to your actual technology stack. Common examples are as follows:
# PSR-18 HTTP Client
composer require open-telemetry/opentelemetry-auto-psr18
# Slim
composer require open-telemetry/opentelemetry-auto-slim
# Laravel
composer require open-telemetry/opentelemetry-auto-laravel
# Symfony
composer require open-telemetry/opentelemetry-auto-symfony
# PDO
composer require open-telemetry/opentelemetry-auto-pdo
# Guzzle
composer require open-telemetry/opentelemetry-auto-guzzle
The minimum principle is:
- Have the extension
- Have
sdk - Have
exporter-otlp - Have
auto-*packages matching your current framework and middleware
Otherwise, you will only get incomplete or even empty trace data.
3. Configure Trace Reporting Parameters¶
It is recommended to use OTLP gRPC to directly connect to the local DataKit on 4317:
OTEL_PHP_AUTOLOAD_ENABLED=true \
OTEL_SERVICE_NAME=my-php-service \
OTEL_SERVICE_VERSION=1.3.1-gtrace \
OTEL_RESOURCE_ATTRIBUTES=deployment.environment=prod \
OTEL_TRACES_EXPORTER=otlp \
OTEL_METRICS_EXPORTER=none \
OTEL_LOGS_EXPORTER=none \
OTEL_EXPORTER_OTLP_PROTOCOL=grpc \
OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4317 \
OTEL_PROPAGATORS=baggage,tracecontext
When troubleshooting, you can switch to HTTP OTLP:
If you use PHP-FPM, Apache, Supervisor, systemd, or containers to start PHP, configure the above environment variables into the process startup environment, not just in the current shell session.
The recommended minimum configuration is as follows:
OTEL_PHP_AUTOLOAD_ENABLED=true
OTEL_SERVICE_NAME=my-php-service
OTEL_SERVICE_VERSION=1.3.1-gtrace
OTEL_TRACES_EXPORTER=otlp
OTEL_METRICS_EXPORTER=none
OTEL_LOGS_EXPORTER=none
OTEL_EXPORTER_OTLP_PROTOCOL=grpc
OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4317
To distinguish environments, add:
4. Add Business Instrumentation¶
Framework auto-instrumentation can only cover general entry points. For key business nodes such as order placement, payment, external API calls, and batch processing, it is recommended to use WithSpan to add instrumentation:
<?php
declare(strict_types=1);
use OpenTelemetry\API\Instrumentation\SpanAttribute;
use OpenTelemetry\API\Instrumentation\WithSpan;
#[WithSpan('order.submit')]
function submitOrder(#[SpanAttribute] string $orderNo): void
{
// Business logic
}
Log Integration¶
It is recommended that the application output JSON logs and explicitly write service, env, and version. If you need to correlate logs with traces, output the current trace_id and span_id together:
use OpenTelemetry\API\Trace\Span;
$context = Span::getCurrent()->getContext();
$traceId = $context->isValid() ? $context->getTraceId() : '';
$spanId = $context->isValid() ? $context->getSpanId() : '';
Enable the logging collector on the DataKit side. Example configuration:
[[inputs.logging]]
logfiles = ["/var/log/php-app/*.log"]
source = "php"
service = "my-php-service"
pipeline = "php-json.p"
It is recommended that the log fields include at least:
messagestatusserviceenvversiontrace_idspan_id
PHP-FPM Metrics Integration¶
If the application runs via PHP-FPM, it is recommended to also enable the phpfpm collector.
- Enable the status page in
www.conf:
-
Expose
/statusthrough Nginx or Apache. -
Enable the
phpfpmcollector on DataKit:
This allows you to monitor:
- Active processes
- Idle processes
- Connection queue length
- Number of slow requests
- Request time and memory consumption per process
Profiling Integration (Optional)¶
If you need to locate CPU, memory allocation, and hotspot functions in addition to traces, you can enable PHP Profiling separately.
The current more reliable approach is:
- Enable the
profilecollector on DataKit - Install
dd-trace-phpon PHP and enable profiling - Configure the following environment variables for the PHP process:
DD_PROFILING_ENABLED=true
DD_SERVICE=my-php-service
DD_ENV=prod
DD_VERSION=1.3.1-gtrace
DD_AGENT_HOST=127.0.0.1
DD_TRACE_AGENT_PORT=9529
Profiling is a supplementary capability to traces. It is recommended to enable it on demand, not by default on all services.
Minimum Integration Sequence¶
If your goal is to first get traces working, then gradually supplement other observability data, it is recommended to follow this order:
- Enable the
opentelemetryinput on DataKit - Install and enable the PHP
opentelemetryextension - Install the
sdk + exporter-otlp + corresponding auto-*dependencies in the project - Configure the
OTEL_*process environment variables - Make a real request and confirm that the trace has entered Guance
- Then add log collection, PHP-FPM metrics, and Profiling
This shortens the trace debugging steps to a minimum, avoiding handling too many components at once.
Current Limitations of the Fork¶
If fully aligning with the official OpenTelemetry zero-code experience, the current GuanceCloud fork still has several obvious gaps:
- No pre-built Linux binaries are available, so the installation path on Linux is not yet short enough
- No independent, identifiable package distribution channel;
pecl install opentelemetrywill land on the upstream, notgtrace - The release assets are not fully integrated with the "system package installation" path in the official documentation, so the documentation cannot directly copy the official installation commands
- It is necessary to separately explain that "the extension comes from the fork, but the SDK and auto-instrumentation dependencies still come from the official Composer packages"
If the integration experience is to be further improved in the future, the priority is recommended as follows:
- Add pre-compiled extension assets for common PHP minor versions for Linux
- Provide an installation script that automatically detects the PHP version,
ts/nts, and extension directory - On the release page, clearly indicate "which PHP version/runtime mode this asset is suitable for"
- In the fork README, clearly distinguish between the "upstream installation path" and the "GuanceCloud gtrace installation path"
Practical Effects¶
After completing the above integration, you can generally obtain the following observability capabilities:
- View trace information such as PHP service entry requests, database calls, downstream HTTP calls, etc., in APM
- Filter logs by
service,env,version, and trace back to the same request based ontrace_id - Observe the running status of PHP-FPM, such as active processes, queuing, and slow requests, in Infrastructure or custom views
- Locate CPU hotspots, memory allocation hotspots, and slow functions in the Profiling view
Best Practice Recommendations¶
- Unify resource attributes: at least standardize
service.name,service.version, anddeployment.environment - Unify release naming: keep the extension version, application version, and release label consistent to facilitate version tracing
- Prefer
4317/gRPC: prioritizeOTLP gRPCin production, and use9529/otelfor debugging and troubleshooting - Prefer ready-made installation methods: prioritize image pre-installation, pre-built artifact distribution, or PECL installation when
peclis available; do not recommend source code compilation as the primary path - Use process-level environment variables: do not set
OTEL_*only in the login shell; write them intophp-fpm,systemd, containers, or startup scripts - Control attribute cardinality: do not write full sets of phone numbers, order numbers, raw SQL, or excessively long URLs into span attributes
- Add manual instrumentation for key business logic: use
WithSpanfor business nodes not covered by auto-instrumentation - Keep trace fields in logs: uniformly output
trace_idandspan_id, otherwise logs and traces cannot be reliably correlated - Check DataKit inputs first: when traces are not working, first confirm whether the
opentelemetry,logging,phpfpm, andprofilecollectors are enabled