ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Plane 日志基础设施实战:深入解析 @plane/logger 的 Winston 结构化日志与 Express 请求日志中间件

Plane 日志基础设施实战:深入解析 @plane/logger 的 Winston 结构化日志与 Express 请求日志中间件 Plane 日志基础设施实战深入解析 plane/logger 的 Winston 结构化日志与 Express 请求日志中间件【免费下载链接】plane Open-source Jira, Linear, Monday, and ClickUp alternative. Plane is a modern project management platform to manage tasks, sprints, docs, and triage.项目地址: https://gitcode.com/GitHub_Trending/pl/planePlane 仓库中的packages/logger是一个内部共享的日志包基于 Winston 为主体骨架结合 packages/logger/src 下的源码逐层拆解其配置项、导出 API、日志级别体系以及在 apps/live 实时协作服务中的真实挂载方式帮助你在自己的 Express 应用中以几乎零成本搭建同样的日志体系。包结构与对外 API从 package.json 可以确认该包的关键事实包名为plane/loggerprivate: true即它只在 Plane 的 pnpm workspace 内部使用不发布到公共 registry依赖只有两个winston和express-winston版本通过 pnpm catalog 统一管理pnpm-workspace.yaml 中锁定为winston ^3.17.0、express-winston ^4.2.0入口产物为./dist/index.mjs同时生成.d.mts类型声明整个包是纯 ESMtype: module构建工具为tsdowntsdown.config.ts 中entry: [src/index.ts]、format: [esm]、dts: true。包的入口文件 src/index.ts 只有两行导出全部 API 就来自两个模块export * from ./config; // 导出 logger 与 loggerConfig export * from ./middleware; // 导出 loggerMiddleware需要特别提醒一个文档与源码的差异README 的 Usage 示例中写的是import { logger, requestLogger } from plane/logger但当前源码实际导出的中间件名称是loggerMiddleware并不存在requestLogger这个导出。从使用侧也能印证——apps/live/src/server.ts 中真实存在的导入是import { logger, loggerMiddleware } from plane/logger;如果按 README 示例去import { requestLogger }拿到的是undefined。编写或核对代码时应以源码导出为准。logger通用结构化日志器通用日志器的完整实现位于 src/config.ts全文只有 11 行有效代码import type { LoggerOptions } from winston; import { createLogger, format, transports } from winston; export const loggerConfig: LoggerOptions { level: process.env.LOG_LEVEL || info, format: format.combine( format.timestamp({ format: YYYY-MM-DD HH:mm:ss:ms, }), format.json() ), transports: [new transports.Console()], }; export const logger createLogger(loggerConfig);这段配置有三个值得注意的点日志级别来自环境变量默认info。level取process.env.LOG_LEVEL || info与 README 的 Configuration 一节一致默认info通过在.env中添加LOG_LEVEL可切换。注意该值在模块加载时读取即服务启动时必须设置好环境变量运行中修改.env不生效。JSON 结构化输出 精确到毫秒的时间戳。format.timestamp({ format: YYYY-MM-DD HH:mm:ss:ms })与format.json()组合后每条日志是一行合法 JSON例如logger.info(This is an error)实际输出形如{level:info,message:This is an error,timestamp:2026-09-06 05:23:27:123}这种格式对日志采集工具grep、JSON 解析管道友好得多也是 README 所称 structured logging 的具体含义。当前只挂载了 Console transport。这是一个与 README 的重要出入README 的 Log file 一节声称日志文件写在当前工作目录的logs文件夹下文件名形如error-%DATE%.log/combined-%DATE%.log并有 7 天轮转期。但在当前仓库的 src/config.ts 与 src/middleware.ts 中均没有配置transports.File也没有引入任何轮转rotation依赖两个导出都只使用了new transports.Console()。可以推断该 README 描述的是早期/计划中的落盘轮转能力而当前代码以输出到标准输出为主这在容器化部署下更常见由 Caddy/Docker 层收集 stdout。以当前仓库实际行为为准日志进控制台而非日志文件。README 给出的基本用法可直接复制logger.info(This is an info log); logger.warn(This is a warning); logger.error(This is an error);在 Plane 自身代码中logger是 live 服务的通用日志入口例如 apps/live/src/server.ts 在初始化关键依赖时打点await redisManager.initialize(); logger.info(SERVER: Redis setup completed); // ... logger.error(SERVER: Failed to initialize live server dependencies:, error);可以看到其约定info用于启动/关闭等生命周期事件SERVER: Express server has started at port 3000、SERVER: Redis connection closed gracefully.error附带原始 Error 对象以便在 JSON 中保留堆栈信息。此外协作编辑引擎 Hocuspocus 的原生日志也被桥接到了这个包——apps/live/src/extensions/logger.ts 继承hocuspocus/extension-logger并在log回调中转发到logger.info即整个实时文档栈共用同一套日志格式与级别。loggerMiddlewareHTTP 请求日志中间件请求日志中间件由 src/middleware.ts 提供完整实现如下import type { RequestHandler } from express; import expressWinston from express-winston; import { transports } from winston; import { loggerConfig } from ./config; export const loggerMiddleware: RequestHandler expressWinston.logger({ ...loggerConfig, transports: [new transports.Console()], msg: {{req.method}} {{req.url}} {{res.statusCode}} {{res.responseTime}}ms, expressFormat: true, });其工作机制可以拆成四层理解复用同一份loggerConfig中间件通过展开...loggerConfig继承了与通用日志器相同的级别LOG_LEVEL环境变量与时间戳 JSON 格式保证应用日志与请求日志级别联动、格式统一随后再覆盖transports为 Console与 config 中相同属于显式声明。expressWinston.logger()基于express-middleware-format模板生成消息msg: {{req.method}} {{req.url}} {{res.statusCode}} {{res.responseTime}}ms会在响应结束时输出一条访问日志典型输出{level:info,message:GET /live/documents/abc 200 15ms,timestamp:2026-09-06 05:23:27:123}expressFormat: true使res.statusCode、res.responseTime等占位符可用responseTime即请求处理耗时毫秒数这是访问日志能带耗时的关键开关。返回类型是express.RequestHandler因此可以直接交给app.use()与 README 中app.use(requestLogger)的用法等价把requestLogger换成实际导出名loggerMiddleware即可const app express(); app.use(loggerMiddleware);在 Plane 的 live 服务中它的挂载位置见 apps/live/src/server.ts 的setupMiddleware()// Security middleware this.app.use(helmet()); // Middleware for response compression this.app.use(compression({ level: env.COMPRESSION_LEVEL, threshold: env.COMPRESSION_THRESHOLD })); // Logging middleware this.app.use(loggerMiddleware); // Body parsing middleware this.app.use(express.json()); this.app.use(express.urlencoded({ extended: true }));两个实现细节值得注意其一loggerMiddleware放在helmet 与 compression 之后、express.json()之前——请求日志记录的是原始进入的 URL 与最终状态码而压缩中间件在前也不影响它因为 express-winston 在 response 完成时挂钩子而非依赖 body 解析其二由于expressWs(this.app)在构造函数中先行注入该中间件同样覆盖 WebSocket 握手这类经由 Express 处理的请求路径从源码结构看凡是走this.app中间件链的请求都会被记录。可用的日志级别README 的 Available Log Levels 一节列出的就是 Winston 原生支持的完整级别阶梯LOG_LEVEL可取以下值级别越高越靠前输出越少级别说明error仅错误warn警告及以上info默认值LOG_LEVEL未设置时http低于info常用于请求/响应类日志verbose比http更细debug调试信息silly最详细的级别由于级别统一由process.env.LOG_LEVEL决定src/config.ts调整生产环境噪音只需在容器/进程环境中设置LOG_LEVEL例如排查问题时临时设为debug无需改动代码。接入方式作为 workspace 依赖使用README 给出的接入方式是在宿主应用的package.json中添加依赖dependencies: { plane/logger: * }在 Plane 仓库内这是 pnpm workspace 内部引用。实际参考 apps/live/package.json 可以确认 live 应用正是这样依赖该包的如果你是在 Plane 仓库内新增一个 Node 应用建议沿用 workspace 协议如plane/logger: workspace:*与 packages/logger/package.json 自身 devDependencies 的写法一致若是脱离本仓库在外部项目中使用则需将 packages/logger/src 下三个源文件拷贝到你的工程中——它的全部运行时依赖只有winston与express-winston两个。构建与检查脚本package.json为pnpm --filter plane/logger build # tsdown 产物 dist/index.mjs .d.mts pnpm --filter plane/logger dev # tsdown --watch 开发模式 pnpm --filter plane/logger check:lint # oxlint --max-warnings0 pnpm --filter plane/logger check:types # tsc --noEmit小结把这套日志方案搬进自己的 Express 应用从仓库源码提炼出的最小可用模式恰好只有三段用createLogger配置level读环境变量、默认info、timestamp精确到毫秒format.json()、Console transport得到一个结构化 JSON 日志器用expressWinston.logger复用同一份 config叠加msg模板与expressFormat: true得到带耗时与状态码的访问日志中间件在 Express 中按 安全头 → 压缩 → 日志 → body 解析 的顺序挂载中间件并在启动/关闭/异常路径上用logger.info/logger.error打生命周期事件。同时记住本文核对出的两处 README 与当前源码的差异导出的中间件名是loggerMiddleware而非requestLogger当前实现只有 Console transportREADME 中 logs 目录 7 天轮转文件 的落盘描述在仓库现有代码中并未落地。若你需要文件轮转应在消费方如 live 服务自行追加transports.File与轮转策略而不是期望本包默认提供。延伸阅读通用日志器实现packages/logger/src/config.ts请求日志中间件实现packages/logger/src/middleware.ts包入口packages/logger/src/index.ts真实挂载示例Express Hocuspocus 实时服务apps/live/src/server.tsHocuspocus 日志桥接apps/live/src/extensions/logger.ts【免费下载链接】plane Open-source Jira, Linear, Monday, and ClickUp alternative. Plane is a modern project management platform to manage tasks, sprints, docs, and triage.项目地址: https://gitcode.com/GitHub_Trending/pl/plane创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表