介绍一下morgan
和winston
的区别
morgan
功能
morgan 是一个 HTTP 请求日志中间件,专门用于记录 Express 应用的 HTTP 请求日志。它简单易用,提供多种预定义的日志格式,能够自动记录每个 HTTP 请求的详细信息,如请求方法、URL、响应时间等。
优势:
- 专注于 HTTP 请求日志:morgan 专门用于记录 HTTP 请求日志,能够自动记录和格式化 HTTP 请求信息。
- 易于集成:morgan 是 Express 的中间件,集成非常方便。
- 标准化输出:morgan 提供的多种日志格式(如 combined, common, dev 等)标准化了日志输出,使其易于阅读和分析。
winston
功能
winston 是一个通用的日志库,支持灵活的配置和多种传输方式(如控制台输出、文件存储、HTTP 传输等)。它适用于记录应用程序的各种日志,包括信息日志、错误日志、调试日志等。
优势
- 通用日志记录:winston 适用于记录各种类型的日志,不限于 HTTP 请求日志。
- 灵活配置:winston 支持自定义格式、不同级别的日志、多个传输方式等,灵活性很高。
- 日志管理:通过配置 DailyRotateFile 等插件,winston 可以实现日志文件的自动轮换、压缩和删除,便于日志管理。
选择
morgan
:专注于 HTTP 请求日志,简单易用,适合作为 Express 中间件记录请求日志winston
: 提供灵活的日志记录和管理功能,适用于记录应用程序的各种日志- 所以结合使用才是最佳解
代码示例
安装3个依赖
npm install morgan winston winston-daily-rotate-file
这里还有一个winston-daily-rotate-file
目的是为了将每天的日志放入不同的文件,防止文件过大,并且会将老日志进行打包压缩
const express = require("express");
const morgan = require("morgan");
const path = require("path");
const fsExtra = require("fs-extra");
const winston = require("winston");
const DailyRotateFile = require("winston-daily-rotate-file");
const app = express();
// 日志目录路径
const logDirectory = path.join(__dirname, "logs");
// 确保日志目录存在
fsExtra.ensureDirSync(logDirectory);
// 配置 winston
const logger = winston.createLogger({
level: "info",
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.Console(),
new DailyRotateFile({
filename: path.join(logDirectory, "application-%DATE%.log"),
datePattern: "YYYY-MM-DD",
zippedArchive: true,
maxSize: "20m",
maxFiles: "14d",
}),
],
});
// 使用 morgan 记录 HTTP 请求到日志文件,并重定向到 winston
app.use(
morgan("combined", {
stream: {
write: (message) => logger.info(message.trim()),
},
})
);
// 示例路由
app.get("/", (req, res) => {
res.send("Hello, world!");
});
// 错误处理
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get("env") === "development" ? err : {};
logger.error({
url: req.url,
body: req.body,
error: err.message,
stack: err.stack,
});
// render the error page
res.status(err.status || 500);
res.send({
code: 500,
msg: err.message,
});
});
// 启动服务器
const port = 3000;
app.listen(port, () => {
logger.info(`Server is running on port ${port}`);
});
注意
:如果记录 http 请求的话,需要把日志部分的注册放到路由拦截之前