怎样使用Nodejs创建访问日志记录的中间件

发布时间:2021-09-24 10:01:37 作者:柒染
来源:亿速云 阅读:206
# 怎样使用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');
});

2.2 输出示例

2023-05-20T08:30:00.000Z - GET /
2023-05-20T08:31:23.456Z - POST /api/users

三、增强日志功能

3.1 记录更多信息

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();
});

3.2 响应时间计算

app.use((req, res, next) => {
  const start = Date.now();
  
  res.on('finish', () => {
    const duration = Date.now() - start;
    console.log(`请求处理时间: ${duration}ms`);
  });
  
  next();
});

四、日志格式化与存储

4.1 使用Winston日志库

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();
});

4.2 日志格式示例

{
  "message": "Request received",
  "method": "GET",
  "url": "/api/products",
  "ip": "::1",
  "timestamp": "2023-05-20T08:45:12.345Z"
}

五、高级日志功能实现

5.1 日志轮转(Log Rotation)

使用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'
}));

5.2 敏感信息过滤

app.use((req, res, next) => {
  const sanitizedHeaders = { ...req.headers };
  
  // 过滤敏感信息
  if (sanitizedHeaders['authorization']) {
    sanitizedHeaders['authorization'] = '***REDACTED***';
  }
  
  logger.info({
    headers: sanitizedHeaders,
    // 其他日志字段...
  });
  
  next();
});

5.3 错误日志记录

// 错误处理中间件
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!');
});

六、性能优化考虑

6.1 异步日志记录

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();
});

6.2 采样率控制

const SAMPLE_RATE = 0.1; // 10%的请求记录详细日志

app.use((req, res, next) => {
  if (Math.random() < SAMPLE_RATE) {
    logger.verbose({
      // 详细日志信息...
    });
  } else {
    logger.info({
      // 基础日志信息...
    });
  }
  next();
});

七、安全最佳实践

7.1 避免记录敏感数据

7.2 日志文件权限

const fs = require('fs');

// 确保日志文件权限适当
fs.chmod('access.log', 0o640, (err) => {
  if (err) logger.error('设置日志文件权限失败', err);
});

7.3 GDPR合规考虑

八、测试日志中间件

8.1 单元测试示例

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();
      });
  });
});

8.2 集成测试考虑

九、部署与监控

9.1 日志收集方案

9.2 监控指标

9.3 报警设置

十、完整实现示例

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格式编写,包含代码示例、结构化标题和实用建议。

推荐阅读:
  1. nodejs 定时访问网页
  2. NodeJS如何创建WebSocket监听

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

nodejs

上一篇:如何实现存储过程返回数组对象

下一篇:数据库查询性能需注意的有哪些

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》