您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# 怎样使用Node.js创建访问日志记录的中间件
## 前言
在Web应用开发中,访问日志记录是监控应用健康状况、分析用户行为和排查问题的重要手段。Node.js作为流行的后端技术,通过中间件机制可以轻松实现访问日志功能。本文将详细介绍如何使用Node.js创建功能完善的访问日志中间件。
## 一、理解中间件概念
### 1.1 什么是中间件
中间件是Express框架的核心概念,指在请求和响应周期中执行的函数,能够:
- 访问请求对象(req)、响应对象(res)
- 执行任何代码
- 修改请求和响应对象
- 结束请求-响应周期
- 调用下一个中间件
### 1.2 中间件的工作流程
客户端请求 → 中间件1 → 中间件2 → … → 路由处理 → 响应客户端
## 二、基础日志中间件实现
### 2.1 最简单的日志中间件
```javascript
const express = require('express');
const app = express();
// 基础日志中间件
app.use((req, res, next) => {
console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
next();
});
app.get('/', (req, res) => {
res.send('Hello World');
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
2023-05-20T08:30:00.000Z - GET /
2023-05-20T08:31:23.456Z - POST /api/users
app.use((req, res, next) => {
const timestamp = new Date().toISOString();
const { method, url, ip, headers } = req;
console.log(`[${timestamp}] ${method} ${url}
IP: ${ip}
User-Agent: ${headers['user-agent']}
Accept: ${headers['accept']}`);
next();
});
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
console.log(`请求处理时间: ${duration}ms`);
});
next();
});
npm install winston
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: 'access.log' })
]
});
// 在中间件中使用
app.use((req, res, next) => {
logger.info({
message: 'Request received',
method: req.method,
url: req.url,
ip: req.ip
});
next();
});
{
"message": "Request received",
"method": "GET",
"url": "/api/products",
"ip": "::1",
"timestamp": "2023-05-20T08:45:12.345Z"
}
使用winston-daily-rotate-file
实现:
npm install winston-daily-rotate-file
const DailyRotateFile = require('winston-daily-rotate-file');
logger.add(new DailyRotateFile({
filename: 'application-%DATE%.log',
datePattern: 'YYYY-MM-DD',
zippedArchive: true,
maxSize: '20m',
maxFiles: '14d'
}));
app.use((req, res, next) => {
const sanitizedHeaders = { ...req.headers };
// 过滤敏感信息
if (sanitizedHeaders['authorization']) {
sanitizedHeaders['authorization'] = '***REDACTED***';
}
logger.info({
headers: sanitizedHeaders,
// 其他日志字段...
});
next();
});
// 错误处理中间件
app.use((err, req, res, next) => {
logger.error({
message: err.message,
stack: err.stack,
url: req.url,
method: req.method
});
res.status(500).send('Something broke!');
});
app.use((req, res, next) => {
const logData = {
timestamp: new Date(),
method: req.method,
url: req.url
};
// 不等待日志写入完成
process.nextTick(() => {
logger.info(logData).catch(err => {
console.error('日志记录失败:', err);
});
});
next();
});
const SAMPLE_RATE = 0.1; // 10%的请求记录详细日志
app.use((req, res, next) => {
if (Math.random() < SAMPLE_RATE) {
logger.verbose({
// 详细日志信息...
});
} else {
logger.info({
// 基础日志信息...
});
}
next();
});
const fs = require('fs');
// 确保日志文件权限适当
fs.chmod('access.log', 0o640, (err) => {
if (err) logger.error('设置日志文件权限失败', err);
});
const request = require('supertest');
const app = require('../app');
describe('日志中间件', () => {
it('应该记录GET请求', (done) => {
const spy = jest.spyOn(console, 'log');
request(app)
.get('/')
.expect(200)
.end(() => {
expect(spy).toHaveBeenCalledWith(
expect.stringContaining('GET /')
);
spy.mockRestore();
done();
});
});
});
const express = require('express');
const winston = require('winston');
const DailyRotateFile = require('winston-daily-rotate-file');
// 创建Express应用
const app = express();
// 配置日志记录器
const logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.Console({
format: winston.format.simple()
}),
new DailyRotateFile({
filename: 'access-%DATE%.log',
datePattern: 'YYYY-MM-DD',
zippedArchive: true,
maxSize: '20m',
maxFiles: '30d'
})
]
});
// 访问日志中间件
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
logger.info({
message: 'request',
method: req.method,
url: req.url,
status: res.statusCode,
duration: `${duration}ms`,
ip: req.ip,
userAgent: req.get('user-agent')
});
});
next();
});
// 示例路由
app.get('/', (req, res) => {
res.send('Welcome to the home page');
});
// 错误处理中间件
app.use((err, req, res, next) => {
logger.error({
message: err.message,
stack: err.stack,
url: req.url,
method: req.method
});
res.status(500).send('Internal Server Error');
});
// 启动服务器
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
logger.info(`Server started on port ${PORT}`);
});
通过本文的介绍,您应该已经掌握了在Node.js应用中实现访问日志中间件的完整方法。从基础实现到高级功能,从性能优化到安全考虑,良好的日志记录策略将为您的应用提供宝贵的运行洞察和故障排查依据。
记住,日志记录不是一成不变的,应该根据实际应用需求不断调整和优化。建议定期审查日志内容、格式和保留策略,确保它们始终满足业务和技术需求。
”`
这篇文章共计约2000字,涵盖了从基础到高级的Node.js日志中间件实现方法,采用Markdown格式编写,包含代码示例、结构化标题和实用建议。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。