Attribute-based Instrumentation
OpenTelemetry PHP Distro supports automatic span creation using PHP 8
attributes. Annotate methods or functions with #[WithSpan] to create spans
without writing instrumentation code manually.
Prerequisites
- PHP 8.0 or later (PHP attributes require PHP 8+).
open-telemetry/apipackage installed in your application.OTEL_PHP_ATTR_HOOKS_ENABLED=trueset in the environment (disabled by default).
Enable
export OTEL_PHP_ATTR_HOOKS_ENABLED=true
Or in php.ini:
opentelemetry_distro.attr_hooks_enabled=true
Basic usage
use OpenTelemetry\API\Instrumentation\WithSpan;
class OrderService
{
#[WithSpan]
public function processOrder(int $orderId): string
{
// A span named "OrderService::processOrder" is created automatically.
return "processed-{$orderId}";
}
}
#[WithSpan] options
#[WithSpan(
span_name: 'custom.span.name', // default: "ClassName::methodName"
span_kind: SpanKind::KIND_SERVER, // default: KIND_INTERNAL
attributes: ['key' => 'value'], // static attributes added to the span
)]
All arguments are optional and can be passed positionally or by name:
// Positional
#[WithSpan('payment.charge', SpanKind::KIND_CLIENT, ['db.system' => 'redis'])]
// Named — any subset
#[WithSpan(span_kind: SpanKind::KIND_PRODUCER)]
#[WithSpan(span_name: 'message.publish', span_kind: SpanKind::KIND_PRODUCER)]
Capturing parameter values with #[SpanAttribute]
Add #[SpanAttribute] to function parameters to include their runtime values as
span attributes:
use OpenTelemetry\API\Instrumentation\WithSpan;
use OpenTelemetry\API\Instrumentation\SpanAttribute;
class UserService
{
#[WithSpan]
public function createUser(
#[SpanAttribute] string $username, // attribute key = "username"
string $password, // not captured
#[SpanAttribute('user.email')] string $email, // attribute key = "user.email"
): int {
// ...
}
}
Capturing property values with #[SpanAttribute]
Apply #[SpanAttribute] to class properties to capture their value at the time
the method is called:
class InvoiceService
{
#[SpanAttribute]
public string $customerId = '';
#[SpanAttribute('invoice.currency')]
public string $currency = 'EUR';
#[WithSpan('invoice.generate')]
public function generate(): string
{
// Span attributes include: customerId, invoice.currency
}
}
Exception recording
If the annotated method throws, the span automatically records the exception and
sets status to ERROR. The exception propagates normally.
#[WithSpan]
public function riskyOperation(): void
{
throw new \RuntimeException('something went wrong');
// Span is ended with STATUS_ERROR and exception event attached.
}
Nested spans
Calling one #[WithSpan] method from another creates nested spans
automatically:
class Pipeline
{
#[WithSpan('pipeline.run')]
public function run(): void
{
$this->step1(); // child span: "pipeline.step1"
$this->step2(); // child span: "pipeline.step2"
}
#[WithSpan('pipeline.step1')]
private function step1(): void {}
#[WithSpan('pipeline.step2')]
private function step2(): void {}
}
Standalone functions
#[WithSpan] works on standalone functions, not only methods:
#[WithSpan('compute.result')]
function computeResult(#[SpanAttribute] int $input): int
{
return $input * 2;
}
Standard span attributes
Every #[WithSpan] span includes these attributes from the declaration site:
| Attribute | Value |
|---|---|
code.function | Function or method name |
code.namespace | Class name (empty for standalone functions) |
code.filepath | Source file path |
code.lineno | Line number of the declaration |
Compatibility
#[WithSpan] and #[SpanAttribute] are the same attributes used by the
official
opentelemetry-php-instrumentation
extension. Applications already using that extension can enable this feature
without code changes.
Feedback
Was this page helpful?
Thank you. Your feedback is appreciated!
Please let us know how we can improve this page. Your feedback is appreciated!