Telemetry: мост OpenTelemetry и no-op-резерв
Модуль Telemetry — это необязательный мост движка к OpenTelemetry SDK (OTel). Когда SDK установлен, модуль формирует span и метрики с очищенными атрибутами. Когда SDK отсутствует, полный набор no-op-объектов трассировщика и измерителя оставляет вызовы инструментирования корректными и практически бесплатными. Инструментирование можно безопасно оставлять в коде.
Установка
Заголовок раздела «Установка»composer require nextpdf/core:^3Концептуальный обзор
Заголовок раздела «Концептуальный обзор»Проектная цель — наблюдаемость с нулевыми затратами, когда SDK отсутствует. Горячие пути движка вызывают трассировщик и измеритель без предварительной проверки. Делают ли эти вызовы реальную работу, зависит от среды выполнения, а не от условной проверки в каждом месте вызова.
OpenTelemetryInterceptor — это мост. isAvailable() сообщает, присутствует ли OTel SDK. startSpan(string $name, array $attributes = []) / endSpan(?object $span) оборачивают трассируемую операцию, а recordMetric() записывает значение счётчика или датчика. Когда OTel отсутствует, перехватчик сообщает, что он недоступен, и вызовы остаются бездействующими. TelemetryBridge связывает перехватчик с точками наблюдения движка.
AttributeSanitizer — это уровень защиты. sanitize(array $attributes) очищает карту атрибутов, прежде чем она покинет процесс. Атрибуты телеметрии — распространённый канал случайной утечки персональных данных (PII), поэтому очистка является частью контракта, а не дополнением. Очиститель, перехватчик и мост помечены как @since 2.3.0.
NullTracer, NullSpanBuilder, NullSpan, NullMeter, NullCounter и NullHistogram — это no-op-резерв. Они соответствуют формам вызовов, которые предоставляет OTel SDK: spanBuilder(), setAttribute() (с цепочкой вызовов), startSpan(), end(), createHistogram(), createUpDownCounter(), add() и record(). Они ничего не делают. Поскольку резерв полный, инструментированный код не ветвится по доступности; он вызывает трассировщик, а no-op поглощает вызов.
Поверхность API
Заголовок раздела «Поверхность API»| Класс | Ключевые члены | Роль |
|---|---|---|
OpenTelemetryInterceptor | isAvailable(), startSpan(), endSpan(), recordMetric() | Мост OTel для span и метрик (@since 2.3.0) |
TelemetryBridge | связь с движком | Связывает перехватчик с точками наблюдения движка (@since 2.3.0) |
AttributeSanitizer | sanitize(array $attributes): array | Очищает атрибуты для защиты от утечки PII (@since 2.3.0) |
NullTracer | spanBuilder(string $name): NullSpanBuilder | No-op-трассировщик |
NullSpanBuilder | setAttribute(), startSpan(): NullSpan | No-op-построитель span (с цепочкой вызовов) |
NullSpan | end() | No-op-span (пустой span) |
NullMeter | createHistogram(), createUpDownCounter() | No-op-измеритель |
NullCounter / NullHistogram | add(), record() | No-op-инструменты |
Выполните composer docs:generate-api-php -- --module=Telemetry, чтобы создать полную таблицу PHPDoc.
Пример кода — быстрый старт
Заголовок раздела «Пример кода — быстрый старт»Исходный код: examples/33-opentelemetry-observability.php.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Telemetry\OpenTelemetryInterceptor;
$otel = new OpenTelemetryInterceptor(/* optional OTel tracer/meter */);
$span = $otel->startSpan('pdf.render', ['doc.pages' => 12]);// ... render work ...$otel->endSpan($span);
$otel->recordMetric('pdf.render.bytes', 482_113, ['profile' => 'pdfa4']);Когда OTel SDK отсутствует, каждый из приведённых выше вызовов является no-op. Код остаётся тем же, а затраты равны нулю.
Пример кода — продакшен
Заголовок раздела «Пример кода — продакшен»Оберните операцию отрисовки и передайте очищенные атрибуты, чтобы метаданные, предоставленные вызывающей стороной, не могли попасть в span.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Telemetry\AttributeSanitizer;use NextPDF\Telemetry\OpenTelemetryInterceptor;
final readonly class InstrumentedRenderer{ public function __construct( private OpenTelemetryInterceptor $otel, private AttributeSanitizer $sanitizer, ) {}
/** * @param callable():string $render Returns the rendered PDF bytes. * @param array<string, mixed> $attributes Caller-supplied span attributes. */ public function render(callable $render, array $attributes): string { $span = $this->otel->startSpan('pdf.render', $this->sanitizer->sanitize($attributes));
try { return $render(); } finally { $this->otel->endSpan($span); } }}Граничные случаи и подводные камни
Заголовок раздела «Граничные случаи и подводные камни»- No-op-резерв является полным по замыслу. Не защищайте инструментирование вызовом
isAvailable()“чтобы сэкономить работу”. No-op уже почти ничего не стоит, а такая защита добавляет именно то ветвление, которое этот подход устраняет. - Всегда пропускайте атрибуты, предоставленные вызывающей стороной, через
AttributeSanitizer, прежде чем присоединять их к span или метрике. Атрибуты телеметрии — это канал случайной утечки PII. endSpan(null)допустимо: span со значением null — это случай no-op. Сопоставляйте каждый вызовstartSpan()с вызовомendSpan()в блокеfinally.NullSpanBuilder::setAttribute()возвращаетstaticдля цепочки вызовов. В режиме no-op цепочка бездействует по замыслу.- Профиль воспроизводимости —
structural: в span есть временные метки и идентификаторы трассировки, поэтому два запуска различаются в этих полях.
Производительность
Заголовок раздела «Производительность»Когда OTel отсутствует, затраты сводятся к вызову метода no-op и практически равны нулю. Когда OTel присутствует, основные затраты определяет OTel SDK; мост добавляет очистку атрибутов, линейную по их количеству. Значение performance_budget в 1500 ms по времени / 64 MB пиковой памяти — это эталонный бюджет движка, а не соглашение об уровне обслуживания (SLA) телеметрии.
Примечания по безопасности
Заголовок раздела «Примечания по безопасности»Телеметрия — это поверхность вывода данных. AttributeSanitizer не допускает попадания секретов и PII в span и метрики. Считайте очистку обязательной для любого атрибута, на который влияет вызывающая сторона; это обязательство проекта по безопасной телеметрии. Экспортёр OTel отправляет данные на внешний бэкенд, и этот бэкенд является границей доверия. Настраивайте его конечную точку и учётные данные через менеджер секретов, а не через конфигурацию в репозитории. Исходите из того, что данные span и метрик попадают в приёмник логов, и очищайте их соответствующим образом. См. модель угроз движка в /modules/core/security/.
Соответствие
Заголовок раздела «Соответствие»Этот модуль не делает нормативных заявлений о соответствии спецификации Portable Document Format (PDF). Он связывается с моделью данных OpenTelemetry — внешней спецификацией наблюдаемости, а не пунктом спецификации PDF. No-op-резерв отражает поверхность API OpenTelemetry, чтобы инструментированный код оставался переносимым. Это свойство совместимости API, а не заявление о соответствии PDF. Соответствие движка проверяется с помощью наборов oracle и golden, описанных в /modules/core/conformance/.
См. также
Заголовок раздела «См. также»- Модуль Observability — более широкая поверхность состояния среды выполнения.
- Модуль Performance — диагностика памяти, которая сочетается с телеметрией.
- Contracts / Observability — контракты структурированных исключений и деградации.
- Модель безопасности движка