brettmc/otel-php-rust

Prototype SDK + auto-instrumentation using Rust

Installs: 20

Dependents: 0

Suggesters: 0

Security: 0

Stars: 1

Watchers: 1

Forks: 0

Open Issues: 0

Language:Rust

Type:php-ext

dev-main 2025-03-03 07:21 UTC

This package is auto-updated.

Last update: 2025-03-03 07:21:34 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.

Installation

PIE (PHP Installer for Extensions)

Requires llvm-dev, libclang-dev, rust compiler and cargo.

php pie.phar install brettmc/otel-php-rust:dev-main

Development

Using docker + compose, Dockerfile provides PHP 8.4 + rust environment to build and test in. I've added Makefiles to make things easier, and written some tests using PHP's phpt.

Quick-start:

  • git clone <this repo>
  • make build
  • make bash

From this bash shell, there is another Makefile to build the extension and run the tests. Tests are organised as:

  • test - all tests
  • test-auto - auto-instrumentation
  • test-otlp - otlp (http/protobuf + grpc) exporting to a local collector
  • test-phpt - test the API via PHP code

For the otlp tests, be sure to docker compose up -d collector first.

What works?

  • Auto-instrumentation of userland and internal code, via zend_observer API (see tests/auto/*)
  • Start a span in RINIT for non-cli SAPIs, use traceparent headers, set HTTP response code in RSHUTDOWN
  • TracerProvider globally registered in MINIT, and shutdown on MSHUTDOWN
  • 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
  • Get SpanContext from a Span
$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();

What doesn't work or isn't implemented? (todo list)

Tracers

Tracers are re-fetched all over the shop from tracer_provider.rs

RINIT

  • Context propagation from incoming request headers doesn't correctly set IsRemote (when root span fetched via Span::getCurrent())

SpanBuilder

  • doesn't keep a reference to the tracer, and instead fetches a new tracer each time (losing any InstrumentationScope)

Span

  • getCurrent() fetches the current span as a SpanRef, and presents it as a CurrentSpan (which mirrors Span, but they don't share an interface)
  • addLink panics when trying to retrieve rust span-context object from a wrapped PHP SpanContext

StatusCode

  • not implemented. PR accepted in phper to allow adding consts to classes & interfaces to enable this.

The future

Depending on what we can get to work, or not, this extension could go in a number of directions.

  1. An implementation of the opentelemetry-php API, backed by opentelemetry-rust API+SDK
  2. Do not expose any classes, and use opentelemetry-rust to support only auto-instrumentation a-la SkyWalking, Compass.
  3. Implement an entirely new API, closer to opentelemetry-rust's (ie, don't try to match opentelemetry-php)
  4. Some combination of the above (probably 1+2 or 2+3)
  5. Abandon ship, chalk it up to experience