Skip to content

运行时 ​

运行时适配器将环境差异(时钟、进程 id、文件系统、默认传输器)隔离在单一接口之后。

ts
type RuntimeName = 'web' | 'node' | 'electron';
type ElectronProcessType = 'main' | 'renderer';

interface RuntimeAdapter {
  readonly name: RuntimeName;
  readonly processType?: ElectronProcessType;
  now(): number;
  pid(): number | undefined;
  hasFileSystem(): boolean;
  getEnv?(name: string): string | undefined;
  defaultTransports(): Transport[];
  attachReceiver?: (ingest: IngestFn) => () => void;
  /**
   * 宿主生命周期钩子。提供时,Logger 会通过它们来接线“退出前 flush”与“崩溃记录”,
   * 而不是直接触碰 `process` / `window`,从而让每个运行时自行决定何时退出、并拥有
   * 自己的 `process.exit()`。在不需要响应宿主生命周期的运行时可省略(或留空)。
   * 内置适配器已提供:Node → process 事件,Electron 主进程 → `app` 的 `before-quit` /
   * `will-quit`,Web → `pagehide` / `visibilitychange`。
   */
  lifecycle?: LifecycleHooks;
}

getEnv 用于提供 LOG_LEVEL 等可选环境配置。自定义运行时若未实现它,Logger 不会读取宿主环境变量。Logger 会在初始化或首次使用时才调用 defaultTransports() 与 attachReceiver()。

生命周期钩子 ​

LifecycleHooks 把 logger 与宿主解耦。logger 提供行为(带超时的 flush、以 fatal 记录崩溃),运行时拥有触发器:

ts
interface LifecycleHooks {
  // 在宿主关闭前 flush 待写条目。返回一个注销函数。
  onFlushBeforeExit(cb: () => void | Promise<void>): () => void;
  // 可选:记录致命的宿主未捕获错误(仅 Node / Electron)。
  onUncaughtError?(cb: (err: unknown) => void | Promise<void>): () => void;
}

只有编写自定义运行时适配器时才需要实现它;内置的 createNodeRuntime / createWebRuntime / createElectronMainRuntime / createElectronRendererRuntime 已经挂好了对应钩子,因此各平台开箱即用 autoFlushOnExit / watchUncaughtErrors。

探测 ​

ts
import { detectRuntime, createWebRuntime, createNodeRuntime, createElectronRuntime } from 'lograil/runtime';

detectRuntime(options?); // 自动探测:Electron → Node → Web

detectRuntime 的优先级为:

  1. 当 process.versions.electron 存在时为 Electron;
  2. 存在 Node 进程时为 Node.js;
  3. 否则为 Web。

对于 Electron,你也可以显式指定:

ts
import { createElectronMainRuntime, createElectronRendererRuntime } from 'lograil/runtime';

createElectronMainRuntime(options?);
createElectronRendererRuntime(options?);

默认传输器 ​

运行时默认传输器
WebConsoleTransport
Node.jsConsoleTransport + FileTransport(rotate-time,按日,含磁盘安全默认上限)
Electron 主进程ConsoleTransport + FileTransport(rotate-time,按日,含磁盘安全默认上限),并接收渲染进程 IPC
Electron 渲染进程ConsoleTransport(经由 IPC 转发到主进程)

磁盘安全默认值:Node 与 Electron 主进程的默认文件传输器自带容量上限,零配置也不会吃满磁盘—— 单文件最多 10 MB(maxSize)、保留约两周的按日文件(maxFiles: 14)、所有日志文件总体积最多 200 MB(maxTotalSize)。 全部可通过 fileTransportOptions 覆盖。

Web 运行时 ​

ts
createWebRuntime();

Web 运行时面向浏览器。它没有文件系统(hasFileSystem() 返回 false),没有进程 id, 默认传输器只有 ConsoleTransport。其生命周期钩子在 pagehide / visibilitychange 时 flush,而非依赖 process 事件。由于 Node 内置模块经 browser 字段被替换为 stub, 在浏览器打包中引入它总是安全的。

ts
createLogger({ runtime: createWebRuntime() });

选项 ​

ts
interface NodeRuntimeOptions {
  appName?: string; // FileTransport 必填;省略时从入口脚本推断
  fileTransportOptions?: Partial<Omit<RotateTimeOptions, 'mode'>>; // 透传给默认 `FileTransport`(覆盖磁盘安全默认值)
  disableFile?: boolean;
}

interface ElectronMainRuntimeOptions {
  // 日志文件用 appName main/renderer;默认目录:app.getPath('logs')
  // (可用 fileTransportOptions: { dir } 覆盖)
  fileTransportOptions?: Partial<Omit<RotateTimeOptions, 'mode'>>;
  disableFile?: boolean;
  receiveFromRenderer?: boolean; // 默认 true
}

可以通过 detectRuntime 或显式工厂函数传入选项:

ts
createLogger({ runtime: createNodeRuntime({ appName: 'my-app', disableFile: false }) });

常量与类型 ​

ts
// 渲染进程 → 主进程日志所经由的 IPC 频道。
const LOGRAIL_CHANNEL: string; // 'lograil:log'

type RuntimeName = 'web' | 'node' | 'electron';
type ElectronProcessType = 'main' | 'renderer';
// 将收到的条目喂回 logger 的回调。
type IngestFn = (entry: LogEntry) => void;

forwardToMain、channel 与 ipcRenderer 专属于 createElectronRendererRuntime:

ts
interface ElectronRendererRuntimeOptions {
  forwardToMain?: boolean; // 默认 true —— 通过 IPC 转发到主进程
  channel?: string;        // 覆盖 IPC 频道
  // 注入的 IPC 发送器。当渲染进程无法访问 require('electron') 时必须提供
  // (例如 nodeIntegration:false + contextIsolation:true):用 preload 桥接
  // 暴露的 ipcRenderer,而非让传输器自己调用 require('electron')。
  ipcRenderer?: { send(channel: string, ...args: unknown[]): void };
}

提供 ipcRenderer 时直接使用它;否则传输器回退到 require('electron').ipcRenderer,而这在受限渲染进程中不可用。详见 Electron 指南 中的 preload 模式。

RuntimeName / ElectronProcessType / IngestFn 属于 RuntimeAdapter 契约(见 运行时适配器接口),在编写自定义适配器或自定义 IPC 桥时很有用。

Released under the MIT License.