winston ( Node.js logger )

juhojung·2022년 3월 13일
0

nodejs

목록 보기
3/6

winston logger

https://www.npmjs.com/package/winston : logging library
https://www.npmjs.com/package/p-queue : promise callstack management

winston 은 로깅 라이브러리로
로그를 관리하고싶은데, 하드하게 관리하는건 귀찮을때 사용하기 편한 라이브러리다.
pino라는 로깅 라이브러리도 검토해봤지만, 기존 프로젝트에 큰 영향을 끼치지않고
독립적으로 쓰려고 하면 winston이 좋다.

winston의 기본 사용법은 어떻게 쓰는지는 쉽게 알 수 있으니 그부분에 description은 생략.

나는 추가로 winston-daily-rotate-file ( https://www.npmjs.com/package/winston-daily-rotate-file ) 라이브러리를 미들웨어로 사용해서, 매일 자동으로 새로운 파일로 생성되고, transport 생성으로 관리 하였다.

import winstonDaily from "winston-daily-rotate-file";
....
const log_file_max_size = 1048576 * 5; // 100MB
....
new winstonDaily({
	level: "AnyLevelYouWant", // info, error, debug...
	datePattern: "YYYYMMDD", // 20220310
	dirname: path.join(__dirname, "../../logs/info"), // where is my log locate
    filename: `altgap_%DATE%.log`, // filename rule
    maxSize: log_file_max_size, // 파일당 최대 사이즈
    maxFiles: 14, // 최대 파일 개수
}),

위와 같이 winston-daily-rotate-file 로 winston.transport 를 정의했다.

그런데 이렇게 해서 잘 사용하고있었는데,
프로세스가 빈번하게 crash & 재시작이 되는 문제가 발생했다.
원인은 해당 로깅 모듈을 여러 곳에 사용하고있었는데 그 중 bot 은 매 틱마다 ( 루프마다 ) 특정 이벤트를 호출하는 기능을 했다.
그러니, File I/O를 매 틱마다 실행하여 중첩되면서 app crash 가 계속 발생했던 것이다.

https://www.npmjs.com/package/p-queue
그래서 p-queue 라이브러리를 사용했다. p-queue 는 여러 promise 객체들을 queue에 넣어서 동시에 순차적으로 실행시켜주는 기능을 한다.

그렇게 p-queue 를 적용하면

import pqueue from "p-queue";
const queue = new pqueue({ concurrency: 4, intervalCap: 1, interval: 10 }); // 동시에 최대 4개 0.01초마다
....
const logger = winston.createLogger({
    format: combine(
        timestamp({
            format: "YYYY-MM-DD HH:mm:ss",
        }),
        customFormat
    ),
    levels: levels,
    transports: transport,
});
const log = async (type: string, msg: string) => {
    await queue.add(function () { // queue 에 promise 객체를 추가
        return Promise.resolve(logger.log(type, msg)); // looger.log 호출
    }); 
};

winston.ts

import pqueue from "p-queue";
import winston, { createLogger, format, transports } from "winston";
import winstonDaily from "winston-daily-rotate-file";
import path from "path";
const queue = new pqueue({ concurrency: 4, intervalCap: 1, interval: 10 });

const { combine, timestamp, printf, colorize } = format;

const customFormat = printf(info => `${info.timestamp} ${info.level}: ${info.message}`);

const log_file_max_size = 1048576 * 5; // 100MB

const levels = { trade: 0, error: 1, debug: 2, info: 3, warn: 4 };

const transport = [
    new winston.transports.Console(),
    new winstonDaily({
        level: "info",
        datePattern: "YYYYMMDD",
        dirname: path.join(__dirname, "../../logs/info"),
        filename: `altgap_%DATE%.log`,
        maxSize: log_file_max_size,
        maxFiles: 14,
    }),
    new winstonDaily({
        level: "warn",
        datePattern: "YYYYMMDD",
        dirname: path.join(__dirname, "../../logs/warn"),
        filename: `altgap_%DATE%.warn.log`,
        maxSize: log_file_max_size,
        maxFiles: 30,
    }),
    new winstonDaily({
        level: "error",
        datePattern: "YYYYMMDD",
        dirname: path.join(__dirname, "../../logs/error"),
        filename: `altgap_%DATE%.error.log`,
        maxSize: log_file_max_size,
        maxFiles: 50,
    }),
    new winstonDaily({
        level: "debug",
        datePattern: "MMDD",
        dirname: path.join(__dirname, "../../logs/debug"),
        filename: `altgap_%DATE%.debug.log`,
        maxSize: log_file_max_size,
        maxFiles: 100,
    }),
    new winstonDaily({
        level: "trade",
        datePattern: "YYYYMMDD",
        dirname: path.join(__dirname, "../../logs/trade"),
        filename: `altgap_%DATE%.trade.log`,
        maxSize: log_file_max_size,
        maxFiles: 50,
    }),
];

const logger = winston.createLogger({
    format: combine(
        timestamp({
            format: "YYYY-MM-DD HH:mm:ss",
        }),
        customFormat
    ),
    levels: levels,
    transports: transport,
});

const stream = {
    write: message => {
        logger.info(message);
    },
};

const log = async (type: string, msg: string) => {
    await queue.add(function () {
        return Promise.resolve(logger.log(type, msg));
    });
};

export { log, stream };

끝 👋

profile
"어찌 할 수 없는 일에 대해 고민하는 시간은 낭비일 뿐이다."

0개의 댓글