Skip to content

处理器和 Middleware

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

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

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

配置任何 processor 都会关闭该 logger 的 record fast path;middleware 不会。

Runtime 支持

全部 27 个 processors 和 middleware 都支持 browser/frontend 与 Node.js/server runtime。这个包本身不依赖 DOM、IndexedDB、filesystem、streams、worker threads 或任何 vendor SDK。

Runtime支持说明
Browser / frontend支持在数据离开页面前,用于 enrichment、隐私清洗、sampling、dedupe、routing、breadcrumbs、schema checks 和 browser-captured errors。
Node.js / server支持与 Node transports 和 integrations 使用同一套 processors;stack parsing 和 error normalization 处理标准 JavaScript errors。
Workers / edge / libraries支持自定义 provider functions 保持同步。Routing 和 fingers-crossed targets 必须引用该 runtime 可用的 transports。

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)按 key name、精确 dot path 或 regex,在 data/context/tags/structured errors 中 mask 或 remove 值。censorreplacement 的非破坏别名。采用 copy-on-write,async transports 不会看到半脱敏对象。
privacyGuardProcessor(options)广谱 PII 清洗,带内置 patterns(email、bearer token、类似银行卡号的数字)和自定义 patterns。
normalizeErrorProcessor(options)强制 error shape:stack 截断、cause-chain 深度限制、可枚举属性捕获。
stackParserProcessor(options) / parseStack(stack)把 stack 解析为结构化 frames(file、line、column、function)。
schemaDevCheckProcessor(options)开发期 event shape 校验;发现 typed events 与实际 payload 的漂移。

Redaction 行为

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

选项:

  • keys:大小写不敏感 key names、匹配 key 或完整 path 的 regexes,或自定义 (key, path, value) => boolean matcher。
  • paths:相对于每个被脱敏 event field 的精确 dot paths,例如 user.passwordrequest.headers.authorization;这些不是 glob patterns。
  • replacement:匹配时写入的值;默认 "[REDACTED]"
  • censor:兼容 Pino 的 replacement 别名;设置了 replacement 时忽略。
  • remove:省略匹配的对象属性,而不是替换。深度限制截断不是 key/path match;到达 maxDepth 时,过深 subtree 仍然会折叠为 replacement
  • maxDepth:最大遍历深度;默认 8。到达深度时 fail closed,替换整个 subtree,而不是输出未知嵌套值。

成本与遍历对象大小乘以 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(loggererror.namestack.top、自定义函数)计算稳定 fingerprint,用于 grouping 和 dedupe keys。
filterProcessor(input)通过 predicate 或声明式规则(minLevelloggertypetags、integration source 等)keep/drop。
levelOverrideProcessor(input)按 category pattern 提升或限制 levels,例如把吵闹依赖降级。

缓冲和路由

Export功能
fingersCrossedProcessor(options)在每个 key 的 ring buffer 中保留低级别日志;触发级别出现时,把缓冲历史 flush 到目标 transport。典型用途是“只有出问题时才给我 debug logs”。
breadcrumbBufferProcessor(options)维护有界 breadcrumb trail,并在触发 events 上附加或 replay。
routeProcessor(input)按规则把 events 固定到命名 transports 或排除 transports(例如 [{ minLevel: "error", transports: ["alerts"] }])。
symbolicateStackProcessor(options)把 source-map 或 release-service symbolication 接入 parsed stack frames,但不捆绑 source-map parser。

顺序建议

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

  1. 先 enrich(tags、context、trace),让后续阶段能匹配这些字段。
  2. 再 normalize(errors、stacks),然后做依赖错误形状的 fingerprint 或 match。
  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.tagsrecord.ctx 可能被冻结并共享)。
  • 抛错会被报告并跳过;不要依赖某个 processor 一定运行成功。

相关链接

基于 MIT License 发布。