Version: 0.71.0This documentation is for Spitfire 0.71.0.
Connecting a PHP service with OTel
The OpenTelemetry PHP extension (opentelemetry) and SDK, with the libraries' automatic
instrumentation packages, collect traces and logs without touching the code. PHP records no
metrics by itself: the service shows under Towers & metrics → Sources once the application
records its own metrics (Metrics API); for the server's metrics use the
Collector. Values and general
rules: Connecting services with OTel: overview.
Version table
| PHP | PECL opentelemetry |
open-telemetry/sdk |
open-telemetry/exporter-otlp |
|---|---|---|---|
| 8.1 and later | 1.4.2 | 1.15.0 | 1.4.0 |
| 8.0 and earlier | not supported | – | Upgrade to PHP 8.1+ or take server metrics only: Collector |
Find your version: php --version (for PHP-FPM php-fpm<php-version> --version).
PHP 8.0: the last packages for it need google/protobuf versions with security advisories, and Composer refuses to install them. Upgrade to PHP 8.1+.
Verified: 2026-11-02. Source: PHP zero-code documentation (PHP 8.0+), PECL opentelemetry (lowest PHP per release), Packagist open-telemetry/sdk, Packagist open-telemetry/exporter-otlp.
What you need
- Spitfire address
https://<spitfire>and OTLP receiver tokensfotlp_… - Tower address
http://<tower>:4318and Collector tokensfcol_… - Protocol
http/protobuf - Service name
<service-name>, version<service-version>, environment<environment> - With a private CA, the CA file
/etc/spitfire-otel/ca.pem - With a proxy, the Tower and Spitfire in
NO_PROXY - Sampling
parentbased_traceidratio,0.1 - Composer in the application (
vendor/autoload.php)
Linux (PHP-FPM, systemd)
- Build and install the extension (Debian/Ubuntu; on RHEL the
php-pecl-opentelemetrypackage from the Remi repository also works):
sudo apt-get install -y gcc make autoconf php-dev php-pear
sudo pecl install opentelemetry-1.4.2- Turn the extension on: create the file
/etc/php/<php-version>/mods-available/opentelemetry.ini, paste this, then runsudo phpenmod opentelemetry:
[opentelemetry]
extension=opentelemetry.so- See that it is on:
php --ri opentelemetry(opentelemetry support => enabled). - In the application's folder, install the SDK, the exporter and your framework's instrumentation
package (write your framework's in place of
opentelemetry-auto-laravel:-auto-symfony,-auto-slim; full list on Packagist):
composer config allow-plugins.php-http/discovery true
composer require open-telemetry/sdk:1.15.0 open-telemetry/exporter-otlp:1.4.0 php-http/guzzle7-adapter \
open-telemetry/opentelemetry-auto-laravel open-telemetry/opentelemetry-auto-psr3
sudo mkdir -p /opt/spitfire-otel /etc/spitfire-otel- Create the file
/etc/spitfire-otel/<service-name>.envand paste this:
IS_OTEL_ENABLED=true
OTEL_SERVICE_NAME=<service-name>
OTEL_RESOURCE_ATTRIBUTES=service.version=<service-version>,deployment.environment=<environment>
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://<spitfire>/otlp/v1/traces
OTEL_EXPORTER_OTLP_TRACES_HEADERS=authorization=sfotlp_…
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=https://<spitfire>/otlp/v1/logs
OTEL_EXPORTER_OTLP_LOGS_HEADERS=authorization=sfotlp_…
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=http://<tower>:4318/v1/metrics
OTEL_EXPORTER_OTLP_METRICS_HEADERS=authorization=sfcol_…
OTEL_TRACES_EXPORTER=otlp
OTEL_METRICS_EXPORTER=otlp
OTEL_LOGS_EXPORTER=otlp
OTEL_TRACES_SAMPLER=parentbased_traceidratio
OTEL_TRACES_SAMPLER_ARG=0.1
NO_PROXY=<tower>,<spitfire>
#OTEL_EXPORTER_OTLP_CERTIFICATE=/etc/spitfire-otel/ca.pem- Restrict its permission:
sudo chmod 600 /etc/spitfire-otel/<service-name>.env - Create the file
/opt/spitfire-otel/otel-runand paste this:
#!/bin/sh
# IS_OTEL_ENABLED=true: OTel loads automatically; any other value: not loaded, SDK off.
if [ "$IS_OTEL_ENABLED" = "true" ]; then
export OTEL_PHP_AUTOLOAD_ENABLED=true
else
export OTEL_PHP_AUTOLOAD_ENABLED=false
export OTEL_SDK_DISABLED=true
fi
exec "$@"- Make it executable:
sudo chmod 755 /opt/spitfire-otel/otel-run - So that PHP-FPM passes environment variables to its workers, uncomment or add this line in the
pool file (
/etc/php/<php-version>/fpm/pool.d/www.conf):
clear_env = no- Find the FPM service's current start command:
systemctl cat php<php-version>-fpm | grep ^ExecStart - Open
sudo systemctl edit php<php-version>-fpmand paste this (on the last line, replace the command afterExecStart=with the command from step 10):
[Service]
EnvironmentFile=/etc/spitfire-otel/<service-name>.env
ExecStart=
ExecStart=/opt/spitfire-otel/otel-run /usr/sbin/php-fpm8.3 --nodaemonize --fpm-config /etc/php/8.3/fpm/php-fpm.conf- Restart:
sudo systemctl daemon-reload && sudo systemctl restart php<php-version>-fpm
For PHP run from the command line (queue worker, cron), apply the same drop-in to that
service's <unit>: ExecStart=/opt/spitfire-otel/otel-run /usr/bin/php /srv/app/artisan queue:work.
Docker
- Put the
otel-runfile (Linux step 7) next to theDockerfile. - In the official
phpimage, add this to theDockerfile(the Composer step as in Linux step 4);/opt/spitfire-otel/otel-rungoes at the start ofENTRYPOINT, the rest is your command:
RUN pecl install opentelemetry-1.4.2 && docker-php-ext-enable opentelemetry
RUN echo "clear_env = no" >> /usr/local/etc/php-fpm.d/www.conf
COPY --chmod=755 otel-run /opt/spitfire-otel/otel-run
ENTRYPOINT ["/opt/spitfire-otel/otel-run", "php-fpm"]- Save the environment file (Linux step 5) on the Docker machine as
/etc/spitfire-otel/<service-name>.env. - Run:
docker run --env-file /etc/spitfire-otel/<service-name>.env …or, in compose, under the serviceenv_file: /etc/spitfire-otel/<service-name>.env. - When the environment file changes, recreate the container (
restartis not enough):docker compose up -d --force-recreate <service>
Kubernetes
- Prepare the image as in the Docker section.
- Save the environment file (Linux step 5) as
<service-name>.envand make it a Secret:
kubectl create secret generic <service-name>-otel --from-env-file=<service-name>.env \
--dry-run=client -o yaml | kubectl apply -f -- In the Deployment, add this under the container:
envFrom:
- secretRef:
name: <service-name>-otel- Restart:
kubectl rollout restart deployment/<deployment>
Windows (IIS)
- Find your PHP's version and build:
php -i | findstr /C:"PHP Version" /C:"Thread Safety" /C:"Architecture"(IIS runs the NTS build,Thread Safety => disabled). - From the PECL Windows page download the zip for your PHP version,
ntsandx64(e.g.https://downloads.php.net/~windows/pecl/releases/opentelemetry/1.4.2/php_opentelemetry-1.4.2-8.3-nts-vs16-x64.zip) and put thephp_opentelemetry.dllinside it in PHP'sextfolder (e.g.C:\php\ext). - Add this line at the end of
php.ini(php --inishows which file):
extension=opentelemetry- See that it is on:
php --ri opentelemetry(opentelemetry support => enabled). - In the application's folder, run the two
composercommands of Linux step 4 (thesudo mkdirline is not needed on Windows). - In an administrator PowerShell, write the
php-cgi.exethe site uses (IIS Manager → FastCGI Settings → Full Path) in place ofC:\php\php-cgi.exeand run (IIS restarts):
Import-Module WebAdministration
$PhpCgi = "C:\php\php-cgi.exe"
$IS_OTEL_ENABLED = "true"
$Vars = [ordered]@{
IS_OTEL_ENABLED = $IS_OTEL_ENABLED
OTEL_SERVICE_NAME = "<service-name>"
OTEL_RESOURCE_ATTRIBUTES = "service.version=<service-version>,deployment.environment=<environment>"
OTEL_EXPORTER_OTLP_PROTOCOL = "http/protobuf"
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = "https://<spitfire>/otlp/v1/traces"
OTEL_EXPORTER_OTLP_TRACES_HEADERS = "authorization=sfotlp_…"
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = "https://<spitfire>/otlp/v1/logs"
OTEL_EXPORTER_OTLP_LOGS_HEADERS = "authorization=sfotlp_…"
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT = "http://<tower>:4318/v1/metrics"
OTEL_EXPORTER_OTLP_METRICS_HEADERS = "authorization=sfcol_…"
OTEL_TRACES_EXPORTER = "otlp"
OTEL_METRICS_EXPORTER = "otlp"
OTEL_LOGS_EXPORTER = "otlp"
OTEL_TRACES_SAMPLER = "parentbased_traceidratio"
OTEL_TRACES_SAMPLER_ARG = "0.1"
NO_PROXY = "<tower>,<spitfire>"
}
# Private CA: $Vars.OTEL_EXPORTER_OTLP_CERTIFICATE = "C:\spitfire-otel\ca.pem"
if ($IS_OTEL_ENABLED -eq "true") {
$Vars.OTEL_PHP_AUTOLOAD_ENABLED = "true"
} else {
$Vars.OTEL_PHP_AUTOLOAD_ENABLED = "false"
$Vars.OTEL_SDK_DISABLED = "true"
}
$Filter = "system.webServer/fastCgi/application[@fullPath='$PhpCgi']/environmentVariables"
foreach ($Name in @($Vars.Keys) + @("OTEL_SDK_DISABLED")) {
Remove-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -Filter $Filter -Name "." -AtElement @{ name = $Name } -ErrorAction SilentlyContinue
}
foreach ($Name in $Vars.Keys) {
Add-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -Filter $Filter -Name "." -Value @{ name = $Name; value = $Vars[$Name] }
}
iisreset /restart- Open a few pages of the site and follow the Verifying steps.
IIS passes these variables to php-cgi.exe when it starts it
(IIS documentation).
Turning off and removing
- Turning off: set
IS_OTEL_ENABLED=falsein the environment file (in the script on Windows) and restart the service (Linux step 12, Docker step 5, Kubernetes step 4, or run the Windows script again). - Removing:
sudo systemctl revert php<php-version>-fpm,sudo phpdismod opentelemetry,sudo rm -r /opt/spitfire-otel /etc/spitfire-otel, and remove theopen-telemetry/packages withcomposer remove; in Docker, delete the lines added to theDockerfile; on Windows, delete theextension=opentelemetryline fromphp.iniand the OTel variables in IIS Manager → FastCGI Settings → Environment Variables.
Common problems
| Symptom | Cause | Fix |
|---|---|---|
php --ri opentelemetry says "not present" |
The extension is not on or was installed for another PHP | Repeat the phpenmod step; for FPM check with php-fpm<php-version> -m |
| The extension is on but there are no traces | clear_env = no is missing or the framework's instrumentation package is not installed |
Check steps 9 and 4 |
pecl install fails on the PHP version |
The PHP version is outside the band | Upgrade to PHP 8.1+ |
| Composer version conflict | The package versions do not fit your PHP | Check PHP 8.1+ with php --version; write no version for the framework package |
| No traces or metrics arrive | Address, token or network | Follow the Verifying steps |