PHPackages                             brettmc/otel-php-rust - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. brettmc/otel-php-rust

ActivePhp-ext[Utility &amp; Helpers](/categories/utility)

brettmc/otel-php-rust
=====================

Prototype SDK + auto-instrumentation using Rust

0.17.0(7mo ago)11971[1 PRs](https://github.com/brettmc/otel-php-rust/pulls)Apache-2.0RustPHP ^7.0CI failing

Since Mar 14Pushed 7mo ago3 watchersCompare

[ Source](https://github.com/brettmc/otel-php-rust)[ Packagist](https://packagist.org/packages/brettmc/otel-php-rust)[ RSS](/packages/brettmc-otel-php-rust/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)DependenciesVersions (37)Used By (0)

OpenTelemetry + Rust
====================

[](#opentelemetry--rust)

Intro
-----

[](#intro)

This is a prototype PHP extension, using [phper](https://github.com/phper-framework/phper)to expose [opentelemetry-rust](https://opentelemetry.io/docs/languages/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 a small and fast 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 small to medium PHP applications 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 that pre-date modern frameworks.

Supported PHP versions
----------------------

[](#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 implemented via the `zend_observer` API for PHP 8.0+, and via `zend_execute_ex` + `zend_execute_internal`for PHP 7.x.

### PHP 7.x

[](#php-7x)

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
------------

[](#installation)

All build approaches require `llvm-dev`, `libclang-dev` (at least 9.0), rust compiler and cargo.

### PIE (PHP Installer for Extensions)

[](#pie-php-installer-for-extensions)

*Only works for PHP versions supported by PIE (8.1+)*

`php pie.phar install brettmc/otel-php-rust:`

### Manual

[](#manual)

```
git clone
cd otel-php-rust
git checkout
make build
make install
```

Debugging
---------

[](#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` -&gt; `error` (default), `warn`, `info`, `debug` or `trace`

`otel.log.file` -&gt; `/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 logs from shutdown phase.

SAPI support
------------

[](#sapi-support)

Tested against `cli-server`, `apache2handler`, `cgi-fcgi` and `cli`.

### `cli`

[](#cli)

Does not auto-create a root span by default, use .ini `otel.cli.create_root_span` to enable.

This should cover cli-based PHP runtimes (roadrunner, react, etc.), but has only been tested against RoadRunner.

Features
--------

[](#features)

- Auto-instrumentation of userland and internal code
    - using either Zend Observer API (PHP 8.0+), or zend\_execute\_ex/zend\_execute\_internal (PHP 7.x)
- Start a span in RINIT, use `traceparent` headers, set HTTP response code in RSHUTDOWN
- Exclude URLs from being traced: `OTEL_PHP_EXCLUDED_URLS=/health*,/ping`
- 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 and `otel.dotenv.per_request` ini setting
- Disabling of auto-instrumentation via `.ini` setting `otel.auto.disabled_plugins`
    - eg `otel.auto.disabled_plugins=laminas,psr18`
- Configure OTEL\_SERVICE\_NAME, OTEL\_RESOURCE\_ATTRIBUTES and OTEL\_DISABLED via .env (for multiple applications on the same host, you can override the general server environment variables)
- Some initial auto-instrumentation plugins:
    - Laminas
    - Zend Framework 1
    - PSR-18 HTTP client

Configuration
-------------

[](#configuration)

### .ini

[](#ini)

NameDefaultDescriptionotel.log.levelerrorLog level: error, warn, debug, traceotel.log.file/dev/stderrLog destination: file or stdout/stderrotel.cli.create\_root\_spanfalseWhether to create a root span for CLI requestsotel.cli.enabledfalseWhether to enable OpenTelemetry for CLI requestsotel.env.set\_from\_serverfalseWhether to set OTEL\_\* environment variables into the environmentotel.env.dotenv.enabledfalseWhether to load .env files per requestotel.auto.enabledtrueAuto-instrumentation enabledotel.auto.disabled\_plugins*empty string*A list of auto-instrumentation plugins to disable, comma-separatedIf either `otel.env.set_from_server` or `otel.env.dotenv.enabled` is set to true, the extension will back up the current environment variables on RINIT, and restore them on RSHUTDOWN.

### Environment variables

[](#environment-variables)

All official OpenTelemetry [SDK configuration](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.46.0/specification/configuration/sdk-environment-variables.md#general-sdk-configuration)environment variables understood by [opentelemetry-rust](https://github.com/open-telemetry/opentelemetry-rust).

If variables are not set in the process environment (eg via apache [SetEnv](https://httpd.apache.org/docs/current/env.html)), then set `otel.env.set_from_server` via php.ini, and `OTEL_*` variables from `$_SERVER` will be set in the environment.

### .env files

[](#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
-----

[](#usage)

### Auto-instrumentation

[](#auto-instrumentation)

By installing the extension and providing the basic [SDK configuration](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.46.0/specification/configuration/sdk-environment-variables.md#general-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.

### Manual instrumentation

[](#manual-instrumentation)

#### Tracing

[](#tracing)

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();
```

Logs
----

[](#logs)

```
use OpenTelemetry\API\Globals;
use OpenTelemetry\API\Logs\LogRecord;

$logger = Globals::loggerProvider()->getLogger("my_logger", '0.1');
$record = new LogRecord('hello otel');
$record
    ->setSeverityNumber(9) //info
    ->setSeverityText('Info')
    ->setEventName('my_event')
    ->setTimestamp((int) (microtime(true) * 1e9))
    ->setAttributes([
        'a_bool' => true,
        'an_int' => 1,
        'a_float' => 1.1,
        'a_string' => 'foo',
        'string_array' => ['one', 'two', 'three'],
        'int_array' => [1, 2, 3],
        'float_array' => [1.1, 2.2, 3.3],
        'bool_array' => [true, false, true],
    ]);
$logger->emit($record);
```

Note that if there is an active span when the log record is emitted, the span context will be associated with the log record.

Plugins
-------

[](#plugins)

Mostly the framework plugins hook in to routing mechanism of that framework, 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

[](#laminas)

Hooks `Laminas\Mvc\MvcEvent::setRouteMatch`. Sets framework name, and uses the `RouteMatch` to set module, controller and action names. Hooks some of the `Laminas\Db` methods to create CLIENT spans for database queries.

### Zend Framework 1

[](#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.

Hooks some Zend\_Db methods to create CLIENT spans for database queries.

### Psr-18

[](#psr-18)

Hooks `Psr\Http\Client\ClientInterface::sendRequest`, creates a CLIENT span and injects the `traceparent` header into outgoing HTTP requests.

Multi-site support
------------------

[](#multi-site-support)

### Vhosts

[](#vhosts)

If providing configuration via Apache `SetEnv` directives, or FPM `env[OTEL_*]` variables, you should enable the `otel.env.set_from_server` setting in your php.ini, so that the extension will set the environment variables from the server environment on RINIT, and restore them on RSHUTDOWN.

For example (untested):

```

    ServerName site1.example.com
    SetEnv OTEL_SERVICE_NAME my-service
    SetEnv OTEL_RESOURCE_ATTRIBUTES "service.namespace=site1,service.version=1.0"
    # Other config...

```

If you cannot modify vhost config, you can also use the `.env` file support described below.

### No vhosts or multiple applications per vhost

[](#no-vhosts-or-multiple-applications-per-vhost)

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.

During request startup (RINIT), the extension will look for a `.env` file in the directory of the processed .php file (eg `/var/www/site1/public/index.php` -&gt; `/var/www/site1/public/.env`), and traverse up until `DOCUMENT_ROOT` is reached. If a .env file is found, it will be checked for `OTEL_SDK_DISABLED`, `OTEL_SERVICE_NAME` and `OTEL_RESOURCE_ATTRIBUTES` variables, and if they are set, they will be set in the current environment, and the original values restored at RSHUTDOWN.

NB that the modified environment variables may not be reflected in `$_SERVER`, but should be visible via `getenv()`.

### Opt-in or opt-out

[](#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?
---------------------------------------

[](#what-doesnt-work-or-isnt-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.
- It could use more interfaces to align with the official OpenTelemetry PHP API

###  Health Score

33

—

LowBetter than 75% of packages

Maintenance63

Regular maintenance activity

Popularity17

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity34

Early-stage or recently created project

 Bus Factor1

Top contributor holds 97.7% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~10 days

Total

20

Last Release

227d ago

PHP version history (2 changes)0.1.0PHP ^8.0

0.8.0PHP ^7.0

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/4978962?v=4)[Brett McBride](/maintainers/brettmc)[@brettmc](https://github.com/brettmc)

---

Top Contributors

[![brettmc](https://avatars.githubusercontent.com/u/4978962?v=4)](https://github.com/brettmc "brettmc (86 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (2 commits)")

### Embed Badge

![Health badge](/badges/brettmc-otel-php-rust/health.svg)

```
[![Health](https://phpackages.com/badges/brettmc-otel-php-rust/health.svg)](https://phpackages.com/packages/brettmc-otel-php-rust)
```

###  Alternatives

[sabre/amf

SabreAMF is a Flash Remoting server and client for PHP

415.9k1](/packages/sabre-amf)[johannschopplich/kirby-seo-audit

SEO analysis powered by Yoast for Kirby CMS

102.3k](/packages/johannschopplich-kirby-seo-audit)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
