체계적으로 로그를 관리하면,
로그 시스템 개발 혹은 시스템의 운영을 효과적으로 할 수 있습니다.
예기치 못한 오류로 시스템이 다운되는 상황에서 유연하게 대처할 수 있습니다.
이번 포스팅에서는 Node.js에서 윈스턴 모듈을 사용해,
체계적으로, 로그 레벨과 파일로 로그를 관리하는 방법에 대해 알아보겠습니다.
윈스턴(winston)과, 윈스턴 데일리 로테이트 파일(winston-daily-rotate-file)을 사용하면,
아래 스크린숏과 같이, 로그 기록을 파일로 관리할 수 있습니다.
윈스턴은 로그를 파일에 저장해 관리할 수 있게 도와주는 모듈입니다.
윈스턴 데일리 로테이트 파일은 윈스턴이 생성할 로그 파일을
일자별로 생성해, 관리할 수 있게 도움을 주는 모듈입니다.
console 객체의 메서드로, 서버의 상황을 파악할 수 있습니다.
하지만, 서버가 종료되는 순간 쌓여있던 로그들은 사라져버립니다.
윈스턴은 로그를 파일로 관리해, 위 상황을 타계할 수 있습니다.
윈스턴 모듈을 설치합니다.
터미널에 npm i winston install, npm i winston-daliy-rotate-file
을 입력해,
윈스턴과, 윈스턴 데일리 로테이트 파일을 설치합니다.
사용할 모듈을 파일에 가져오고, 저장할 디렉토리를 설정합니다.
const winston = require("winston");
const winstonDaily = require("winston-daily-rotate-file");
const path = require("path"); // node의 내장 모듈 path를 사용하면, 저장할 디렉토리를 알 수 있습니다.
const appRoot = require("app-root-path"); // **app-root-path** 모듈을 사용하면 app의 root path에 쉽게 접근할 수 있습니다.
// 내장 모듈이 아니기 때문에 npm i app-root-path를 통해, 모듈을 설치해야합니다.
const { createLogger } = require("winston");
const process = require("process"); // node의 내장 모듈 process를 사용하면, 터미널에서도 로그를 확인할 수 있습니다.
const logDir = `${appRoot}/logs`; // 디렉토리 'logs'의 하위 파일로 저장됩니다.
기록될 로그의 네이밍 룰을 설정합니다.
const { combine, timestamp, label, printf } = winston.format;
// 로그 네이밍 설정
const logFormat = printf(({ level, message, label, timestamp }) => {
// label은 시스템 명입니다.
// timestamp는 생성일과 시간입니다.
// level은 로그의 형식입니다.
// message는 로그에 남겨진 메시지입니다.
return `${timestamp} [${label}] ${level}: ${message}`;
});
윈스턴 로거(logger)를 생성합니다. createLogger
// logger 생성
const logger = createLogger({
format: combine(label({ label: "NODE_PROJECT" }), timestamp(), logFormat),
// format은 로그의 다양한 형식을 지정합니다.
// 그중 combine은 여러 형식을 혼합해서 사용할 때 사용됩니다.
// label의 값은 일반적으로 시스템 명으로 지정합니다.
// transports에는, 다양한 형식에 맞는 로그 메시지 정의합니다.
transports: [
new winstonDaily({
level: "info",
datePattern: "YYYY-MM-DD",
dirname: logDir, // dirname은 저장할 디렉토리입니다.
filename: "%DATE%.log", // %DATE%를 하면, 자동적으로 파일명이 생성됩니다.
maxSize: "20m", // maxSize는 저장할 로그 파일의 최대 크기입니다.
// 최대 크기를 초과하면 앞에 기록된 메시지가 삭제됩니다.
// 굳이 정의를 하지 않아도 괜찮습니다.
maxFiles: "30d", // maxFiles에 파일 보관 기한입니다. 기한을 넘어가면, 로그 파일이 삭제됩니다.
}),
new winstonDaily({
level: "error",
datePattern: "YYYY-MM-DD",
dirname: logDir,
filename: "%DATE%.error.log",
maxSize: "20m",
maxFiles: "30d",
}),
],
});
// 개발 환경에서 터미널에서 출력
if (process.env.NODE_ENV != "prod") {
logger.add(
new winston.transports.Console({
format: winston.format.combine(
winston.format.colorize(), // colorize는 로그의 색상입니다.
winston.format.simple()
),
})
);
}
module.exports = logger;
const logger = require("./winston/logger");
logger.info("인포(info) 입니다.");
logger.error("에러(error) 입니다.");
터미널에 테스트 파일을 구동해봅니다.
node test.js
를 터미널에 입력하면,
아래와 같이 로그를 터미널에서도 확인할 수 있습니다.
모든 코드를 합쳐서 구성하면 다음과 같습니다.
const winston = require("winston");
const winstonDaily = require("winston-daily-rotate-file");
const path = require("path"); // node의 내장 모듈 path를 사용하면, 저장할 디렉토리를 알 수 있습니다.
const appRoot = require("app-root-path"); // 모듈은 app의 root path에 쉽게 접근을 가능하게 해줍니다.
// 내장 모듈이 아니기 때문에 npm i app-root-path를 통해, 모듈을 설치해야합니다.
const { createLogger } = require("winston"); //
const process = require("process"); // node의 내장 모듈 process를 사용하면, 터미널에서도 로그를 확인할 수 있습니다.
const logDir = `${appRoot}/logs`; // 디렉토리 'logs'의 하위 파일로 저장됩니다.
const { combine, timestamp, label, printf } = winston.format;
// 로그 네이밍 설정
const logFormat = printf(({ level, message, label, timestamp }) => {
// label은 시스템 명입니다.
// timestamp는 생성일과 시간입니다.
// level은 로그의 형식입니다.
// message는 로그에 남겨진 메시지입니다.
return `${timestamp} [${label}] ${level}: ${message}`;
});
// logger 생성
const logger = createLogger({
format: combine(label({ label: "NODE_PROJECT" }), timestamp(), logFormat),
// format은 로그의 다양한 형식을 지정합니다.
// 그중 combine은 여러 형식을 혼합해서 사용할 때 활용됩니다.
// label의 값은 일반적으로 시스템 명으로 지정합니다.
// transports에는, 다양한 형식에 맞는 로그 메시지 정의합니다.
transports: [
new winstonDaily({
level: "info",
datePattern: "YYYY-MM-DD",
dirname: logDir, // dirname은 저장할 디렉토리입니다.
filename: "%DATE%.log", // %DATE%를 하면, 자동적으로 파일명이 생성됩니다.
maxSize: "20m", // maxSize는 저장할 로그 파일의 최대 크기입니다.
// 최대 크기를 초과하면 앞에 기록된 메시지가 삭제됩니다.
// 굳이 정의를 하지 않아도 괜찮습니다.
maxFiles: "30d", // maxFiles에 파일 보관 기한입니다. 기한을 넘어가면, 로그 파일이 삭제됩니다.
}),
new winstonDaily({
level: "error",
datePattern: "YYYY-MM-DD",
dirname: logDir,
filename: "%DATE%.error.log",
maxSize: "20m",
maxFiles: "30d",
}),
],
});
// 개발 환경에서 터미널에서 출력
if (process.env.NODE_ENV != "prod") {
logger.add(
new winston.transports.Console({
format: winston.format.combine(
winston.format.colorize(), // colorize는 로그의 색상입니다.
winston.format.simple()
),
})
);
}
module.exports = logger;
이 글은 윈스턴의 모든 기능을 설명하고 있지 않습니다.
윈스턴이 더 궁금하시다면, 아래 잘 정리된 블로그 글을 읽어보시는 걸 추천드리겠습니다.
인파: NODE-📚-Winston-모듈-사용법-서버-로그-관리