Я использую OpenTelemetry для оснащения приложения Laravel и пытаюсь создать корневые диапазоны для консольных команд (хотя Laravel Artisan). Я заметил, что структура отправляет события CommandStarting и CommandFinished при запуске и завершении команды, которую я пытаюсь прослушать, чтобы построить свой корневой диапазон:
<?php
namespace App\OpenTelemetry\Instrumentation;
use Illuminate\Console\Events\CommandFinished;
use Illuminate\Console\Events\CommandStarting;
use OpenTelemetry\API\Trace\Span;
use OpenTelemetry\API\Trace\SpanKind;
use OpenTelemetry\API\Trace\TracerInterface;
use OpenTelemetry\Context\Context;
class ArtisanInstrumentation implements Instrumentation
{
public function register(): void
{
app('events')->listen(CommandStarting::class, [$this, 'recordStartOfCommand']);
app('events')->listen(CommandFinished::class, [$this, 'recordEndOfCommand']);
}
public function recordStartOfCommand(CommandStarting $event): void
{
/** @var TracerInterface $tracer */
$tracer = app(TracerInterface::class);
$span = $tracer
->spanBuilder($event->command)
->setSpanKind(SpanKind::KIND_SERVER)
->startSpan();
$span->activate();
}
public function recordEndOfCommand(CommandFinished $event): void
{
$scope = Context::storage()->scope();
$span = Span::fromContext($scope->context());
$scope->detach();
$span->end();
}
}
Как вы можете видеть, я пытаюсь запустить интервал, когда команда начинает выполняться, и завершить его позже, когда команда завершится. Однако из приведенного выше кода я получаю следующую ошибку об отсутствующем вызове для отсоединения области:
Scope: missing call to Scope::detach() for scope #3776, created
at OpenTelemetry.Context.Context.activate(Context.php:87)
at OpenTelemetry.API.Trace.Span.activate(Span.php:51)
at App.OpenTelemetry.Instrumentation.ArtisanInstrumentation.recordStartOfCommand(ArtisanInstrumentation.php:32)
Промежуток, который я получаю с помощью Span::fromContext($scope->context()), является правильным, что я подтвердил, выгрузив его и проверив его имя. Но вызов detach() на области явно не отсоединяет ее должным образом.
Я думаю, что я просто немного потерялся в генерировании того, как вообще работают области видимости и как получить область видимости диапазона где-то еще в кодовой базе. Все примеры в документации OpenTelemetry показывают использование области в контексте, в котором вы ее создали, а не динамическое получение ее из несвязанного кода.
Методом проб и ошибок я заставил это работать, сохранив результат $span->activate() в свойстве класса, а затем деактивировав его в методе recordEndOfCommand следующим образом:
$scope = Context::storage()->scope();
$span = Span::fromContext($scope->context());
$this->scope->detach();
$span->end();
но я не уверен, предпочтительнее ли это извлечения области из контекста?






Вы сталкиваетесь с предупреждением от DebugScope, функции OpenTelemetry, которая активна в PHP с поддержкой утверждений, которая существует, чтобы помочь вам определить, когда Scope не отсоединен должным образом (чего нет в recordStartOfCommand - он сразу выходит за рамки когда эта функция завершается, получает GC и вызывает ошибку, которую вы видите). Вы можете отключить эту функцию с помощью переменной среды OTEL_PHP_DEBUG_SCOPES_DISABLED=true или отключив утверждения PHP.
Если вы не хотите отслеживать область действия между функциями pre и post, вы можете управлять этим следующим образом:
public function recordStartOfCommand(CommandStarting $event): void
{
$tracer = app(TracerInterface::class);
$span = $tracer
->spanBuilder($event->command)
->setSpanKind(SpanKind::KIND_SERVER)
->startSpan();
// do not `activate()` the span, but instead:
Context::storage()->attach($span->storeInContext(Context::getCurrent()));
}
public function recordEndOfCommand(CommandFinished $event): void
{
$scope = Context::storage()->scope();
$scope->detach();
Span::fromContext($scope->context())->end();
}
Спасибо, это работает хорошо, и я думаю, что начинаю понимать, как работает контекст, изучая вызовы методов, которые вы здесь даете.
Вы пробовали использовать автоинтрументацию? Команды перехвата должны быть описаны здесь: github.com/open-telemetry/opentelemetry-php-contrib/blob/main/…