Morgan 请求日志实战:Express HTTP 访问日志从入门到生产化

Morgan 是 Express 应用记录 HTTP 请求日志的标准中间件。本文讲解 Morgan 的五种预定义格式、自定义 token、JSON 输出改造、与 Winston 的配合,以及请求日志接入观测云实现状态码监控与慢请求分析的落地路径。

最佳实践
Morgan 请求日志实战:Express HTTP 访问日志从入门到生产化技术指南封面

Morgan 是 Node.js/Express 生态中专责 HTTP 请求日志的中间件,自动记录每个进入请求的方法、URL、状态码、响应耗时、客户端 IP 与 UA 等信息。 没有它,Express 应用对流量是"盲"的——哪些接口被访问、响应多快、错误率多少,全都无从得知。

核心要点速览

  • 一行接入:app.use(morgan('combined')),立即获得 Apache 风格的完整访问日志;
  • 五种预定义格式:combined/common/dev/short/tiny,开发用 dev,生产用自定义 JSON;
  • 自定义 token 可注入 request_id 等字段,实现请求级追踪;
  • 生产环境让 Morgan 输出 JSON,由 DataKit 采集进观测云做状态码统计、慢请求分析与告警。

为什么需要 Morgan?

裸 Express 应用对请求毫无记录:看不到哪些路由被访问、无法统计状态码、没有响应耗时数据、可疑请求无痕可查。Morgan 作为中间件挂在请求链路上,每个请求处理完毕自动产生一条访问日志,一行代码补齐可观测性最基础的一环。

快速上手

npm install morgan
import express from 'express';
import morgan from 'morgan';

const app = express();
app.use(morgan('combined'));

访问接口后输出 Apache combined 风格日志:

::1 - - [25/Aug/2026:10:15:14 +0000] "GET /about HTTP/1.1" 304 - "-" "Mozilla/5.0 ..."

五种预定义格式怎么选?

格式 内容 适用场景
combined Apache 完整格式(IP、时间、请求、状态码、大小、Referer、UA) 兼容传统分析工具
common combined 去掉 Referer/UA 精简访问记录
dev 彩色单行:方法 URL 状态码 耗时 本地开发
short 短格式 简单服务
tiny 最小格式 快速冒烟

切换只需改字符串:app.use(morgan('dev'))。

自定义 token:给每个请求一个 ID

内置 token(:method、:url、:status、:response-time 等)之外,可以自定义。最有价值的一个是请求 ID:

import { v4 as uuidv4 } from 'uuid';

app.use((req, res, next) => { req.id = uuidv4(); next(); });
morgan.token('id', (req) => req.id);

app.use(morgan(':id :method :url :status :res[content-length] - :response-time ms'));
e17c72f8-cb0c-4559-9d4f-3d22b75e03d6 GET / 304 - - 16.537 ms

有了 request_id,就能把访问日志与应用内部日志、下游调用串成一条线。

生产化:输出 JSON

文本格式进平台还要切割,不如让 Morgan 直接产出 JSON——传入自定义格式函数即可:

app.use(
  morgan((tokens, req, res) => JSON.stringify({
    request_id: tokens.id(req, res),
    method: tokens.method(req, res),
    url: tokens.url(req, res),
    status: parseInt(tokens.status(req, res), 10),
    response_time_ms: parseFloat(tokens['response-time'](req, res)),
    client_ip: tokens['remote-addr'](req, res),
    user_agent: tokens['user-agent'](req, res),
  }))
);

每条请求日志即一个标准 JSON 对象。需要同时保留应用日志时,把 Morgan 的 stream 选项接到 Winston/Pino 上,让请求日志与应用日志同一通道、同一格式输出:

app.use(morgan('combined', { stream: { write: (msg) => logger.info(msg.trim()) } }));

也可以按状态码分流:4xx/5xx 走 logger.error,其余走 logger.info,后续按级别筛选更直接。

验证请求日志的集中采集

上述 JSON 示例已经提供请求字段。使用观测云时,按 DataKit 日志采集配置选择文件或容器日志入口,再用成功请求、4xx 和 5xx 各一条测试字段解析:确认时间正确,HTTP 状态码可筛选,耗时是数值且单位一致。若将 HTTP 状态码映射为日志级别,应保留原始状态码字段。

在日志查看器按 URL 和状态码查找失败请求,再根据业务阈值建立日志检测规则。request_id 适合查询同一请求的多条日志;需要从日志进入 APM 链路时,应另外写入与链路一致的 trace_id,参见日志关联字段。

总结

Morgan 的生产化三步:开发用 dev 格式求快,生产改 JSON 格式求结构化,加 request_id token 求可追踪。采集后再用已知请求验证字段与查询结果,避免错误率统计建立在缺失或误解析的数据上。

常见问题(FAQ)

Q:Morgan 和应用日志库(Winston/Pino)是什么关系?
分工不同:Morgan 只管 HTTP 请求日志,应用内的业务/错误日志由 Winston/Pino 负责。实践中常把 Morgan 的输出通过 stream 导入 Winston/Pino,统一格式与通道。

Q:Morgan 还在维护吗?
更新频率很低,但功能早已稳定——请求日志中间件本身不需要频繁迭代,Express 生态至今没有公认替代品,可放心使用。

Q:高并发下 Morgan 会影响性能吗?
开销很小(每个请求一次格式化输出)。真正要注意的是输出目的地:生产写 stdout 即可,切勿同步写数据库或远程 HTTP。

Q:已有 Nginx 访问日志,还需要 Morgan 吗?
建议保留。Nginx 日志看不到应用内部视角(如路由参数、业务用户 ID),Morgan 在应用层可携带更丰富的上下文;集中采集时给两类日志设置不同来源,并传递同一个请求标识,便于区分代理层和应用层记录。


系列阅读:Winston 日志实战指南 | Node.js 日志库八款对比

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台