下面是详细的攻略。
1. 需求分析
在开发过程中,我们需要记录应用程序的全链路日志以便于排查问题和进行性能优化。要实现全链路日志,需要收集每个请求的相关信息,如请求方法、请求参数、响应状态码、响应时间、错误类型等信息。这些信息需要保留到一个日志文件中。
2. 策略设计
要优雅地打印全链路日志,我们需要使用以下策略:
- 定义一个格式化文本日志中间件,将收集的日志信息格式化输出到控制台或日志文件;
- 使用链式中间件设计模式,将格式化日志中间件与业务中间件组合起来;
- 使用Node.js的核心模块
util
来格式化日志信息。
3. 实现步骤
第一步:创建格式化日志中间件
在Node.js中,我们可以使用morgan
模块创建一个HTTP请求日志中间件,该模块可以很方便地记录HTTP请求响应的信息,但是它缺少一些额外的信息,如请求参数、错误信息等。因此,我们需要自定义一个格式化日志中间件来收集这些额外的信息。
以下是一个示例代码:
const { createLogger, format, transports } = require('winston');
const { combine, timestamp, printf } = format;
const myFormat = printf(({ level, message, label, timestamp }) => {
return `${timestamp} [${label}] ${level}: ${message}`;
});
const logger = createLogger({
level: 'debug',
format: combine(
label({ label: 'my-app' }),
timestamp(),
myFormat
),
transports: [
new transports.Console(),
new transports.File({ filename: 'combined.log' })
]
});
function logMiddleware(req, res, next) {
const start = Date.now();
const { method, url } = req;
const { statusCode } = res;
const duration = Date.now() - start;
const logEntry = `[${method}] ${url} - ${statusCode} ${duration}ms`;
logger.info(logEntry);
next();
}
module.exports = logMiddleware;
上面代码中,我们使用了winston
模块来创建一个logger
对象。在日志格式化中,我们使用了format.combine
方法将多个format
打包到一起,其中timestamp
方法用于添加时间戳,将日志中的label、时间戳、level、message以适当的格式进行输出。然后,我们在中间件中收集请求的相关信息,并将信息[String]格式调用logger.info方法记录在日志中。
第二步:使用链式中间件模式设计业务逻辑
可以在http.createServer()中,像如下代码一样将请求和日志中间件打通,使请求经过日志中间件记录完全请求信息后,进入路由处理(中间件链entry -> 中间件链 -> 路由)
const http = require('http')
const app = require('./app')
http.createServer(app).listen(3000, () => {
console.log(`server is running on ${3000}`)
})
此时logger.info(logEntry)
将记录请求的日志信息,你可以在控制台中或指定的日志文件中查看该信息。
示例一:使用中间件记录请求信息
const express = require('express')
const app = express()
const logMiddleware = require('./logMiddleware')
app.use(logMiddleware) // 自定义的日志中间件
app.get('/', (req, res) => {
res.send('hello world')
})
app.listen(3000, () => {
console.log(`server is running on ${3000}`)
})
上面代码中我们将日志中间件logMiddleware
添加到中间件链的最上面,这将会保证路由处理前已经在日志中记录了请求的全部信息。
示例二:记录路由处理结果
我们可以使用try/catch
来捕获处理过程中的异常,比如:
const express = require('express')
const app = express()
const logMiddleware = require('./logMiddleware')
// 将日志中间件添加到中间件链的最上面
app.use(logMiddleware)
app.get('/', (req, res) => {
try {
const data = { result: 'hello world' }
res.json(data)
} catch (error) {
res.status(500).json({ error: error.message })
}
})
app.listen(3000, () => {
console.log(`server is running on ${3000}`)
})
上面代码中我们保证了代码运行过程中任何错误都不会引起应用程序的崩溃,同时在异常发生时我们会返回一个响应来告诉客户端错误信息,并且这个错误信息也同样会被记录在日志中。
这样我们就可以轻松地记录应用程序的全链路日志了。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:如何用node优雅地打印全链路日志 - Python技术站