# 日志与调试

URL: https://caijiao.org/express/chapter9/3-logger
Source: docs/express/chapter9/3-logger.md
Description: 本章节将介绍如何在 Express 项目中进行日志记录和调试，帮助开发者更高效地追踪和解决问题。通过使用适当的日志记录和调试工具，能够更好地监控应用运行情况，捕获错误信息，提升开发和维护效率。

在开发和维护一个 Express 应用时，日志记录和调试是至关重要的环节。它们帮助开发者监控应用运行情况，及时发现和解决潜在的问题，尤其是在生产环境中，合适的日志系统能够显著提高问题排查效率。在本章节中，我们将介绍如何在 Express 项目中使用日志记录和调试工具。

## 1. 日志记录的重要性

日志是应用程序记录其运行状态、行为、错误等信息的主要方式。良好的日志记录可以帮助开发者：

- 追踪请求的生命周期。
- 记录应用的关键事件。
- 及时发现并定位应用错误。
- 提供调试信息和系统运行健康情况。

为了方便日志管理和分析，通常会使用专门的日志库和工具。

## 2. 使用 `morgan` 记录请求日志

`morgan` 是一个流行的 HTTP 请求日志中间件，能够自动记录每一个 HTTP 请求的相关信息（如请求路径、响应状态码、响应时间等）。它能够帮助开发者轻松追踪请求和响应的状态。

### 2.1 安装 `morgan`

首先，安装 `morgan` 中间件：

```bash
npm install morgan
````

### 2.2 配置 `morgan`

在 `app.js` 中配置并使用 `morgan`：

```js
const express = require('express');
const morgan = require('morgan');

const app = express();

// 使用 morgan 中间件记录请求日志
app.use(morgan('dev'));  // 'dev' 格式将记录简洁的请求日志信息，包括请求方法、URL、状态码和响应时间

app.get('/', (req, res) => {
  res.send('Hello, World!');
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});
```

`morgan` 提供了多种日志格式，如 `combined`、`tiny`、`dev`、`common` 等，开发者可以根据需要选择合适的格式。`dev` 格式通常在开发环境中使用，它会输出简洁且颜色高亮的日志。

### 2.3 日志输出到文件

在生产环境中，除了控制台输出，通常还需要将日志保存到文件中，以便后续分析和审计。我们可以使用 `fs`（文件系统）模块将日志写入文件。

首先，创建一个写入流并将日志输出到文件：

```js
const fs = require('fs');
const path = require('path');
const morgan = require('morgan');

// 创建日志写入流
const logStream = fs.createWriteStream(path.join(__dirname, 'access.log'), { flags: 'a' });

// 使用 morgan 中间件，将日志写入文件
app.use(morgan('combined', { stream: logStream }));
```

`combined` 是 `morgan` 提供的标准日志格式，它会记录详细的请求信息，包括请求来源、响应时间、状态码、请求头等。

## 3. 使用 `winston` 进行日志管理

`winston` 是一个功能强大的日志库，支持多种日志级别、输出到不同的目标（控制台、文件、远程服务器等），并能够为不同环境配置不同的日志策略。它是一个适用于生产环境的日志记录工具。

### 3.1 安装 `winston`

首先，安装 `winston`：

```bash
npm install winston
```

### 3.2 配置 `winston`

在项目中配置 `winston`，设置日志级别和输出目标：

```js
const winston = require('winston');

// 创建一个 winston logger 实例
const logger = winston.createLogger({
  level: 'info',  // 默认日志级别，'info' 级别包括 info、warn、error
  transports: [
    // 输出到控制台
    new winston.transports.Console({
      format: winston.format.combine(
        winston.format.colorize(),
        winston.format.simple()
      ),
    }),
    // 输出到文件
    new winston.transports.File({
      filename: 'combined.log',
      level: 'info', // 记录 info 级别及以上的日志
    }),
  ],
});

module.exports = logger;
```

在上面的配置中，我们创建了一个 `logger` 实例，并将日志输出到控制台和文件 `combined.log`。可以通过设置不同的 `level` 来控制输出的日志级别。例如，`info` 级别会包括 `info`、`warn`、`error` 级别的日志。

### 3.3 使用 `winston` 记录日志

在应用中使用 `winston` 记录日志：

```js
const logger = require('./logger');

// 记录 info 级别的日志
logger.info('This is an info message');

// 记录 warn 级别的日志
logger.warn('This is a warning message');

// 记录 error 级别的日志
logger.error('This is an error message');
```

### 3.4 自定义日志格式

你可以自定义日志输出格式，以便更好地适应项目需求。比如，我们可以使用 `winston.format.printf` 来定义一个自定义的日志格式：

```js
const logger = winston.createLogger({
  level: 'info',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.printf(({ timestamp, level, message }) => {
      return `${timestamp} [${level}]: ${message}`;
    })
  ),
  transports: [
    new winston.transports.Console(),
    new winston.transports.File({ filename: 'app.log' }),
  ],
});
```

自定义的日志格式包括了时间戳、日志级别和消息内容，方便开发者更清晰地看到每一条日志的上下文信息。

## 4. 调试工具：使用 `debug` 库

在开发过程中，`debug` 是一个轻量级的调试工具，可以帮助开发者在控制台输出调试信息。它允许根据需要启用或禁用调试信息的输出。

### 4.1 安装 `debug`

首先，安装 `debug` 库：

```bash
npm install debug
```

### 4.2 配置 `debug`

在代码中使用 `debug` 打印调试信息：

```js
const debug = require('debug')('app:startup');

debug('This is a debug message');
```

### 4.3 启用调试信息

在启动应用时，可以通过设置环境变量来启用调试信息：

```bash
DEBUG=app:* node app.js
```

这会打印所有以 `app:` 开头的调试信息。如果只需要某一部分的调试信息，可以按模块过滤：

```bash
DEBUG=app:startup node app.js
```

这样，只有 `app:startup` 相关的调试信息会被输出。

## 5. 总结

在本章节中，我们学习了如何在 Express 应用中使用日志记录和调试工具：

* **`morgan`**：用于记录 HTTP 请求日志，可以输出到控制台或文件中，便于开发者跟踪请求信息。
* **`winston`**：一个功能强大的日志库，支持多种日志级别和日志输出目标，适用于生产环境中的日志管理。
* **`debug`**：一个轻量级的调试工具，帮助开发者输出调试信息并进行调试。

通过使用合适的日志记录和调试工具，我们可以更高效地监控应用运行情况，发现并解决潜在问题，从而提高开发效率和应用稳定性。
