Telemetry:OpenTelemetry 桥接与无操作回退
Telemetry 模块是引擎的可选 OpenTelemetry 桥接层。安装 OpenTelemetry SDK 后,它会发出带有已清理属性的 span 与 metric。若未安装,完整的一组无操作 tracer 与 meter 对象会让检测调用保持有效且零成本。因此,检测代码始终可以安全地留在执行路径中。
composer require nextpdf/core:^3概念总览
标题为“概念总览”的章节设计目标是实现「不存在时零成本」的可观测性。引擎的热路径会无条件调用 tracer 与 meter。这些调用是否实际执行工作,取决于运行时,而不是每个调用点上的条件判断。
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 就是无操作回退。它们实现了与 OTel SDK 暴露的相同 API 形状——spanBuilder()、setAttribute()(可链式调用)、startSpan()、end()、createHistogram()、createUpDownCounter()、add()、record()——但本身什么也不做。由于回退是完整的,受检测的代码无需根据可用性做分支判断;它可以直接调用 tracer,由无操作回退吸收这次调用。
API 接口
标题为“API 接口”的章节| 类 | 主要成员 | 角色 |
|---|---|---|
OpenTelemetryInterceptor | isAvailable(), startSpan(), endSpan(), recordMetric() | OTel span/metric 桥接(@since 2.3.0) |
TelemetryBridge | 引擎接线 | 将拦截器连接到观测点(@since 2.3.0) |
AttributeSanitizer | sanitize(array $attributes): array | PII 安全的属性清洗器(@since 2.3.0) |
NullTracer | spanBuilder(string $name): NullSpanBuilder | 无操作 tracer |
NullSpanBuilder | setAttribute(), startSpan(): NullSpan | 无操作 span builder(可链式调用) |
NullSpan | end() | 无操作 span |
NullMeter | createHistogram(), createUpDownCounter() | 无操作 meter |
NullCounter / NullHistogram | add(), record() | 无操作仪器 |
运行 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 不存在时,上面的每个调用都是无操作——代码保持不变,成本为零。
代码示例——生产环境
标题为“代码示例——生产环境”的章节使用已清理的属性包裹一次渲染,防止调用方提供的元数据泄漏到 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); } }}边界情况与陷阱
标题为“边界情况与陷阱”的章节- 无操作回退按设计就是完整的。不要为了「省下工作」而用
isAvailable()防护检测代码。无操作本来就没有成本,这层防护反而会新增一个分支;设计目标正是消除这个分支。 - 务必先让调用方提供的属性经过
AttributeSanitizer,再进入 span 或 metric。遥测属性是意外 PII 泄漏的通道。 endSpan(null)是有效的——null span 表示无操作情形。每一次startSpan()都应搭配一次位于finally中的endSpan()。NullSpanBuilder::setAttribute()会返回static以支持链式调用;在无操作下,这条调用链是惰性的,这是有意设计,并非缺陷。- 可重现性配置为
structural:span 会带有时间戳与 trace id,因此两次运行在这些字段上的值会不同。
当 OTel 不存在时,成本只是进入一次无操作方法调用——实际等同于零。当它存在时,成本来自 OTel SDK,而非本模块;桥接层只额外增加属性清理,其成本与属性数量成线性关系。1500 ms 墙钟时间/64 MB 峰值的 performance_budget 是引擎参考值,而不是遥测 SLA。
安全注意事项
标题为“安全注意事项”的章节遥测是一个数据出口面。AttributeSanitizer 是阻止机密与 PII 进入 span 和 metric 的控制机制。对于任何受调用方影响的属性,都应将清理视为必需;这是本项目的安全遥测义务。OTel 导出器会把数据发送到外部后端,而该后端边界就是一道信任边界。请从密钥管理器配置其端点与凭据,不要使用已提交(committed)的配置文件。应假设 span 与 metric 数据会抵达某个日志接收端,并据此清洗。请参阅 /modules/core/security/ 中的引擎威胁模型。
符合性
标题为“符合性”的章节本模块不会作出任何关于 PDF 规范的规范性声明。它桥接的是 OpenTelemetry 数据模型;这是外部可观测性规范,而不是 PDF 条款。无操作回退会镜像 OTel API 接口,使受检测代码具备可移植性;这是一种 API 兼容性特性,而不是 PDF 符合性声明。引擎符合性由 /modules/core/conformance/ 中所述的 oracle 与 golden 测试套件验证。
另请参阅
标题为“另请参阅”的章节- Observability 模块——更广泛的运行时状态面。
- Performance 模块——与遥测搭配的内存诊断。
- Contracts / Observability——结构化异常与降级契约。
- 引擎安全模型