brettmc / otel-php-rust
Prototype SDK + auto-instrumentation using Rust
Installs: 93
Dependents: 0
Suggesters: 0
Security: 0
Stars: 7
Watchers: 3
Forks: 0
Open Issues: 1
Language:Rust
Type:php-ext
Requires
- php: ^7.0
- dev-main
- 0.11.0
- 0.10.0
- 0.9.0
- 0.8.2
- 0.8.1
- 0.8.0
- 0.7.0
- 0.6.0
- 0.5.1
- 0.5.0
- 0.4.0
- 0.3.0
- 0.2.0
- 0.1.0
- dev-disable-auto-ini
- dev-gh-action
- dev-edition-2024
- dev-refactor
- dev-improve-disabled
- dev-otel_disabled
- dev-zf1-php7
- dev-tidy2
- dev-merge-resource-attributes
- dev-traverse-dotenv
- dev-execute-ex-fix
- dev-zf1
- dev-docs-multisite
- dev-scope-from-dotenv
- dev-refactor-plugins
- dev-more-resource-attributes
- dev-dotenv
- dev-laminas
- dev-apache-url
- dev-ini-disable-cli
- dev-bugfix/get-tracer-args
- dev-support-php7
- dev-otel-0.30
- dev-request-tidy
- dev-rshutdown-cleanup
- dev-local-root-span-refactor
- dev-otel-rust-0.29
- dev-scope-context
This package is auto-updated.
Last update: 2025-08-07 06:26:48 UTC
README
Intro
This is a prototype PHP extension, using phper to expose opentelemetry-rust via PHP classes and implement auto-instrumentation.
The initial idea was to implement the PHP API in an extension, which could be a drop-in replacement for the core of opentelemetry-php. Since 3rd parties are strongly encouraged to only depend on the API, this should be all they need.
As it's slowly evolved and things have changed in the official opentelemetry-php implementation, the focus has shifted to being an opentelemetry implementation for legacy PHP versions that currently do not have an official way to use OpenTelemetry.
I've focussed development whilst thinking about a large legacy shared PHP host at my day job, where we have hundreds of sites running on a single server (99% running as sub-directories in one Apache vhost), and we want to be able to trace them without modifying the code. There is a mix of frameworks, and some applications pre-date modern frameworks.
Supported PHP versions
This works on all PHP versions supported by phper (7.0+). I've mostly tested against
8.4
, 7.4
and some light testing against 7.0
. Auto-instrumentation is implemeneted
via the zend_observer
API for PHP 8.0+, and via zend_execute_ex
for PHP 7.x.
PHP 7.x
Note that writing to stdout/stderr during MSHUTDOWN doesn't seem to work in PHP 7.x, so console exporting and log writing do not work for this stage. This mostly affects tests, and OTLP exporting works as expected.
Installation
PIE (PHP Installer for Extensions)
Requires llvm-dev
, libclang-dev
, rust compiler and cargo.
php pie.phar install brettmc/otel-php-rust:<version>
Debugging
There's a bunch of logging from the extension and the underlying opentelemetry-rust and dependencies. It's configurable via .ini
:
otel.log.level
-> error
(default), warn
, info
, debug
or trace
otel.log.file
-> /dev/stderr
(default), or another file/location of your choosing
If you really want to see what's going on, set the log level to trace
and you'll get a lot of logs.
In PHP 7.x, logging to stdout/stderr during MSHUTDOWN doesn't work, so you will need to set otel.log.file
to a file location if you want to see the logs.
SAPI support
cli
http + grpc exporters work. Use .ini otel.cli.create_root_span
to create a root span for this SAPI.
This should cover cli-based PHP runtimes (roadrunner, react, etc.), but has only been tested against RoadRunner.
cli-server
http + grpc exporter works. Creates root span on RINIT.
apache2handler
As above
cgi-fcgi
As above
Features
- Auto-instrumentation of userland (PHP8.0+) and internal (PHP8.2+) code, via zend_observer API (see
tests/auto/*
) - Auto-instrumentation of userland code via
zend_execute_ex
(PHP 7.x) - Start a span in RINIT, use
traceparent
headers, set HTTP response code in RSHUTDOWN - TracerProvider created in RINIT (so that child processes have a working instance)
- Spans can be built through a SpanBuilder, some updates made (not all implemented yet), and
end()
ed - Spans can be
activate()
d, and scope detached - Spans export to stdout, otlp (grpc + http/protobuf)
- Batch and Simple span processors
- Get SpanContext from a Span
- Access "local root span"
memory
exporter for testing- Support for shared hosting (ie one apache/fpm server with multiple sites), via
.env
files andotel.dotenv.per_request
ini setting - Disabling of auto-instrumentation via
.ini
settingotel.auto.disabled_plugins
- eg
otel.auto.disabled_plugins=laminas,psr18
- eg
- Configure OTEL_SERVICE_NAME, OTEL_RESOURCE_ATTRIBUTES and OTEL_DISABLED via .env or environment variables (for multiple applications on the same host)
Configuration
.ini
Name | Default | Description |
---|---|---|
otel.log.level | error | Log level: error, warn, debug, trace |
otel.log.file | /dev/stderr | Log destination: file or stdout/stderr |
otel.cli.create_root_span | false | Whether to create a root span for CLI requests |
otel.cli.enabled | false | Whether to enable OpenTelemetry for CLI requests |
otel.dotenv.per_request | false | Whether to load .env files per request |
otel.auto.enabled | true | Auto-instrumentation enabled |
otel.auto.disabled_plugins | empty string | A list of auto-instrumentation plugins to disable, comma-separated |
Environment variables
All official OpenTelemetry SDK configuration environment variables understood by opentelemetry-rust.
.env files
OTEL_SERVICE_NAME
, OTEL_RESOURCE_ATTRIBUTES
and OTEL_SDK_DISABLED
can be set in a .env
file. Other variables should be
set in the environment (todo: could be relaxed to allow setting all OpenTelemetry SDK configuration variables in the .env
file).
Usage
Auto-instrumentation
By installing the extension and providing the basic SDK configuration that opentelemetry expects, each HTTP request will generate an HTTP server root span. There are some initial auto-instrumentation plugins for some legacy frameworks, which will add some extra attributes to the root span. I've kept things very basic for now: one span per request.
Manual instrumentation
Basic usage:
$provider = \OpenTelemetry\API\Globals::tracerProvider(); $tracer = $provider->getTracer('name', '0.1' /*other params*/); $span = $tracer ->spanBuilder('test-span') ->setAttribute('key', 'value'); $span->updateName('updated'); var_dump($span->getContext()->getTraceId()); $span ->setStatus('Ok') ->end();
Some more advanced stuff:
$tracer = \OpenTelemetry\API\Globals::tracerProvider()->getTracer('my-tracer'); $root = $tracer->spanBuilder('root')->startSpan(); $scope = $root->activate(); //somewhere else in code \OpenTelemetry\API\Trace\Span::getLocalRoot()->updateName('updated'); $root->end(); $scope->detach();
Plugins
Mostly the framework plugins hook in to routing mechanism of that framework, and update the root span's name to something more meaningful, and add some attributes.
A couple of non-standard attributes are added if the data is available:
php.framework.name
, php.framework.module.name
, php.framework.controller.name
,
php.framework.action.name
.
Laminas
Hooks Laminas\Mvc\MvcEvent::setRouteMatch
. Sets framework name, and uses the RouteMatch
to set
module, controller and action names.
Zend Framework 1
Hooks Zend_Controller_Router_Interface::route
. Sets framework name, and uses the
Zend_Controller_Request_Abstract
to set module, controller and action names.
Psr-18
Hooks Psr\Http\Client\ClientInterface::sendRequest
, creates a CLIENT span and
injects the traceparent
header into outgoing HTTP requests.
Multi-site support
Vhosts
Multi-site using apache vhosts should "just work". You should set the required environment variables in the vhost config. For example (untested):
<VirtualHost *:80>
ServerName site1.example.com
SetEnv OTEL_SERVICE_NAME my-service
SetEnv OTEL_RESOURCE_ATTRIBUTES "service.namespace=site1,service.version=1.0"
# Other config...
</VirtualHost>
If you cannot modify vhost config, you can also use the .env
file support described below.
No vhosts
If you have multiple sites on a single host (for example each application is a subdirectory of the web root), you can
use the .env
file support to set the environment variables for each site. The extension will look for a .env
file
for each request in the directory of the processed .php file (eg /var/www/site1/public/index.php
-> /var/www/site1/public/.env
). The .env files will be
checked for OTEL_SERVICE_NAME
and OTEL_RESOURCE_ATTRIBUTES
variables, and if they are set, they will be used to
configure the tracer.
Opt-in or opt-out
OpenTelemetry can be either opt-in, or opt-out, using environment variables and .env
files.
If you want to disable OpenTelemetry by default, and enable it for specific applications, you can set
OTEL_DISABLED=true
in the server environment, and then set OTEL_DISABLED=false
in the .env
file
for each application you want to enable observability for.
If you want to enable OpenTelemetry by default, and disable it for specific applications, you can set
OTEL_DISABLED=false
in the server environment, and then set OTEL_DISABLED=true
in the .env
file
for each application you want to disable observability for.
What doesn't work or isn't implemented?
- Context storage - otel-rust doesn't support storing non-simple values, and context keys are created at compile time. This will probably never work like opentelemetry-php.