LaunchDarkly is a feature management platform that serves trillions of feature flags daily to help teams build better software, faster. Get started using LaunchDarkly today!
This package provides an OpenTelemetry integration for the LaunchDarkly PHP Server-Side SDK. It exposes a TracingHook that, when registered with an LDClient, enriches the active OpenTelemetry span with a feature_flag span event for every flag evaluation. The event carries the semantic-convention attributes defined by the OpenTelemetry feature-flag specification and the LaunchDarkly OTEL integration specification (see Attributes emitted).
Reach for this package when you already have OpenTelemetry instrumentation in place and want flag evaluations to show up on the traces that cover them. The hook is a pure consumer of the SDK's hooks API and adds no network or storage dependencies of its own.
This package supports PHP 8.1, 8.2, 8.3, and 8.4. It is safe to use under any PHP SAPI (CLI, PHP-FPM, long-running worker pools); see PHP-FPM and short-lived request lifecycles for guidance on flushing spans in request-response environments.
| PHP SAPI | Supported | Notes |
|---|---|---|
| CLI (scripts, workers) | yes | Nothing to configure. |
| PHP-FPM / mod_php (web requests) | yes | See FPM caveats below — span processors must flush before the request ends. |
| Long-running worker pools (RoadRunner, Swoole, etc.) | yes | Same rules as CLI; follow your pool's shutdown hooks to flush the tracer provider. |
| Dependency | Version |
|---|---|
launchdarkly/server-sdk |
>=6.8 (first release exposing the evaluation hooks API) |
open-telemetry/api |
^1.0 |
psr/log |
^1.0, ^2.0, or ^3.0 |
open-telemetry/api is interface-only. A runtime OpenTelemetry SDK implementation is also required — typically open-telemetry/sdk plus at least one exporter (for example open-telemetry/exporter-otlp for OTLP/HTTP). This package does not pull the SDK in for you, since most applications already configure one.
If you are installing this package from source before launchdarkly/server-sdk has tagged its first hooks-ready release, you may need to track a compatible branch of the parent SDK until that tag lands.
composer require launchdarkly/server-sdk-otel<?php
require __DIR__ . '/vendor/autoload.php';
use LaunchDarkly\LDClient;
use LaunchDarkly\LDContext;
use LaunchDarkly\OpenTelemetry\TracingHook;
use OpenTelemetry\API\Globals;
// Assumes your application has already configured an OpenTelemetry
// TracerProvider and registered it with OpenTelemetry\API\Globals.
$tracer = Globals::tracerProvider()->getTracer('my-app');
$client = new LDClient('sdk-key', [
'hooks' => [new TracingHook()],
]);
$span = $tracer->spanBuilder('handle-request')->startSpan();
$scope = $span->activate();
try {
$enabled = $client->variation(
'my-flag-key',
LDContext::create('user-123'),
false,
);
// ...
} finally {
$scope->detach();
$span->end();
}When $client->variation(...) runs inside the active span, the hook attaches a feature_flag event to that span. When no span is active, the hook is a no-op.
TracingHookOptions is an immutable configuration object passed to the TracingHook constructor. All arguments are optional.
| Option | Type | Default | Purpose |
|---|---|---|---|
includeValue |
bool |
false |
When true, attaches the serialized evaluated flag value as feature_flag.result.value. Be mindful of cardinality and sensitivity before enabling this in production. |
addSpans |
bool |
false |
Experimental. When true, wraps every variation call in an LDClient.<method> child span in addition to the event. The exact span structure and naming may change in future releases. |
environmentId |
string|null |
null |
Emitted as feature_flag.set.id. Empty or whitespace-only input is rejected and stored as null (a warning is logged if a logger is supplied). See Known limitations. |
logger |
Psr\Log\LoggerInterface|null |
null |
Receives construction-time warnings from the options object (for example, an invalid environmentId). When null, no diagnostic output is produced. |
Example:
use LaunchDarkly\OpenTelemetry\TracingHook;
use LaunchDarkly\OpenTelemetry\TracingHookOptions;
$hook = new TracingHook(new TracingHookOptions(
includeValue: true,
addSpans: false,
environmentId: 'your-environment-id',
));The hook emits the following attributes on the feature_flag span event. Attribute names and semantics follow the LaunchDarkly OTEL integration specification.
Required attributes (always emitted when the hook emits an event):
| Attribute | Value |
|---|---|
feature_flag.key |
The flag key being evaluated. |
feature_flag.provider.name |
The fixed string LaunchDarkly. |
feature_flag.context.id |
The canonical key of the LDContext the flag is being evaluated for. |
Optional attributes (emitted only when the corresponding condition is met):
| Attribute | Emitted when |
|---|---|
feature_flag.result.value |
TracingHookOptions::$includeValue is true. Always serialized to a string; bool becomes "true"/"false", null becomes "null", and arrays/objects are JSON-encoded. |
feature_flag.result.variationIndex |
The evaluation produced a non-null variation index. Emitted as an integer, including the value 0. |
feature_flag.result.reason.inExperiment |
The evaluation reason has inExperiment=true. When false, the attribute is omitted entirely rather than emitted as false. |
feature_flag.set.id |
TracingHookOptions::$environmentId is configured with a non-empty string. |
When addSpans=true, the wrapper LDClient.<method> span carries only feature_flag.key and feature_flag.context.id; all other attributes remain on the feature_flag event on the caller's surrounding span.
When no span is active on the current OpenTelemetry context, or the active span has an invalid context, the hook emits nothing.
Under PHP-FPM and similar request-response SAPIs, the PHP process hands control back to the web server as soon as a request completes, which can cut off span exports that a background processor has not yet flushed.
If you use BatchSpanProcessor, its in-memory queue is not guaranteed to flush before the process returns to the pool, and spans emitted late in the request may be lost. You have two straightforward options:
- Use
SimpleSpanProcessor, which exports each span synchronously on end. This is the simplest correct default for FPM deployments. - Continue using
BatchSpanProcessor, but register a shutdown hook that flushes the tracer provider before the process exits:
register_shutdown_function(static function () use ($tracerProvider): void {
$tracerProvider->shutdown();
});Worker pools (RoadRunner, Swoole, and similar) keep the PHP process alive across requests, so BatchSpanProcessor works as intended there. Follow your pool's shutdown hooks to call $tracerProvider->shutdown() at process exit.
feature_flag.set.idis emitted only when the environment ID is supplied viaTracingHookOptions. The alternative path — where the SDK would pass the environment ID throughEvaluationSeriesContextper the LaunchDarkly OTEL integration specification — is not yet supported, because the LaunchDarkly PHP Server-Side SDK does not currently expose an environment ID onEvaluationSeriesContext. ConfiguringenvironmentIdon the options is the supported way to emitfeature_flag.set.idtoday.- When
addSpans=true, the wrapper span name is built from the PHP SDK method string (variation,variationDetail,migrationVariation), producingLDClient.variation,LDClient.variationDetail, andLDClient.migrationVariation. Aligning the casing with other LaunchDarkly SDKs is a concern for the core PHP Server-Side SDK and is tracked separately.
We encourage pull requests and other contributions from the community. Check out our contributing guidelines for instructions on how to contribute to this SDK.
Apache 2.0. See LICENSE.txt for the full text.
- LaunchDarkly is a continuous delivery platform that provides feature flags as a service and allows developers to iterate quickly and safely. We allow you to easily flag your features and manage them from the LaunchDarkly dashboard. With LaunchDarkly, you can:
- Roll out a new feature to a subset of your users (like a group of users who opt-in to a beta tester group), gathering feedback and bug reports from real-world use cases.
- Gradually roll out a feature to an increasing percentage of users, and track the effect that the feature has on key metrics (for instance, how likely is a user to complete a purchase if they have feature A versus feature B?).
- Turn off a feature that you realize is causing performance problems in production, without needing to re-deploy, or even restart the application with a changed configuration file.
- Grant access to certain features based on user attributes, like payment plan (eg: users on the 'gold' plan get access to more features than users in the 'silver' plan). Disable parts of your application to facilitate maintenance, without taking everything offline.
- LaunchDarkly provides feature flag SDKs for a wide variety of languages and technologies. Read our documentation for a complete list.
- Explore LaunchDarkly
- launchdarkly.com for more information
- docs.launchdarkly.com for our documentation and SDK reference guides
- apidocs.launchdarkly.com for our API documentation
- blog.launchdarkly.com for the latest product updates