01MVP 标识01MVP
包文档基础设施服务Logs 日志工具

Logs 日志工具

使用 @mono/logs 进行统一日志记录、模块化打标和错误追踪

Logs 日志工具

@mono/logs 是项目内统一的日志工具包,基于 consola 封装,提供:

  • 环境感知的日志配置
  • 模块级 logger
  • 开发环境彩色输出
  • 生产环境紧凑格式和时间戳
  • 简单一致的 API

安装方式

在 monorepo 中直接通过 workspace 依赖使用:

{
  "dependencies": {
    "@mono/logs": "workspace:*"
  }
}

快速开始

使用默认 logger

import { logger } from "@mono/logs";

logger.info("应用启动成功");
logger.warn("配置项缺失,将使用默认值");
logger.error("数据库连接失败");

创建模块级 logger

import { createModuleLogger } from "@mono/logs";

const authLogger = createModuleLogger("auth");
const paymentLogger = createModuleLogger("payment");

authLogger.info("用户登录成功");
paymentLogger.warn("支付回调签名校验失败");

提示: 推荐每个领域模块创建自己的 logger,而不是手动在消息里拼接前缀。

日志级别

当前包使用的默认策略:

  • development:显示 debug 及以上级别日志
  • production:显示 info 及以上级别日志

常用级别:

logger.trace("最细粒度调试信息");
logger.debug("调试信息");
logger.info("普通信息");
logger.success("操作成功");
logger.warn("警告信息");
logger.error("错误信息");
logger.fatal("致命错误");

实战示例

1. 在认证模块中记录登录行为

import { createModuleLogger } from "@mono/logs";

const authLogger = createModuleLogger("auth");

export async function signIn(email: string) {
  authLogger.info("开始登录流程", { email });

  try {
    const user = await findUserByEmail(email);

    if (!user) {
      authLogger.warn("用户不存在", { email });
      return null;
    }

    authLogger.success("登录成功", { userId: user.id });
    return user;
  } catch (error) {
    authLogger.error("登录失败", {
      email,
      error: error instanceof Error ? error.message : String(error),
    });
    throw error;
  }
}

2. 在 API 路由中记录请求耗时

import { createModuleLogger } from "@mono/logs";

const apiLogger = createModuleLogger("api");

export async function GET(request: Request) {
  const start = Date.now();

  apiLogger.debug("收到请求", {
    method: request.method,
    url: request.url,
  });

  try {
    const data = await getDashboardData();
    const duration = Date.now() - start;

    apiLogger.info("请求处理完成", {
      duration,
      status: 200,
    });

    return Response.json(data);
  } catch (error) {
    apiLogger.error("请求处理失败", {
      error: error instanceof Error ? error.message : String(error),
    });

    return Response.json({ error: "Internal Server Error" }, { status: 500 });
  }
}

3. 在邮件发送场景中记录成功和失败

import { createModuleLogger } from "@mono/logs";

const mailLogger = createModuleLogger("mail");

export async function sendWelcomeEmail(to: string) {
  mailLogger.info("准备发送欢迎邮件", { to });

  try {
    await sendViaProvider({
      to,
      subject: "Welcome",
    });

    mailLogger.success("欢迎邮件发送成功", { to });
  } catch (error) {
    mailLogger.error("欢迎邮件发送失败", {
      to,
      error: error instanceof Error ? error.message : String(error),
    });
    throw error;
  }
}

4. 在批处理任务中记录任务进度

import { createModuleLogger } from "@mono/logs";

const jobLogger = createModuleLogger("jobs");

export async function processBatch(batchId: string, items: string[]) {
  jobLogger.info("批处理任务开始", {
    batchId,
    total: items.length,
  });

  for (const [index, item] of items.entries()) {
    jobLogger.debug("处理单条记录", {
      batchId,
      item,
      progress: `${index + 1}/${items.length}`,
    });

    await processItem(item);
  }

  jobLogger.success("批处理任务完成", { batchId });
}

输出格式说明

开发环境

开发环境下:

  • 开启颜色输出
  • 不显示时间戳
  • 更适合本地调试阅读

生产环境

生产环境下:

  • 不使用颜色
  • 显示时间戳
  • 输出更紧凑
  • 更适合容器日志、日志采集平台和监控系统

与日志服务集成

虽然 @mono/logs 当前主要输出到标准输出,但它天然适合和以下平台集成:

  • Vercel / Docker / Kubernetes 日志流
  • Datadog
  • Better Stack
  • CloudWatch
  • Elasticsearch / OpenSearch
  • Loki + Grafana

常见做法是:

  1. 应用通过 logger 输出到 stdout / stderr
  2. 部署平台或日志 agent 负责采集
  3. 外部日志平台做检索、告警和可视化

示例思路:

import { logger } from "@mono/logs";

export async function handleWebhook(payload: unknown) {
  logger.info("收到 webhook 事件", {
    source: "stripe",
    payloadType: typeof payload,
  });

  // 后续由平台采集 stdout 输出到外部日志系统
}

配置行为

包内部会根据 NODE_ENV 自动切换配置:

const isDev = process.env.NODE_ENV === "development";
const isProd = process.env.NODE_ENV === "production";

对应行为:

  • isProd 时默认 level 为 3
  • 非生产环境默认 level 为 4
  • 生产环境显示日期并启用紧凑格式
  • 开发环境启用颜色

注意:实际底层由 consola 控制展示行为,因此建议以本包导出的 logger 为唯一入口,避免各处自行创建 logger 造成风格不一致。

API 一览

logger

默认日志实例。

import { logger } from "@mono/logs";

logger.info("hello");
logger.error(new Error("boom"));

createModuleLogger(module: string)

创建带 tag 的 logger。

import { createModuleLogger } from "@mono/logs";

const logger = createModuleLogger("uploads");
logger.info("开始上传文件");

最佳实践

1. 每个模块使用自己的 logger

const authLogger = createModuleLogger("auth");
const storageLogger = createModuleLogger("storage");

2. 记录结构化上下文

logger.info("订单创建成功", {
  orderId,
  userId,
  amount,
});

不要只写模糊文本:

logger.info("订单成功");

3. 不要记录敏感信息

避免输出:

  • 密码
  • token
  • cookie
  • 身份证号
  • 完整手机号 / 邮箱(必要时脱敏)
logger.info("用户登录成功", {
  userId,
  email: maskEmail(email),
});

4. 错误日志要带上下文

try {
  await saveUser(data);
} catch (error) {
  logger.error("保存用户失败", {
    userId: data.id,
    error: error instanceof Error ? error.message : String(error),
  });
  throw error;
}

5. 用合适的级别

  • debug:调试过程
  • info:正常业务事件
  • warn:可恢复问题
  • error:失败但系统可继续运行
  • fatal:系统级不可恢复故障

测试中的使用建议

在测试里通常只需要验证:

  • logger 是否可创建
  • 模块 logger 是否带 tag
  • 错误对象是否能被安全记录
  • 环境配置是否正确生效

如果测试输出过多,可以在测试环境中减少日志输出,或者仅测试 logger 接口行为。

总结

@mono/logs 的目标不是做复杂日志平台,而是提供一个:

  • 足够轻量
  • 输出风格统一
  • 便于模块隔离
  • 适合生产采集

的日志基础设施。

如果你在新增模块,建议第一步就是:

const logger = createModuleLogger("your-module");

然后在关键成功、失败和异常路径中补齐必要日志。