즐겁게 개발을...

개발보다 게임이 더 많이 올라오는 것 같은...

개발/Node.js

[2021.03] Winston패키지를 이용한 Logger 클래스

다물칸 2021. 3. 26. 15:06
728x90

Winston을 이용한 Logger 패키지이다. 사용법은 다음과 같다. 

const logger = require('./src/helper/logger').logger;

logger.info('===================================')
logger.info('Program Started!!');
logger.info('-----------------------------------')

사용 패키지

path

fs

 

winston-daily-rotate-file

winston

moment-timezone

 

환경설정

"Logger": {
    "TimeZone": "Asia/Seoul",
    "logPath": "logs",
    "logFile": "logfilename",
    "loglevel": "debug",
    "maxSize": "20m",
    "maxFiles": "7d",
    "datePattern": "YYYY-MM-DD",
    "logformat": "%{color}%{time:2006-01-02 15:04:05.000 MST} [%{module}] %{shortfunc} -> %{level:.4s} %{id:03x}%{color:reset} %{message}"
  }
  • TimeZone : 시간 표시 할 때 타임존에 따라 표시한다. (기본값은 Asia/Seoul)
  • logPath : 절대경로를 입력해 다른 위치에 로그를 남길 수도 있고, 위 처럼 상대경로를 입력하면 프로그램에 경로를 생성해 로그를 남기도록 했다. 본 소스에서는 ../.. 에 남기도록 했으니 위치가 틀린 경우 이 부분(46 라인)을 수정하면 된다.
  • logfile : 로그파일 이름 (접두어)
  • loglevel: 로그레벨을 설정한다. (debug > info > error)
  • maxSize: 설정한 용량이 넘어가면 날짜와 상관없이 파일을 추가 생성한다.
  • maxFiles: 로그파일의 개수를 설정하는 것인데 7d는 7일치의 로그만 유지하겠다는 의미이다. maxSize에 의해서 하루에 1개이상 로그파일이 생길 경우도 포함되는지는 체크하지 않았다. 
  • datePattern: 파일명에 붙는 날짜의 패턴을 정의한다.
  • logformat : 로그 메시지 포맷이다. 만약 중앙에서 로그를 파싱해야 한다면 이것을 적절하게 수정하면 된다.

소스 : logger.js

/**
 *  Copyright 2021 Benjamin Shin.
 *  + Logger class
 */
 'use strict'

var Path = require('path');
var fs = require('fs');
var DailyRotateFile = require('winston-daily-rotate-file');
var { createLogger, format, transports } = require('winston');

const appCfg = require('../../config/config.json');
const { Logger } = appCfg;
const { combine, colorize, splat, printf, timestamp } = format;

const moment = require('moment-timezone');
const keysToFilter = ['password', 'token'];

const formatter = printf((info) => {
  const { level, message, timestamp: ts, ...restMeta } = info;
  const tz = moment().tz(Logger.TimeZone ? Logger.TimeZone : 'Asia/Seoul').format(ts);

  const module = restMeta.module ? restMeta.module : '';
  const fcn = restMeta.fcn ? restMeta.fcn : '';
  const reason = restMeta && restMeta.reason && Object.keys(restMeta.reason).length 
    ? JSON.stringify(restMeta.reason, (key, value) => keysToFilter.includes(key) ? '******' : value, 2)
    : restMeta.reason instanceof Object 
    ? ''
    : restMeta.reason;
  const params = restMeta && restMeta.params && Object.keys(restMeta.params).length 
  ? JSON.stringify(restMeta.params, (key, value) => keysToFilter.includes(key) ? '******' : value, 2)
  : restMeta.params instanceof Object 
  ? ''
  : restMeta.params;

  return `${tz} [${module}>${fcn}] [${level.padStart(5, ' ')}] ${message} ${reason ? `++ Reason: ${reason}` : ''} ${params ? `++ Params: ${params}` : ''}`;
});

let trans = [];

trans = [new transports.Console({
  level: Logger.loglevel,
  format: combine(colorize({ all: true })),
})];

const logPath = Logger.logPath.indexOf('/') > 0 ? Logger.logPath : Path.join(__dirname, '../..', Logger.logPath);
if (!fs.existsSync(logPath)) {
  fs.mkdirSync(logPath);
}

const logger = createLogger({
  level: Logger.loglevel,
  format: combine(splat(), colorize(), timestamp(), formatter),
  transports: [
    ...trans,
    new DailyRotateFile({
      maxSize: Logger.maxSize,
      maxFiles: Logger.maxFiles,
      datePattern: Logger.datePattern,
      zippedArchive: true,
      filename: `${logPath}/${Logger.loglevel}-%DATE%.log`
    })
  ]
});

module.exports.logger = logger;
반응형