5月28日 00:14

Bun 的日志和错误处理机制如何?

Bun 作为基于 JavaScriptCore 引擎的高性能运行时,在日志和错误处理方面既保持了与 Node.js 的兼容性,又提供了自己的特色实现。下面从日志 API、错误捕获、服务端错误处理三个方面展开。

日志机制:console API 与配置增强

Bun 的日志系统以标准 console API 为核心,完全兼容浏览器和 Node.js 的用法:

  • 标准 console 方法:Bun 支持 console.log()console.error()console.warn()console.info()console.debug() 等全部标准方法。输出格式与 Node.js 一致,开发者无需修改现有代码即可迁移。
  • 对象检查深度可配置:Bun 允许通过 bunfig.toml 或 CLI 参数调整 console.log() 输出嵌套对象的深度,默认为 2 层:
toml
# bunfig.toml console.depth = 4

或通过命令行指定:

bash
bun --console-depth 4 run index.ts

这对于调试深层嵌套对象非常实用,避免在 Node.js 中频繁使用 JSON.stringify 的繁琐操作。

  • Bun.inspect 精细化输出:Bun 提供 Bun.inspect() 方法,支持语法高亮的格式化输出,特别适合错误对象的详细展示:
javascript
const err = new Error("Something went wrong"); console.log(Bun.inspect(err, { colors: true }));

Bun.inspect 会输出错误消息、堆栈跟踪以及出错位置的源代码预览,比 Node.js 默认的 console.log(err) 提供更丰富的上下文信息。

  • stdout/stderr 作为 BunFile:Bun 将标准输出和标准错误暴露为 Bun.stdoutBun.stderr,类型为 BunFile。这意味着可以直接用文件操作 API 写入日志:
javascript
await Bun.write(Bun.stdout, "自定义日志输出\n");
  • 调试环境变量:通过设置 BUN_CONFIG_VERBOSE_FETCH=1,Bun 会自动记录所有 fetch()node:http 发出的网络请求,方便排查网络问题,无需手动添加日志:
bash
BUN_CONFIG_VERBOSE_FETCH=1 bun run server.ts

错误处理机制:堆栈跟踪与服务端容错

Bun 的错误处理建立在 JavaScript 标准异常模型之上,但在堆栈跟踪和服务端错误边界方面有独特的实现。

  • V8 兼容的堆栈跟踪:Bun 使用 JavaScriptCore 引擎,但将 error.stack 格式化为与 V8 一致的格式,确保依赖 V8 堆栈格式的库(如 Sentry)能正常工作。同时实现了完整的 V8 Stack Trace API:
javascript
// 捕获自定义堆栈跟踪 function myFunction() { const err = new Error("custom"); Error.captureStackTrace(err, myFunction); console.log(err.stack); } // 自定义堆栈格式化 Error.prepareStackTrace = (err, callsites) => { return callsites.map(c => `${c.getFileName()}:${c.getLineNumber()}`).join("\n"); };
  • 未处理异常的源码预览:当未捕获的异常或 Promise 拒绝发生时,Bun 会自动打印出错位置的源代码片段,而不是仅显示堆栈文本。这让定位问题更加直观。

  • Sourcemap 自动映射:Bun 对所有转译文件自动生成和提供 sourcemap。在堆栈跟踪中点击文件路径,可以直接跳转到原始 TypeScript 或 JSX 源码位置,而非转译后的代码。

Bun.serve 的错误边界

HTTP 服务是 Bun 的核心使用场景,Bun.serve 提供了专门的 error 回调来处理请求处理过程中的异常:

  • error 回调:当 fetch 函数抛出异常时,Bun 会调用 error 回调,该回调应返回一个 Response 对象:
javascript
Bun.serve({ fetch(req) { throw new Error("Something went wrong"); }, error(error) { return new Response(`Error: ${error.message}`, { status: 500, headers: { "Content-Type": "text/plain" }, }); }, });
  • 开发模式错误页面:设置 development: true 后,Bun 会在浏览器中展示内置的错误详情页面,包含堆栈跟踪和源码高亮:
javascript
Bun.serve({ development: true, fetch(req) { throw new Error("debug me"); }, });
  • Bun.file 流式响应的错误陷阱:当 Bun.file() 作为流式响应的一部分出错时,错误无法通过 fetch 内部的 try/catch 捕获。这类错误只能由 error 回调统一处理:
javascript
Bun.serve({ fetch(req) { try { const file = Bun.file("not-exist.txt"); return new Response(file); // 文件不存在时,try/catch 无法捕获 } catch (e) { // 这里不会执行 return new Response("Not found", { status: 404 }); } }, error(error) { // 必须在这里处理 Bun.file 的错误 return new Response("File not found", { status: 404 }); }, });

这是一个容易踩坑的地方:流式响应的错误发生在 fetch 返回之后,因此 try/catch 无法拦截。

  • 动态更新处理器:使用 server.reload() 可以在不停机的情况下更新 fetcherror 处理函数:
javascript
const server = Bun.serve({ fetch(req) { return new Response("v1"); }, error(err) { return new Response("error v1", { status: 500 }); }, }); // 热更新处理逻辑 server.reload({ fetch(req) { return new Response("v2"); }, error(err) { return new Response("error v2", { status: 500 }); }, });

生产环境的日志与错误策略

在生产环境中,仅依赖 console 输出不足以支撑可观测性需求,需要结合第三方工具:

  • 结构化日志:推荐使用社区库如 Pino(通过 bun-logger 等封装)实现 JSON 格式的结构化日志,便于日志平台采集和分析:
javascript
import pino from "pino"; const logger = pino({ level: process.env.LOG_LEVEL || "info" }); logger.info({ userId: "user123" }, "User login");
  • 错误监控集成:Sentry 官方提供 Bun SDK,支持异常捕获和结构化日志:
javascript
import * as Sentry from "@sentry/bun"; Sentry.init({ dsn: process.env.SENTRY_DSN, enableLogs: true, }); // 全局异常捕获 process.on("uncaughtException", (error) => { Sentry.captureException(error); });
  • 日志级别控制:在 bunfig.toml 中可以为 bun install 设置日志级别(debug/warn/error),但运行时日志级别需通过环境变量自行管理:
javascript
const LOG_LEVEL = process.env.LOG_LEVEL || "info"; const levels = { debug: 0, info: 1, warn: 2, error: 3 }; function log(level, message) { if (levels[level] >= levels[LOG_LEVEL]) { console.log(`[${level.toUpperCase()}] ${message}`); } }
  • 敏感信息过滤:错误日志应避免泄露密码、API Key 等敏感字段,在写入日志前做脱敏处理:
javascript
function sanitize(obj) { const safe = { ...obj }; for (const key of ["password", "apiKey", "secret"]) { if (key in safe) safe[key] = "****"; } return safe; } console.error("Request failed:", sanitize(context));

Bun 的日志和错误处理机制以标准 console API 为基础,通过 Bun.inspect、V8 兼容堆栈跟踪、Bun.serveerror 回调等特性提供了更强的调试能力和容错设计。理解 Bun.file 流式响应的错误边界、善用 BUN_CONFIG_VERBOSE_FETCH 调试网络请求、以及在生产环境集成 Pino 或 Sentry,是实际项目中的关键实践。

标签:Bun