ㅇㅅㅇ

[NODE.JS] winston 사용하여 로그를 기록해보기 본문

프로그래밍/NODE.JS

[NODE.JS] winston 사용하여 로그를 기록해보기

소 아 2022. 10. 2. 09:00

로그는 시스템을 개발하는 중에만 필요한 것이 아니라 시스템을 효과적으로 운영하기 위해서 반드시 체계적으로 로그 관리를 해야 한다. 시스템을 운영하다 보면 예기치 못한 오류가 발생할 수 있고, 때로는 치명적인 오류로 인해 시스템이 다운되는 상황도 발생할 수 있다. 그래서 개발자가 로그 관리 프로그램을 구현하는 것은 필수라 할 수 있습니다. 이번 포스팅에서는 Node.js의 winston 모듈을 사용해서 로그를 로그 레벨 및 파일로 관리하는 방법을 알아보고자 한다.

로그 기록을 위해 사용할 모듈

서론에 기재한 winston와 함께 winston-daily-rotate-file, app-root-path를 사용하고자 한다.

  • winston : 실제 서버를 운영할 때 파악이 어렵고 서버가 종료되는 순간에 쌓여 있던 로그들이 사라지는 console를 대체하기 위한 모듈로 로그를 외부 파일에 저장해 관리할 수 있도록 해주는 모듈이다.
  • winston-daily-rotate-file : winston 확장모듈로 로그 파일을 일자별로 생성하는데 필요하다.
  • app-root-path : app이 실행되는 프로젝트 루트를 찾아주는 모듈이다.

사용방법

  1. 터미널에서 winston, winston-daily-rotate-file, app-root-path 모듈 설치한다.
    npm install winston
    npm install winston-daily-rotate-file
    npm install app-root-path
  2. winston 폴더 및 winston 폴더 안에 logger.js 생성하고 아래와 같이 입력한다.
    1. 설치한 모듈 및 사용할 함수 불러오기, 저장 위치 정의하기
      // winston/logger.js
      
      const winston = require("winston");
      const winstonDaily = require("winston-daily-rotate-file");
      const appRoot = require("app-root-path");
      const { createLogger } = require("winston");
      const process = require("process"); // 프로그램과 관련된 정보를 나타내는 객체 모듈
      
      const logDir = `${appRoot}/logs`; // logs 디렉토리 하위에 로그 파일 저장
      
      const { combine, timestamp, label, printf } = winston.format; // winston.format의 내부 모듈을 가져옴
    2. 로그출력 포맷 설정 정의 및 info, error 로그 파일 설정 정의
      // winston/logger.js
      
      ...
      
      // 1. 로그 출력 포맷 정의, printf : 실제 출력 양식
      const logFormat = printf(({ level, message, label, timestamp }) => {
          return `${timestamp} [${label}] ${level}: ${message}`; 
          // timestamp : 시간, label : 시스템 네임, level : 정보, 에러, 경고 인지 구분, message :개발자가 남긴 로그 메세지
      });
      
      // 2. logger 생성
      const logger = createLogger({ 
          format: combine(label({ label: "NODE_PROJECT" }), timestamp(), logFormat), 
          // 포맷 종류에는 simple과 combine 있음, winston이용시에는 combine을 주로 인용
          transports: [
              new winstonDaily({ // log 파일 설정
                level: "info", // 심각도
                datePattern: "YYYY-MM-DD", // 날짜포맷방식
                dirname: logDir, // 디렉토리 파일 이름 설정
                filename: "%DATE%.log", // 파일이름 설정, %DATE% - 자동으로 날짜가 들어옴
                maxSize: "20m", // 로그파일 크기, 정의하지 않으면 데이터가 쌓이고, 제안하면 초과시 앞의 데이터를 지움
                maxFiles: "30d", // 최근 30일치 로그 파일만 보관
              }),
              new winstonDaily({ // 로그 파일 설정
                level: "error", // 심각도
                datePattern: "YYYY-MM-DD",
                dirname: logDir, // 디렉토리 파일 이름 설정
                filename: "%DATE%.error.log", // 파일이름 설정, 에러파일을 구분해 별도보관
                maxSize: "20m", // 로그파일 크기
                maxFiles: "30d", // 최근 30일치 로그 파일만 보관
              }),
            ],
      });
    3. 개발 환경일 경우, 터미널에서도 로그를 확인할 수 있도록 추가 설정(process 모듈 사용)
      // winston/logger.js
      
      ...
      
      if (process.env.NODE_ENV != "prod") { // NODE_ENV환경 설정가능, 환경이 prod가 아닐 경우(개발환경일 경우), process 모듈을 통해 터미널 창에 로그를 확인할 수 있도록 설정
          logger.add(
          new winston.transports.Console({
              format: winston.format.combine(
              winston.format.colorize(), // 로그 출력시 구분할 수 있도록 색상 추가
              winston.format.simple() // 메세지 형태를 단순하게 설정, prod이 아닐 경우 폴더와 터미널창에서 로그를 확인할 수 있도록
              ),
          })
          );
      }​
    4. 내보내기
      // winston/logger.js
      
      ...
      
      // 4. logger 내보내기
      module.exports = logger;
    전체소스
    // winston/logger.js
    
    // 1. 설치한 모듈 및 사용할 함수 불러오기, 저장 위치 정의하기
    const winston = require("winston");
    const winstonDaily = require("winston-daily-rotate-file");
    const appRoot = require("app-root-path");
    const { createLogger } = require("winston");
    const process = require("process"); // 프로그램과 관련된 정보를 나타내는 객체 모듈
    
    const logDir = `${appRoot}/logs`; // logs 디렉토리 하위에 로그 파일 저장
    
    const { combine, timestamp, label, printf } = winston.format; // winston.format의 내부 모듈을 가져옴
    
    // 2-1. 로그 출력 포맷 정의, printf : 실제 출력 양식
    const logFormat = printf(({ level, message, label, timestamp }) => {
        return `${timestamp} [${label}] ${level}: ${message}`; 
        // timestamp : 시간, label : 시스템 네임, level : 정보, 에러, 경고 인지 구분, message :개발자가 남긴 로그 메세지
    });
    
    // 2-2. logger 생성
    const logger = createLogger({ 
        format: combine(label({ label: "NODE_PROJECT" }), timestamp(), logFormat), 
        // 포맷 종류에는 simple과 combine 있음, winston이용시에는 combine을 주로 인용
        transports: [
            new winstonDaily({ // log 파일 설정
              level: "info", // 심각도
              datePattern: "YYYY-MM-DD", // 날짜포맷방식
              dirname: logDir, // 디렉토리 파일 이름 설정
              filename: "%DATE%.log", // 파일이름 설정, %DATE% - 자동으로 날짜가 들어옴
              maxSize: "20m", // 로그파일 크기, 정의하지 않으면 데이터가 쌓이고, 제안하면 초과시 앞의 데이터를 지움
              maxFiles: "30d", // 최근 30일치 로그 파일만 보관
            }),
            new winstonDaily({ // 로그 파일 설정
              level: "error", // 심각도
              datePattern: "YYYY-MM-DD",
              dirname: logDir, // 디렉토리 파일 이름 설정
              filename: "%DATE%.error.log", // 파일이름 설정, 에러파일을 구분해 별도보관
              maxSize: "20m", // 로그파일 크기
              maxFiles: "30d", // 최근 30일치 로그 파일만 보관
            }),
          ],
    });
    
    // 3. 개발 환경일 경우, 터미널에서도 로그를 확인할 수 있도록 추가 설정(process 모듈 사용)
    if (process.env.NODE_ENV != "prod") { // NODE_ENV환경 설정가능, 환경이 prod가 아닐 경우(개발환경일 경우), process 모듈을 통해 터미널 창에 로그를 확인할 수 있도록 설정
        logger.add(
        new winston.transports.Console({
            format: winston.format.combine(
            winston.format.colorize(), // 로그 출력시 구분할 수 있도록 색상 추가
            winston.format.simple() // 메세지 형태를 단순하게 설정, prod이 아닐 경우 폴더와 터미널창에서 로그를 확인할 수 있도록
            ),
        })
        );
    }
    
    // 4. logger 내보내기
    module.exports = logger;
  3. winston/logger.js를 나와 winston.js파일을 생성해 적용되었는지 파일을 가져와 실행해보기
    // winston/logger.js에서 export한 logger 가져오기
    const logger = require("./winston/logger");
    
    // info와 error 로그 구현
    logger.info("Hello world!"); 
    logger.error("고객 정보 저장 중 에러가 발생했습니다.");

결과

터미널
logs/2022-10-02.log
logs/2022-10-02.error.log

 

참고

logs/2022-10-02.log파일에는 info와 error 로그가 함께 들어와 있는데 이는 winston에 설정된 level이 info보다 상위인 로그들(0인 error, 1인 warn)이 함께 들어와서라고 한다.

// npm logging levels
{
  error: 0,
  warn: 1,
  info: 2,
  http: 3,
  verbose: 4,
  debug: 5,
  silly: 6
}

level에 따라 색상 지정 등 그 외 다양한 기능을 지원하던데 필요할 때 공식문서를 참고해 만들어 보면 좋을 것 같다.

출처

개발자의 품격 부트캠프 강의

 

winston

A logger for just about everything.. Latest version: 3.8.2, last published: 24 days ago. Start using winston in your project by running `npm i winston`. There are 17061 other projects in the npm registry using winston.

www.npmjs.com

 

[NODE] 📚 Winston 모듈 사용법 - 서버 로그 관리

Winston 모듈 어떤 서버든지 실제로 서비스를 운영하려면 로그를 꼼꼼히 남기는 것은 필수이다. Log는 에러를 파악할 수 있는 열쇠이기 때문에 서버를 운영한다고 하면 로그 시스템을 구축해서 시

inpa.tistory.com

 

Comments