Node.js Winston:構建工業級的日誌管理與分析系統

在開發階段我們習慣使用 console.log,但在正式環境,我們需要更專業的解決方案:將紀錄 (Logs) 存入磁碟、區分優先等級、並在檔案過大時自動切割。Winston 是 Node.js 生態系中最穩定且功能最強大的日誌框架。

為什麼不用 console.log?

  1. 等級分明:Winston 支援標準的 RFC5424 等級(error, warn, info, http, verbose, debug, silly),讓你只需輸出當前環境關心的資訊。
  2. 多重輸出 (Transports):可以同時將日誌印在控制台、存入本地檔案,甚至即時發送到遠端伺服器 (HTTP)。
  3. 格式化 (Formatting):能輕鬆將日誌轉為 JSON 格式,方便後續對接 ELK (Elasticsearch/Logstash/Kibana) 等分析系統。

安裝與基礎配置

安裝核心套件:npm install winston

建立 logger.js

const winston = require('winston');

const logger = winston.createLogger({
  level: 'info', // 僅紀錄 info 及以上等級
  format: winston.format.combine(
    winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
    winston.format.json() // 正式環境建議使用 JSON
  ),
  transports: [
    // 專門儲存 Error
    new winston.transports.File({ filename: 'logs/error.log', level: 'error' }),
    // 儲存所有紀錄
    new winston.transports.File({ filename: 'logs/combined.log' }),
  ],
});

// 開發環境加開彩色控制台輸出
if (process.env.NODE_ENV !== 'production') {
  logger.add(
    new winston.transports.Console({
      format: winston.format.combine(winston.format.colorize(), winston.format.simple()),
    })
  );
}

module.exports = logger;

自動滾動與清理 (Log Rotation)

為了防止日誌檔案無限制增長導致硬碟爆滿,建議搭配 winston-daily-rotate-file 使用:

npm install winston-daily-rotate-file
const DailyRotateFile = require('winston-daily-rotate-file');

const rotateTransport = new DailyRotateFile({
  filename: 'logs/application-%DATE%.log',
  datePattern: 'YYYY-MM-DD',
  zippedArchive: true, // 自動壓縮舊檔案
  maxSize: '20m', // 單個檔案最大 20MB
  maxFiles: '14d', // 保留最近 14 天的紀錄
});

logger.add(rotateTransport);

實戰建議:結合 Express 的 Morgan

如果你在開發 Web 應用,可以將 Morgan 的 HTTP 存取日誌導向 Winston,實現日誌大一統:

const morgan = require('morgan');
const logger = require('./logger');

app.use(
  morgan('combined', {
    stream: { write: (message) => logger.info(message.trim()) },
  })
);

總結

  1. Winston 是產品化應用的必備組件。
  2. 透過 Transports,你可以讓日誌在正確的時間出現在正確的地方(檔案、Slack、雲端)。
  3. 務必實作 Rotation (滾動) 策略,這是伺服器維運的基本功。