Telemetry: ponte com OpenTelemetry e fallback no-op
Visão geral
Seção intitulada “Visão geral”O módulo Telemetry é a ponte opcional entre o engine e o software development kit (SDK) do OpenTelemetry (OTel). Quando o SDK está instalado, ele emite spans e métricas com atributos sanitizados. Quando o SDK está ausente, um conjunto completo de objetos no-op de tracer e meter mantém as chamadas de instrumentação válidas e praticamente sem custo. Você pode manter a instrumentação no caminho do código com segurança.
Instalação
Seção intitulada “Instalação”composer require nextpdf/core:^3Visão conceitual
Seção intitulada “Visão conceitual”O objetivo do projeto é oferecer observabilidade com custo zero quando o SDK está ausente. Os caminhos críticos do engine chamam um tracer e um meter sem verificação prévia. Se essas chamadas executam trabalho depende do runtime, não de um condicional em cada ponto de chamada.
OpenTelemetryInterceptor é a ponte. isAvailable() informa se o SDK do OTel está presente. startSpan(string $name, array $attributes = []) / endSpan(?object $span) delimitam uma operação rastreada, e recordMetric() registra um valor de contador ou gauge. Quando o OTel está ausente, o interceptor informa indisponibilidade, e as chamadas ficam inertes. TelemetryBridge conecta o interceptor aos pontos de observação do engine.
AttributeSanitizer é a camada de segurança. sanitize(array $attributes) limpa o mapa de atributos antes que ele saia do processo. Atributos de telemetria são um canal acidental comum para informações de identificação pessoal (PII), portanto a sanitização faz parte do contrato; não é um complemento. O sanitizador, o interceptor e a ponte são @since 2.3.0.
NullTracer, NullSpanBuilder, NullSpan, NullMeter, NullCounter e NullHistogram são o fallback no-op. Eles correspondem aos formatos de chamada expostos pelo SDK do OTel: spanBuilder(), setAttribute() (encadeável), startSpan(), end(), createHistogram(), createUpDownCounter(), add() e record(). Eles não fazem nada. Como o fallback é completo, o código instrumentado não ramifica conforme a disponibilidade; ele chama o tracer, e o no-op absorve a chamada.
Superfície da API
Seção intitulada “Superfície da API”| Classe | Membros principais | Função |
|---|---|---|
OpenTelemetryInterceptor | isAvailable(), startSpan(), endSpan(), recordMetric() | Ponte de spans e métricas do OTel (@since 2.3.0) |
TelemetryBridge | integração com o engine | Conecta o interceptor aos pontos de observação do engine (@since 2.3.0) |
AttributeSanitizer | sanitize(array $attributes): array | Limpa atributos para proteger PII (@since 2.3.0) |
NullTracer | spanBuilder(string $name): NullSpanBuilder | Tracer no-op |
NullSpanBuilder | setAttribute(), startSpan(): NullSpan | Span builder no-op (encadeável) |
NullSpan | end() | Span no-op |
NullMeter | createHistogram(), createUpDownCounter() | Meter no-op |
NullCounter / NullHistogram | add(), record() | Instrumentos no-op |
Execute composer docs:generate-api-php -- --module=Telemetry para gerar a tabela completa de PHPDoc.
Exemplo de código — Início rápido
Seção intitulada “Exemplo de código — Início rápido”Fonte: 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']);Quando o SDK do OTel está ausente, toda chamada acima é um no-op. O código permanece idêntico, e o custo é zero.
Exemplo de código — Produção
Seção intitulada “Exemplo de código — Produção”Envolva uma operação de renderização com atributos sanitizados para impedir que metadados fornecidos pelo chamador vazem para um 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); } }}Casos extremos e armadilhas
Seção intitulada “Casos extremos e armadilhas”- O fallback no-op é completo por design. Não proteja a instrumentação com
isAvailable()“para economizar trabalho”. O no-op já não tem custo, e a proteção adiciona a ramificação que este design remove. - Sempre passe os atributos fornecidos pelo chamador pelo
AttributeSanitizerantes de anexá-los a um span ou métrica. Atributos de telemetria são um canal acidental para PII. endSpan(null)é válido: um span nulo é o caso no-op. Pareie todostartSpan()com umendSpan()em umfinally.NullSpanBuilder::setAttribute()retornastaticpara encadeamento. Sob o no-op, a cadeia é inerte por design.- O perfil de reprodutibilidade é
structural: os spans carregam timestamps e identificadores de trace, portanto duas execuções diferem nesses campos.
Desempenho
Seção intitulada “Desempenho”Quando o OTel está ausente, o custo é uma chamada de método para um no-op, praticamente sem custo. Quando o OTel está presente, o custo vem do SDK do OTel; a ponte adiciona a sanitização de atributos, que é linear em relação à quantidade de atributos. O performance_budget de 1500 ms de wall / 64 MB de pico é o orçamento de referência do engine, não um acordo de nível de serviço (SLA) para telemetria.
Notas de segurança
Seção intitulada “Notas de segurança”A telemetria é uma superfície de saída de dados. O AttributeSanitizer mantém segredos e PII fora dos spans e métricas. Trate a sanitização como obrigatória para qualquer atributo influenciado pelo chamador; essa é a obrigação de telemetria segura do projeto. O exporter do OTel envia dados para um backend externo, e esse backend é uma fronteira de confiança. Configure o endpoint e as credenciais a partir de um gerenciador de segredos, não de uma configuração versionada. Suponha que dados de span e métrica cheguem a um destino de log e limpe-os adequadamente. Consulte o modelo de ameaças do engine em /modules/core/security/.
Conformidade
Seção intitulada “Conformidade”Este módulo não faz nenhuma afirmação normativa sobre a especificação Portable Document Format (PDF). Ele faz a ponte com o modelo de dados do OpenTelemetry, uma especificação externa de observabilidade, não com uma cláusula do PDF. O fallback no-op espelha a superfície da application programming interface (API) do OpenTelemetry para que o código instrumentado permaneça portável. Isso é uma propriedade de compatibilidade de API, não uma declaração de conformidade com o PDF. A conformidade do engine é validada pelas suítes de oráculo e golden descritas em /modules/core/conformance/.
Veja também
Seção intitulada “Veja também”- Módulo Observability — superfície mais ampla de estado em runtime.
- Módulo Performance — diagnósticos de memória que se combinam com telemetria.
- Contracts / Observability — contratos de exceção estruturada e degradação.
- Modelo de segurança do engine