00 / 00

日志工具

服务端与浏览器日志记录工具,基于 evlog 封装

这是什么

@repo/logger 是模板里的统一日志工具,帮你记录服务端请求、后台任务、浏览器错误和关键业务事件。它分成两个入口:

  • @repo/logger/server:服务端、Hono、oRPC、后台任务使用
  • @repo/logger/client:浏览器端错误、交互事件和用户上下文使用

底层基于 evlog 的结构化日志模型,默认会对常见敏感字段做脱敏。

能做什么

  • 服务端事件 -- 记录接口、任务、支付、上传等结构化事件
  • 请求日志 -- Hono 和 TanStack Start 中间件可以挂载 request-scoped logger
  • 浏览器日志 -- 浏览器端可以输出到控制台,也可以投递到日志收集接口
  • 身份上下文 -- 登录后把用户 ID 写入浏览器日志上下文,退出时清理
  • 错误解析 -- createError() / parseError() 用于把未知错误整理成响应安全的结构

怎么用

服务端初始化

在应用启动时初始化一次:

import { initLogger, LOG_SERVICES } from "@repo/logger/server";

initLogger({
  env: {
    environment: process.env.NODE_ENV,
    service: LOG_SERVICES.WEB_SERVER,
    version: process.env.SOURCE_COMMIT,
  },
});

服务端记录事件

import { log } from "@repo/logger/server";

log.info({ event: "payment_created", orderId: "order_123" });
log.warn({ event: "upload_retry", attempt: 2 });
log.error({ event: "rpc_handler_error", error });

独立任务或脚本

import { createLogger } from "@repo/logger/server";

const logger = createLogger({ job: "sync_users" });

logger.set({ users: { processed: 42 } });
logger.emit({ event: "job_completed" });

解析错误

import { createError, parseError } from "@repo/logger/server";

throw createError({
  message: "Checkout failed",
  status: 402,
  why: "Card declined by issuer",
});

const parsed = parseError(error);

浏览器端

import { initLog, LOG_SERVICES, log, setIdentity } from "@repo/logger/client";

initLog({
  batchedTransport: {
    drain: {
      credentials: "include",
      endpoint: "/_logs/ingest",
    },
  },
  service: LOG_SERVICES.WEB_CLIENT,
});

setIdentity({ user: { id: "user_123" } });
log.info({ event: "profile_saved" });

大概原理

项目里主要做三件事:

  • 服务端通过 initLogger() 设置 service、版本、环境和脱敏规则
  • Hono / TanStack Start 中间件把请求信息挂到 request logger 上
  • 浏览器端通过 initLog() 把事件输出到控制台或发送到日志收集接口

服务端日志输出到标准输出(stdout),部署平台(Cloudflare、Zeabur、Docker、K8s)会自动采集。浏览器日志是否发送到后端,由 batchedTransport.drain.endpoint 决定。

最佳实践

  • 用对象记录事件,例如 { event, userId, orderId },不要只写一句话
  • 给事件名取稳定名称,方便后续检索和告警
  • 不要记录敏感信息(密码、token、身份证号、完整手机号/邮箱)
  • 服务端优先用 @repo/logger/server,浏览器端优先用 @repo/logger/client
  • 浏览器登录后调用 setIdentity(),退出后调用 clearIdentity()
  • 错误日志要附带上下文,方便定位问题

相关链接

这篇文档有问题?