Перейти к содержимому

Наблюдение за отрисовкой через OpenTelemetry

NextPDF включает встроенную инструментацию OpenTelemetry: 10 интервалов трассировки и 7 метрик на протяжении всего жизненного цикла создания Portable Document Format (PDF). Контракт гарантирует нулевые накладные расходы и нулевую настройку, когда OTel SDK отсутствует: без сбоев автозагрузки и потерь производительности. Установите software development kit (SDK), зарегистрируйте TracerProvider/MeterProvider глобально — и тот же код начнёт экспортировать данные автоматически. AttributeSanitizer работает по списку разрешений и обеспечивает соблюдение политики данных Zero-Trust, поэтому телеметрия никогда не содержит содержимого документа или персональных данных (PII).

Используйте эту страницу как PHP-ориентированное дополнение к концепциям OpenTelemetry, не зависящим от транспорта. Готовый к запуску пример и сопутствующий тест покрывают весь процесс.

Окно терминала
composer require nextpdf/core:^3

Один только Core предоставляет безопасный слой инструментации, который ничего не делает при отсутствии OTel. Чтобы экспортировать данные в реальном времени, добавьте SDK и один экспортёр.

Окно терминала
composer require open-telemetry/sdk:^1
composer require open-telemetry/exporter-otlp:^1 # or zipkin / prometheus

Используйте две точки входа:

  • TelemetryBridge — статический фасад. isAvailable() один раз проверяет наличие OTel и кэширует результат. startSpan() / endSpan() / recordMetric() сразу выполняются вхолостую, когда OTel отсутствует. Это и есть контракт нулевых накладных расходов. Когда OTel отсутствует, эти вызовы выполняются менее чем за микросекунду.
  • OpenTelemetryInterceptor — путь с интеграцией SDK. Он автоматически трассирует 10 известных интервалов, записывает 7 известных метрик и пропускает каждый атрибут через AttributeSanitizer. Он проверяет наличие SDK при создании объекта и кэширует результат. Все ссылки на классы OTel защищены проверками во время выполнения, поэтому класс загружается даже без SDK. Рекомендуемые границы BatchSpanProcessor (maxQueueSize=2048, maxExportBatchSize=512) доступны как статические методы доступа.

10 интервалов: document.build, font.resolve, html.parse, writer.serialize, image.decode, layout.pass, barcode.encode, form.build, navigation.build, attachment.embed. 7 метрик: render.duration, render.page_count, render.warnings, render.memory_peak, render.file_size, render.font_count, render.image_count.

AttributeSanitizer работает только по списку разрешений. Он пропускает ключи структурных метаданных, такие как pdf.page_count, pdf.file_size_bytes, pdf.output_profile и nextpdf.tier. Необработанный HTML, байтовые потоки PDF, base64-блоки и пути в файловой системе он безусловно отбрасывает. Это реализует два положения из рекомендаций NIST SP 800-92: телеметрия не должна содержать конфиденциальные данные, а конфиденциальность телеметрии должна быть явным средством контроля.

Описание application programming interface (API) генерируется из PHPDoc для NextPDF\Telemetry\TelemetryBridge, NextPDF\Telemetry\OpenTelemetryInterceptor и NextPDF\Telemetry\AttributeSanitizer. Ниже используются в основном TelemetryBridge::isAvailable() / startSpan() / endSpan() / recordMetric(); OpenTelemetryInterceptor::knownSpans() / knownMetrics() / maxQueueSize() / maxExportBatchSize(); и AttributeSanitizer::sanitize().

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
use NextPDF\Telemetry\TelemetryBridge;
$span = TelemetryBridge::startSpan('document.build', [
'pdf.page_count' => 1,
'nextpdf.tier' => 'core',
]);
$doc = Document::createStandalone();
$doc->addPage();
$doc->setFont('helvetica', '', 12);
$doc->cell(0, 10, 'Observed render');
$pdf = $doc->getPdfData();
TelemetryBridge::recordMetric('render.file_size', strlen($pdf), []);
TelemetryBridge::endSpan($span); // null-safe when OTel is absent
$doc->save(getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/out.pdf');

Полный пример подтверждает путь без операций с нулевыми накладными расходами, потому что выполняется при отсутствии SDK. Он задействует список разрешений санитайзера и соблюдает выходной канал тестового стенда. Стенд проверки воспроизводимости запускает этот скрипт дважды.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
use NextPDF\Telemetry\AttributeSanitizer;
use NextPDF\Telemetry\OpenTelemetryInterceptor;
use NextPDF\Telemetry\TelemetryBridge;
// Discover the surface — static, dependency-free, SDK-optional.
$spans = OpenTelemetryInterceptor::knownSpans();
$metrics = OpenTelemetryInterceptor::knownMetrics();
// Zero-Trust Data Policy: the sanitizer drops anything off the allowlist
// and anything that looks like a payload.
$sanitizer = new AttributeSanitizer();
$exported = $sanitizer->sanitize([
'pdf.page_count' => 1,
'pdf.output_profile' => 'PDF/A-4',
'document.raw_html' => '<html><body>secret</body></html>', // dropped
'source.path' => '/var/secret/invoice.pdf', // dropped
]);
$span = TelemetryBridge::startSpan('document.build', [
'pdf.page_count' => 1,
'nextpdf.tier' => 'core',
]);
$doc = Document::createStandalone();
$doc->setTitle('Observability demo');
$doc->addPage();
$doc->setFont('helvetica', 'B', 16);
$doc->cell(0, 12, 'Observe rendering with OpenTelemetry', newLine: true);
$pdf = $doc->getPdfData();
TelemetryBridge::recordMetric('render.page_count', 1, []);
TelemetryBridge::recordMetric('render.file_size', strlen($pdf), []);
TelemetryBridge::endSpan($span);
$doc->save(getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/out.pdf');
fwrite(STDERR, sprintf(
"spans=%d metrics=%d otel_available=%s sanitized_keys=%s\n",
count($spans),
count($metrics),
TelemetryBridge::isAvailable() ? 'yes' : 'no',
implode(',', array_keys($exported)),
));
  • Телеметрия никогда не нарушает отрисовку. И мост, и перехватчик поглощают собственные внутренние ошибки. Неправильно настроенный экспортёр ухудшает наблюдаемость, но не выходной PDF. Не оборачивайте код отрисовки в блок catch, который трактует сбой телеметрии как сбой отрисовки.
  • endSpan(null) безопасен. startSpan() возвращает null, когда OTel отсутствует, а endSpan() принимает null как операцию без эффекта. Всегда используйте их в паре и никогда не выполняйте ветвление по возвращаемому значению.
  • Для метрик требуется зарегистрированный MeterProvider. Если зарегистрирован только TracerProvider, интервалы экспортируются, но метрики молча пропускаются. Метрики носят рекомендательный характер. Для полного покрытия зарегистрируйте оба провайдера.
  • Санитайзер работает только по списку разрешений. Новый ключ атрибута, которого нет в списке разрешений, не будет экспортирован. Это поведение является преднамеренным. Расширьте список разрешений в движке и не обходите санитайзер.
  • Распространение контекста трассировки W3C Trace Context. Межсервисное распространение трассировки использует заголовки W3C Trace Context traceparent/tracestate. Их обрабатывают пропагаторы OTel SDK, а не NextPDF. Рекомендации W3C Trace Context нет в корпусе проверки, поэтому это замечание о распространении не подтверждено RAG и приведено как руководство по интеграции, а не как нормативное утверждение. См. боковую панель.
  • Оговорка о воспроизводимости. Отрисовка создаёт документ, у которого /ID и дата изменения создаются заново при каждом сохранении (ISO 32000-2 §14.3). Захваченный PDF сравнивается с профилем semantic, который охватывает только структурное абстрактное синтаксическое дерево (AST) и метаданные.
  • Путь без OTel: isAvailable() кэшируется после первого вызова. Последующие вызовы интервалов и метрик выполняют одну булеву проверку и сразу возвращаются. Инструментированный пример полностью выполняется при отсутствии SDK.
  • С OTel: границы BatchSpanProcessor (maxQueueSize=2048, maxExportBatchSize=512) ограничивают объём памяти при устойчивой нагрузке, а экспорт остаётся вне горячего пути.
  • Параметр performance_budget (wall_ms: 3000, peak_mb: 128) ограничивает прогон тестового стенда, а не произвольные документы.
  • Этот рецепт закрывает пункт #33 из списка пробелов §4.3. Раньше существовала только концептуальная страница в стиле MCP, без PHP-ориентированного примера. Были созданы новый файл examples/33-opentelemetry-observability.php и сопутствующий ему tests/Cookbook/Php/ObserveWithOpenTelemetryRecipeTest.php.
  • Телеметрия не должна содержать содержимое документа или PII. Список разрешений AttributeSanitizer обеспечивает соблюдение этого правила на уровне кода. Необработанный HTML, потоки PDF, base64-блоки и пути в файловой системе отбрасываются. Это соответствует рекомендациям NIST SP 800-92 по недопущению конфиденциальных данных в журналах и телеметрии, а также по защите конфиденциальности телеметрии.
  • Атрибуты, которые вы добавляете сами, по-прежнему подчиняются списку разрешений. Вы всё равно отвечаете за то, чтобы не внести конфиденциальные значения под разрешённым ключом. Например, не помещайте идентификатор пользователя в pdf.output_profile.
  • Диагностические сведения передаются структурированными ключами, а не произвольной полезной нагрузкой. Это тот же принцип, который PSR-3 §1.2 применяет к контексту журнала.
ПоложениеСпецификацияРазделreference_id (идентификатор ссылки)
Телеметрия не должна содержать конфиденциальные данные; требуется надлежащая обработка PII.NIST SP 800-92§3
Конфиденциальность телеметрии и журналов должна быть явным средством контроля.NIST SP 800-92§3
Подробности передаются структурированными ключами контекста, а не произвольной полезной нагрузкой.PSR-3§1.2
Выходные /ID и даты создаются заново при каждом сохранении → профиль semantic.ISO 32000-2§14.3

Этот рецепт описывает инженерное поведение инструментации. Он не утверждает наличия какой-либо сертификации соответствия. Ссылки на NIST SP 800-92 обосновывают проектный принцип “без содержимого в телеметрии”, а не утверждение о соответствии.