Skip to content

插件 ​

插件通过可选的生命周期钩子来扩展 logger。所有钩子都是可选的;若插件需要转换条目,实现 onEntry 即可。

ts
interface Plugin {
  /** 唯一插件名。 */
  readonly name: string;
  onInit?(ctx: PluginContext): void | Promise<void>;
  onEntry?(entry: LogEntry): LogEntry | null | Promise<LogEntry | null>;
  onTransport?(transport: Transport): void;
  onDestroy?(): void | Promise<void>;
}

在 onEntry 中返回 null 即可 丢弃 一条条目;返回(可能是新的)条目则继续往下传递。

注册插件 ​

ts
import { createLogger } from 'lograil';

const log = createLogger();

await log.use({
  name: 'add-host',
  onEntry(entry) {
    entry.metadata = { ...entry.metadata, host: os.hostname() };
    return entry;
  },
});

PluginContext ​

onInit 会收到一个 PluginContext——它是一座桥梁,让插件能够在运行时重新配置 logger:

ts
interface PluginContext {
  addTransport(transport: Transport): void;
  removeTransport(name: string): void;
  pipeline: Pipeline; // 添加/移除过滤器与处理器,更换格式化器
  use(plugin: Plugin): Promise<void>;
  unregisterPlugin(name: string): void;
  logger: Logger;
}

示例——一个同时添加脱敏处理器与采样过滤器的插件:

ts
import { createRedactProcessor, createLevelFilter, type Filter } from 'lograil';

// 仅保留约 10% 的条目(随机采样)。
const sampleFilter: Filter = () => Math.random() < 0.1;

log.use({
  name: 'secure',
  onInit(ctx) {
    ctx.pipeline.addProcessor(createRedactProcessor(['password', 'token']));
    ctx.pipeline.addFilter(sampleFilter);
    ctx.pipeline.addFilter(createLevelFilter(20)); // 保留 debug 及以上
  },
});

生命周期 ​

插件通过四个可选的生命周期钩子参与日志的生产与销毁过程。

总览 ​

onEntry 拦截链详解 ​

每个日志条目会按注册顺序依次经过所有插件的 onEntry 钩子。若某个插件返回 null,后续插件不会收到该条目。

钩子触发时机 ​

钩子触发时机特性
onInit插件被注册时(通过 use)可异步,仅执行一次
onEntry对每条条目,在格式化之前可异步,按注册顺序链式执行
onTransport有传输器被添加时(包括被其他插件添加)同步,遍历所有插件
onDestroy调用 unregisterPlugin 或 logger.destroy() 时可异步,单个注销为 fire-and-forget
ts
log.unregisterPlugin('secure'); // 触发 onDestroy
log.hasPlugin('secure'); // false

异步与错误处理 ​

  • onEntry 的拦截是异步的,且按注册顺序串行执行。
  • 若某个插件的 onEntry 抛出异常,错误会被上报(通过 onError),但条目会原样传递给下一个插件——一个故障插件不会丢失或破坏日志。
  • 在进程退出前调用 await log.flush() / await log.destroy(),以确保所有插件工作都已完成。
  • 子 logger 与父级共享同一个 PluginManager,插件只需注册一次。

内置插件:OTel trace 关联 ​

createOtelTracePlugin() 会自动把当前活跃的 OpenTelemetry trace 与 span 标识注入到每条条目的 metadata(traceId / spanId)中,这样 OtlpTransport(或任何读取这两个字段的后端)就能把日志与其 span 关联起来——而无需你手动透传上下文。

@opentelemetry/api 是可选的对等依赖。若未安装,或当前没有活跃 span,该插件即为空操作,条目不受影响。

ts
import { createOtelTracePlugin } from 'lograil';

await log.use(createOtelTracePlugin());

// 在已追踪的操作内部,活跃 span 会被自动拾取:
logger.info('handling request'); // => metadata: { traceId, spanId }

Released under the MIT License.