Skip to content

处理器和 Middleware ​

@loggerjs/processors 是管线中间层的 runtime-neutral 工具箱。这里的所有能力都是同步、有序、错误隔离的:抛错的 processor 会被报告到 logger meta,管线继续运行。

存在两种形态(完整模型见 核心概念):

  • Middleware 运行在 LogRecord 上,在 id/message/error 工作之前执行,是 enrich 或 drop 的最低成本位置。
  • Processors 运行在 LogEvent 上,在投影之后执行;当你需要解析后的 event 形状时才必须使用。

配置任何 processor 都会关闭该 logger 的 record 快速路径;middleware 不会。

Runtime 支持 ​

全部 27 个 processor 和 middleware 都支持浏览器/前端以及 Node.js/服务端运行时。这个包本身不依赖 DOM、IndexedDB、文件系统、流、worker 线程或任何厂商 SDK。

Runtime支持说明
浏览器 / 前端支持在数据离开页面之前,用于补充字段、隐私清洗、采样、去重、路由、breadcrumbs、结构校验,以及处理浏览器采集到的错误。
Node.js / 服务端支持与 Node 的 transport 和 integration 搭配使用同一套 processor;堆栈解析和错误规范化适用于标准的 JavaScript 错误。
Worker / edge / 库支持自定义 provider 函数必须保持同步。路由和 fingers-crossed 的目标必须是该运行时中可用的 transport。

Enrichment ​

Export功能
tagsProcessor(tags) / tagsMiddleware(tags)把固定 tags 合并到每条日志。
typeProcessor(type) / typeMiddleware(type)设置 event type。
contextProcessor(ctx) / contextMiddleware(ctx)合并固定 context 字段。
enrichProcessor(input) / enrichMiddleware(input)通用 patch:传入静态 patch 或返回 { message, type, tags, data, context, trace, source } 的函数;返回 false 可丢弃。
traceContextProcessor(provider) / traceContextMiddleware(provider)每条日志都从 provider function 附加 { traceId, spanId, ... }。

隐私和标准化 ​

Export功能
redactProcessor(options)按键名、精确的点路径或正则,在 data/context/tags/结构化错误中遮盖或移除值。censor 是 replacement 的兼容别名。采用写时复制,异步 transport 不会看到只脱敏了一半的对象。
privacyGuardProcessor(options)广谱 PII 清洗,带内置 patterns(email、bearer token、类似银行卡号的数字)和自定义 patterns。 带有 toJSON() 的值(例如 URL)会按其序列化后的形态扫描。
normalizeErrorProcessor(options)强制 error shape:stack 截断、cause-chain 深度限制、可枚举属性捕获。
stackParserProcessor(options) / parseStack(stack)把堆栈解析为结构化的帧(文件、行、列、函数)。
schemaDevCheckProcessor(options)开发期的 event 结构校验,用于发现类型化事件与实际 payload 之间的偏差。

Redaction 行为 ​

redactProcessor() 有意保持同步、解释执行。LoggerJS 不会用 eval 或 new Function 编译用户提供的 paths;自定义 matchers 是在 processor 错误边界内运行的普通函数。

选项:

  • keys:不区分大小写的键名、匹配键或完整路径的正则表达式,或自定义的 (key, path, value) => boolean 匹配函数。
  • paths:相对于每个被脱敏 event field 的精确 dot paths,例如 user.password 或 request.headers.authorization;这些不是 glob patterns。
  • replacement:匹配时写入的值;默认 "[REDACTED]"。
  • censor:兼容 Pino 的 replacement 别名;设置了 replacement 时忽略。
  • remove:直接省略匹配的对象属性,而不是替换。深度截断不属于键/路径匹配;到达 maxDepth 时,过深的子树仍会被折叠为 replacement。
  • maxDepth:最大遍历深度,默认 8。到达深度上限时采取保守策略,直接替换整个子树,而不是输出未经检查的嵌套值。
  • 带有 toJSON() 方法的值(例如 URL、Buffer 或自定义类)会按其序列化后的形态脱敏,因此 URL 仍保持为字符串。如果 toJSON() 抛错,该值会被替换。Date 值保持原样。

成本与遍历对象大小乘以 matcher 数量成正比。热日志器优先使用精确 keys 和 paths;广泛 regex 和深层遍历适合 edge loggers 或低频错误路径。

流量控制 ​

Export功能
sampleProcessor(options)按 level rate 做概率采样;默认保留 error/fatal。
dynamicSamplerProcessor(options)按 category 在滑动窗口内自适应采样;抑制吵闹 logger,保留安静 logger。
rateLimitProcessor(options)按 category 的 token bucket;默认豁免 error/fatal。
dedupeProcessor(options)在时间窗口内把重复的相同日志折叠成一条带 count 的 event。
coalesceProcessor(options)抑制窗口内重复 events,并在下一个匹配 event 上输出前一次 repeat count。
fingerprintProcessor(options)从可配置 parts(logger、error.name、stack.top、自定义函数)计算稳定 fingerprint,用于 grouping 和 dedupe keys。
filterProcessor(input)通过判断函数或声明式规则(minLevel、logger、type、tags、integration 来源等)决定保留或丢弃。
levelOverrideProcessor(input)按 category pattern 提升或限制 levels,例如把吵闹依赖降级。

缓冲和路由 ​

Export功能
fingersCrossedProcessor(options)在每个 key 的 ring buffer 中保留低级别日志;触发级别出现时,把缓冲历史 flush 到目标 transport。典型用途是“只有出问题时才给我 debug logs”。
breadcrumbBufferProcessor(options)维护有上限的 breadcrumb 轨迹,并在触发条件的 event 上附加或重放它们。
routeProcessor(input)按规则把 event 固定投递到指定名称的 transport,或排除某些 transport(例如 [{ minLevel: "error", transports: ["alerts"] }])。
symbolicateStackProcessor(options)把 source map 或发布服务提供的符号化能力接入解析后的堆栈帧,但不内置 source map 解析器。

顺序建议 ​

顺序很重要,每个阶段看到的是前一阶段输出:

  1. 先 enrich(tags、context、trace),让后续阶段能匹配这些字段。
  2. 再规范化(错误、堆栈),然后再做依赖错误结构的指纹计算或匹配。
  3. 在检查 data 的采样决策之前先 redact,并且始终在任何内容离开进程前 redact。
  4. 最后做流量控制(sample、rate-limit、dedupe),这样丢弃的是完整 events,counters 的含义也清楚。
ts
createLogger({
  middleware: [tagsMiddleware({ service: "checkout" })],
  processors: [
    normalizeErrorProcessor(),
    redactProcessor({ keys: ["password", /token/i] }),
    sampleProcessor({ rates: { debug: 0.1 } }),
  ],
});

编写自己的能力 ​

Middleware:

ts
import { createMiddleware } from "@loggerjs/core";

const requestIdMiddleware = createMiddleware("request-id", (record) => {
  record.props = { ...record.props, requestId: currentRequestId() };
  return record; // 或 null 表示丢弃
});

Processor:

ts
import type { Processor } from "@loggerjs/core";

const dropHealthChecks: Processor = (event) => {
  if (event.data && (event.data as { path?: string }).path === "/healthz") return false;
  return event;
};

合约提醒:

  • 只能同步执行,管线内不要 await。
  • 替换共享对象,不要原地修改(record.tags、record.ctx 可能被冻结并共享)。
  • 抛错会被报告并跳过;不要依赖某个 processor 一定运行成功。

相关链接 ​

基于 MIT License 发布。