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 请求日志写 stdout/文件后由 DataKit 采集上报(容器用 stdout 采集,虚拟机用磁盘文件采集),Pipeline 提取标准字段 time、并按状态码区间映射 status(5xx→error、4xx→warning)。随后请求日志立刻变成可运营的数据:

  • 看板:查看器中按 url 分组统计 QPS、按 status 看错误率、按 response_time_ms 找慢接口,一键导出到仪表板 ;
  • 告警:监控器(日志检测)配置"5xx 数量超阈值"或"某核心接口 P 耗时段异常"规则,告警策略推送钉钉/企业微信/飞书 ;
  • 追踪request_id 字段贯穿查询,若同时接入了观测云 APM,还可与链路数据互相跳转 。

总结

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 在应用层可携带更丰富的上下文;两者在观测云中按 source 区分,互为补充。


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

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

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

立即开始

选择观测云版本

代码托管平台