NodeJs 日志输出到以每天的日期命名的文件夹中

服务端的日志是非常重要的,可以帮助我们故障排查与问题定位。混乱的日志系统会导致我们花费大量时间去定位问题,查找日志。所以,把日志输出到以每天的日期命名的文件夹中,并把各种日志类型分类,可以大大提高我们的效率。

我们期望把输出成以下的结构:

markdown 复制代码
- logs/
  - 2024-04-05/
    - error.log
    - info.log
  - 2024-04-06/
    - error.log
    - info.log

下面我们以winston为例子说明,先引入Winson和winston-daily-rotate-file

js 复制代码
import * as winston from 'winston';
// 这是 Winston 的一个插件,用于实现日志文件的每日轮转,确保日志文件不会无限增长,而是根据日期进行切割和管理。
import 'winston-daily-rotate-file';

1. 定义好日志的类型以及输出的格式

js 复制代码
const logTypes = {
  INFO: 'info',
  ERROR: 'error',
} as const;

type LogTypeUnion = (typeof logTypes)[keyof typeof logTypes];

interface ExtendedLogger extends winston.Logger {
  track: (prefix?: string | number, message?: number | string) => void;
}

// 创建日志格式 
// 假设type为info, 2024-04-06 12:22:29 [info]: this is log message!
const getBaseFormat = () =>
  winston.format.combine(
    winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
    winston.format.printf(({ timestamp, message, type }) => {
      return `${timestamp} [${type}]: ${message}`;
    })
  );

2. 创建日志文件的 transports

在 Winston 中,传输器(transports)是用于将日志消息从应用程序中的源传送到目的地的组件。传输器决定了日志消息的最终去向,比如控制台输出、文件存储、数据库存储等。

js 复制代码
const logDirectory = 'logs';

// 创建控制台的 transport,用于控制台打印
const getBaseConsole = () =>
  new winston.transports.Console({
    format: getBaseFormat(),
  });

const getBaseTransport = (type: LogTypeUnion) =>
  new winston.transports.DailyRotateFile({
    dirname: `${logDirectory}/%DATE%`,
    filename: `${type}.log`,
    // 如果想要测试的话,这边可以改成 YYYY-MM-DD-hh-mm-ss
    datePattern: 'YYYY-MM-DD',
  });

这样就创建了一个transport,当前是2024-04-06,作用是会把日志输出到logs/2024-04-06/{type}.log下面,但是现在还不会每天自动更新,只有第一次会创建,因为DailyRotateFile本来是适用于每天更新文件名的,而不是文件夹名,所以我们下面还要改一下。

3. 创建logger

js 复制代码
const getBaseLogger = (type: LogTypeUnion) => {
  // 获取上面的transport
  let baseTransport = getBaseTransport(type);
  // 创建一个 Winston 日志记录器实例
  const logger = winston.createLogger({
    level: 'info',
    format: getBaseFormat(),
    transports: [baseTransport, getBaseConsole()],
  }) as ExtendedLogger;
  // 每天需要重新创建 transport,来实现每天新建文件夹,并写入日志
  baseTransport.on('rotate', () => {
    baseTransport = getBaseTransport(type);
  });
  // 添加 track 方法
  logger.track = (
    ...arg: [number | string | undefined, number | string | undefined]
  ) => {
    const length = arg.length;
    const prefix = length > 1 ? arg[0] : '';
    const message = length > 1 ? arg[1] : arg[0] || '';
    const formattedMessage = prefix ? `|${prefix}| ${message}` : `${message}`;
    logger.log({
      level: 'info',
      message: formattedMessage,
      type,
    });
  };
  return logger as ExtendedLogger;
};

4. 根据type批量生成日志示例

js 复制代码
const loggers: Record<LoggerTypeUnion, ExtendedLogger> = Object.values(
  logTypes
).reduce(
  (acc, type) => ({ ...acc, [`${type}Logger`]: getBaseLogger(type) }),
  {} as Record<LoggerTypeUnion, ExtendedLogger>
);

export const { infoLogger, errorLogger } = loggers;

5. 测试一下代码

baseTransport中的datePattern改成YYYY-MM-DD-hh-mm-ss, 然后测试,发现每秒都会生成一个文件夹,测试成功后可以把datePattern改回去,或者可以拓展成自己想要的时间,比如每分钟命名的文件夹等等。

js 复制代码
import { infoLogger, errorLogger } from '.';

async function demo() {
  while (true) {
    infoLogger.track('Hello World ' + new Date().getSeconds());
    errorLogger.track('Hello World ' + new Date().getSeconds());
    console.log(new Date().getSeconds());
    await new Promise(r => setTimeout(r, 1000));
  }
}

demo();

完整代码可以查看我的github

相关推荐
丁总学Java15 分钟前
微信小程序-npm支持-如何使用npm包
前端·微信小程序·npm·node.js
看到请催我学习2 小时前
如何实现两个标签页之间的通信
javascript·css·typescript·node.js·html5
NiNg_1_2346 小时前
npm、yarn、pnpm之间的区别
前端·npm·node.js
余生H7 小时前
前端的全栈混合之路Meteor篇:关于前后端分离及与各框架的对比
前端·javascript·node.js·全栈
Ink8 小时前
从底层看 path.resolve 实现
前端·node.js
奔跑吧邓邓子10 小时前
npm包管理深度探索:从基础到进阶全面教程!
前端·npm·node.js
知否技术1 天前
为什么nodejs成为后端开发者的新宠?
前端·后端·node.js
谢尔登1 天前
【Node.js】worker_threads 多线程
node.js
osnet1 天前
showdoc二次开发
node.js·vue
泯泷1 天前
「生产必看」在企业环境中正确使用 Node.js 的九大原则
前端·后端·node.js