Exceptions
The bundle automatically captures unhandled exceptions and records them on the request span. To report caught exceptions or add context to errors, use the OpenTelemetry PHP API directly.
Recording an Exception on the Current Span
When you catch an error but want it reported to Traceway, record it as an event on the active span:
use OpenTelemetry\API\Trace\Span;
use OpenTelemetry\API\Trace\StatusCode;
try {
$this->paymentGateway->charge($order);
} catch (\Throwable $e) {
$span = Span::getCurrent();
$span->recordException($e);
$span->setStatus(StatusCode::STATUS_ERROR, $e->getMessage());
throw $e;
}recordException adds an exception event to the span with the type, message, and stack trace. Traceway extracts these events and creates Issues from them.
Adding Attributes to Exceptions
Add context by setting span attributes before or after recording the exception:
use OpenTelemetry\API\Trace\Span;
use OpenTelemetry\API\Trace\StatusCode;
$span = Span::getCurrent();
$span->setAttribute('user.id', $userId);
$span->setAttribute('order.id', $orderId);
try {
$this->processOrder($orderId);
} catch (\Throwable $e) {
$span->recordException($e, [
'order.status' => 'failed',
'retry.count' => $retryCount,
]);
$span->setStatus(StatusCode::STATUS_ERROR, $e->getMessage());
throw $e;
}The additional attributes passed to recordException are attached to the exception event itself.
Capturing Exceptions in Services
For exceptions in services outside of a controller, get the current span from context:
namespace App\Service;
use OpenTelemetry\API\Trace\Span;
use OpenTelemetry\API\Trace\StatusCode;
class PaymentService
{
public function processPayment(string $customerId, float $amount): void
{
$span = Span::getCurrent();
try {
$this->gateway->charge($customerId, $amount);
} catch (\Throwable $e) {
$span->recordException($e, [
'customer.id' => $customerId,
'payment.amount' => $amount,
]);
$span->setStatus(StatusCode::STATUS_ERROR, $e->getMessage());
throw $e;
}
}
}Custom Error Types
Custom exception classes work the same way. The exception type name appears in the Traceway dashboard:
class InsufficientFundsException extends \RuntimeException
{
public function __construct(
public readonly string $accountId,
public readonly float $requested,
public readonly float $available,
) {
parent::__construct("Insufficient funds: requested {$requested}, available {$available}");
}
}
try {
$this->withdraw($accountId, $amount);
} catch (InsufficientFundsException $e) {
$span = Span::getCurrent();
$span->recordException($e, [
'account.id' => $e->accountId,
'amount.requested' => $e->requested,
'amount.available' => $e->available,
]);
$span->setStatus(StatusCode::STATUS_ERROR, $e->getMessage());
}