依赖扩展与观测
July 29, 2026 · View on GitHub
可选 extras
| extra | 用途 |
|---|---|
htmlkit | 实验性 HTMLKit/litehtml Provider |
playwright | Playwright Provider |
takumi | Takumi Provider |
pillow | 独立 Pillow RasterScene Capability |
skia | 独立 Skia RasterScene Capability |
filehost | 为内置 HTTP asset publisher 增加 py-machineid 守卫标识来源 |
sentry | Sentry spans 与 metrics |
prometheus | Prometheus metrics |
all | 安装上述全部能力,包括具有平台限制的 Skia |
uv add "nonebot-plugin-htmlrender[playwright,sentry,prometheus]>=0.8.0,<0.9"
HTMLKit/Playwright/Takumi 的引擎库缺失会形成可诊断的 Provider availability;插件不会在 import 时无条件加载所有引擎。选择 HTMLKit 时,bootstrap 会在 NoneBot
startup 前只加载其对应插件,以注册上游 Fontconfig 初始化 hook。filehost transport由 htmlrender 自有的 HostedAssetStore 提供,bootstrap 会在 FastAPI ASGI host启动前安装固定路由和请求头守卫,不再加载第二个 NoneBot filehost 插件。filehost
extra 只提供 py-machineid 作为默认守卫值的机器标识来源;未安装时会使用内置回退,也可以显式配置 request_header_value。
Pillow/Skia 只在 render.graphics.backends 显式配置后加载,并形成独立 typed
Capability,不进入 Provider discovery。Skia 没有 sdist/musllinux wheel,并要求manylinux_2_28、macOS 11+ 或受支持的 Windows wheel;Linux 还必须提供libEGL.so.1、libGL.so.1 与 libexpat.so.1 等运行库。Alpine/musl 或旧 glibc 镜像不要安装 skia 或 all extra;完整平台矩阵与安装命令见 Skia 后端。
HTMLKit 当前精确锁定 nonebot-plugin-htmlkit==0.1.0rc5。它不引入 Playwright 或Pillow,但属于 prerelease,平台 wheel、选项限制和 Fontconfig 生命周期见HTMLKit 配置。
开启观测
render:
provider: playwright
observability:
sentry: true
prometheus: true
完整路径为 render.observability.sentry 与render.observability.prometheus,默认均为 false。开关启用后 bootstrap 会自动尝试 require 对应 NoneBot 集成插件;未安装或加载失败只记录 warning,不会让渲染运行时启动失败。
htmlrender 只负责产生 span 与指标,不负责重复配置 exporter:Sentry 的 DSN、采样、transport 和 release 等设置仍由 nonebot_plugin_sentry/Sentry SDK 管理;Prometheus
registry 与 HTTP endpoint 仍由 nonebot_plugin_prometheus 管理。两个 NoneBot 插件会在 htmlrender 导入阶段按开关提前加载,使它们来得及注册 startup hook;不要等到第一次渲染后才动态加载集成。
插装边界
composition 为每个 Application 创建 observer,并注入 Provider、Graphics backend、Resource Service、template compiler 与 Capability。Sentry 和 Prometheus 同时开启时,同一个 observer 将一次操作扇出到两个 exporter,不引入第二套渲染生命周期或参数契约;两者都关闭时 composition 直接注入 no-op observer。
| 调用面 | 观测范围 | operation |
|---|---|---|
| 通用渲染 | Provider executor 的完整调用 | playwright.html_render.rasterize_html、takumi.rasterize_html、htmlkit.rasterize_html |
| Provider 生命周期 | runtime acquisition、启动与关闭 | acquisition 使用内部兼容名称;启动与关闭为 render.startup、render.shutdown |
| Provider runtime | 引擎创建、连接与释放子步骤 | playwright.open_runtime、playwright.open_session、takumi.open_runtime、takumi.close_runtime |
| Graphics | draw 与 encode 的完整调用 | graphics.pillow.render_scene、graphics.skia.render_scene |
| Playwright 原生访问 | async with app.extensions.playwright.page() 或 .browser() 的完整租约 | playwright.native.page、playwright.native.browser |
| Takumi 托管 API | app.extensions.takumi.api() 返回对象的每个异步方法 | takumi.api.* |
| Takumi 原生访问 | async with app.extensions.takumi.renderer() 的完整租约 | takumi.native.renderer |
Playwright 的 Page.goto()、Locator.screenshot() 等调用位于playwright.native.page span 内,但 htmlrender 不代理 Playwright 对象,也不会为每个上游方法再建立一层 operation。若 Playwright 自身另有 tracing,它可以在同一调用中独立工作。Takumi 的托管 API 可以在不牺牲上游类型的情况下按方法插装;直接取得原生Renderer 时则与 Playwright 相同,只观测整个租约,不猜测或拦截其内部调用。原生上下文内未被调用方捕获的上游异常会把该上下文标记为失败,但异常类型本身保持不变;调用方在上下文内部捕获并吞掉的异常不会被 observer 推断为失败。
生成的 operation span 总会包含 render.backend,结束时补充 render.status(ok 或error)与 render.duration_seconds。具体调用还可能提供稳定的低基数属性,例如render.format、render.access 与 render.cache_hit。
Sentry 插装
存在当前 Sentry span 时,htmlrender 创建 child span;否则创建以 operation 为 op和 name 的 root transaction,并把 transaction source 设为 task。是否实际采样、如何上传完全遵循 Sentry SDK 配置。Sentry SDK 没有可用 metrics surface 时,trace仍可工作,指标则安全跳过。
生成的失败 span 总会附加 error.type。若异常属于 RenderingError,还会附加error.message、error.message_truncated、error.cause_types 与error.causes_truncated;这些值来自有界错误快照,不包含 native 异常对象。这里仅标记 span,不额外把同一个异常捕获为 Sentry event。
Prometheus 插装
Prometheus collector 在首次使用时按进程惰性创建并复用,避免重复注册。操作 counter与 duration histogram 使用相同的 op、backend、status 标签。当 Sentry span提供 trace ID 时,htmlrender 会尽力把 trace_id exemplar 同时写入 counter 与histogram;客户端版本或存储后端不支持 exemplar 时自动回退为普通观测。
/metrics 路由、registry 选择和抓取配置属于 nonebot_plugin_prometheus,不是htmlrender 的公共接口。启用 htmlrender 的 Prometheus 开关只表示向该集成注册并更新collector。
稳定指标 schema
| 含义 | Prometheus | 类型与 labels | Sentry | 类型与 tags |
|---|---|---|---|---|
| 操作次数 | nonebot_htmlrender_operations_total | counter;op、backend、status | nonebot.htmlrender.count | count;op、backend、status |
| 操作耗时 | nonebot_htmlrender_duration_seconds | histogram;op、backend、status | nonebot.htmlrender.duration | distribution(second);op、backend、status |
| 缓存事件 | nonebot_htmlrender_cache_events | counter;cache、event | nonebot.htmlrender.cache.events | count;cache、event |
| 缓存条目 | nonebot_htmlrender_cache_entries | gauge;cache | nonebot.htmlrender.cache.entries | gauge;cache |
| 缓存驻留字节 | nonebot_htmlrender_cache_resident_bytes | gauge;cache | nonebot.htmlrender.cache.resident_bytes | gauge(byte);cache |
当前 cache 值由 composition 固定为 resource、template_environment、filehost或 takumi_compiled;event 使用 hit、miss、load、wait 与 eviction 中适用于该缓存的子集。仅 byte-weighted cache 会更新 resident_bytes。
指标表示的具体缓存层并不相同:template_environment entries 是 Environment 数量,不包含内层 compiled templates;filehost entries 是 publisher mapping;takumi_compiled 的 resident bytes 是输入 source weight,不是 native heap 精确值。按现象选择指标和调优动作见缓存组件、失效与调优。
操作指标只使用稳定的 operation、provider identity 与 status 维度。当前导出schema 中 provider identity 的 label 名保留为 backend;它是兼容性字段,不是公共架构概念。路径、URL、HTML、模板变量、字体名、digest、资源内容、错误消息和 cause
type 都不会进入指标标签。
常用 PromQL 示例:
sum by (op, backend, status) (
rate(nonebot_htmlrender_operations_total[5m])
)
histogram_quantile(
0.95,
sum by (le, op, backend) (
rate(nonebot_htmlrender_duration_seconds_bucket[5m])
)
)
多进程部署会由每个 worker 持有自己的 registry、cache gauge 与运行时;聚合规则应以 Prometheus 抓取到的实例标签区分进程,不能把单进程 cache gauge 当作集群总量。
故障隔离
observer 由 composition 注入。Sentry/Prometheus 写入失败只降低观测质量,不会替换成功的渲染结果,也不会覆盖原始业务异常。自定义 Provider 不应自行创建 exporter;使用 ProviderDependencies 提供的 operation/cache observer,并为operation 与属性选择固定、低基数的值。
bootstrap 发现已启用的集成缺失或加载失败时会记录 warning;SDK API 不兼容、collector 注册或写入失败会记录 htmlrender.telemetry warning。无可用 Sentry trace时还会输出 operation、backend、status 与 duration 的 debug 日志作为本地诊断回退。可选插件的首次加载结果会在进程内缓存;修复安装或启动配置后需要重启进程。