winston
: 로그 파일 및 로그 레벨 관리 모듈winston-dayily-rotate-file
: 매일 날짜 별로 로그 파일 생성 및 관리 모듈 ( 시간이 지나면 자동으로 삭제 & 압축 관리 )morgan
: request
요청 로깅 미들웨어
winston
으로 로그 레벨, 타임라인을 관리하고morgan
으로 요청/응답 정보들을 로깅을 할 수 있게 해서Express
로그를 관리하고 위에서 로깅한 정보들을 날짜 별로 로그 파일을 생성해주고 일정 시간이 지나면 삭제 및 압축을 해주는 기능을 사용하기 위해winston-dayily-rotate-file
을 사용했습니다!
: Morgan
사용법은 정말 간단합니다 기본적으로 사용할 때는
margan("출력타입");
위 처럼 작성하면 끝 입니다! 이때 출력 타입들의 종류는 커스터마이징 하거나 기본적으로 제공해주는 Format
중에 선택하면 됩니다.
여러가지 Format
중 주로 사용하는 부분만 정리하면 아래와 같습니다.
:http-version
: 요청한 HTTP
버전:method
: 요청한 HTTP method
:status
: 응답의 상태 코드 입니다.📌
status
주의 사항클라이언트에 응답을 보내기 전에 요청/응답 주기가 완료되면(예: 클라이언트가 요청을 중단하여 TCP 소켓이 조기에 닫히는 상황) 상태가 비어 있게 됩니다.
("-"
가 로그에 표시됨).
:url
: 요청한 URL
:response-time
: morgan
으로 들어오는 요청과 응답 헤더가 작성된 시간 사이의 시간(응답시간):res[content-length]
: 응답 길이저는 아래와 같은 형식을 주로 사용합니다.
:method :status :url :response-time ms
코드에서는
// app.js 파일
app.use(
morgan(":method :status :url :response-time ms", { stream: logger.stream })
);
위처럼 morgan
을 통해 dev format
으로 생성 된 log
를 winston
에 보내주는 코드 입니다.
winston
은 createLogger
를 통해 자신만의 고유한 logger
를 만들 수 있습니다.
winston
은 기본 로깅 수준 설정은 RFC5424
에서 지정한 심각도 순서를 따릅니다.
const levels = {
error: 0,
warn: 1,
info: 2,
http: 3,
verbose: 4,
debug: 5,
silly: 6,
};
즉 따로 설정하지 않으면 위의 수준을 사용하는건데 따로 설정할 필요가 없어 저대로 사용하였습니다.
const logFormat = printf((info) => {
return `${info.timestamp} ${info.level}: ${info.message}`;
});
const logger = winston.createLogger({
format: combine(
timestamp({
format: "YYYY-MM-DD HH:mm:ss",
}),
logFormat
),
logger.stream = {
// morgan wiston 설정
write: (message) => {
logger.info(message);
},
};
winston createLogger
의 설정은 위와 같게 되어있습니다.
하나씩 풀면 logFormat
을 통해 로그 형식을 맞춘 후,
createLogger
의 format: combine
을 통해 여러 형식을 하나의 format
으로 합쳐줍니다.
여기서 timestamp
즉 수신한 시간과 logFormat
으로 만든 사용자 지정 로그 format
을 combine
으로 하나의 format
으로 합쳐줍니다.
이때 logger.stream
을 통해 logger
의 info
에 받은 message
값을 넣어주게 됩니다.
그 후, app.js
파일의 { stream: logger.stream }
을 통해 morgan
을 통해 나온 로그를 넣어줍니다.
app.use(
morgan(":method :status :url :response-time ms", { stream: logger.stream })
);
winston-dayily-rotate-file
은 코드 중 transport
부분을 담당하고 있습니다.
new winstonDaily
를 통해 하나의 로그 파일의 포맷과 폴더 형식들을 정해줄 수 있다.
const logDir = "logs";
new winstonDaily({
level: "info",
datePattern: "YYYY-MM-DD",
dirname: logDir,
filename: `%DATE%.log`, // file 이름 날짜로 저장
maxFiles: 30, // 30일치 로그 파일 저장
zippedArchive: true,
}),
위 코드의 값들에 대해 하나씩 알아보자면
level
: 저장될 로그의 레벨datePattern
: 날짜형식dirname
: 로그가 저장 될 폴더의 이름filename
: 로그 파일 이름 형식maxFiles
: 로그 파일이 저장되는 기간zippedArchive
: 압축여부입니다.
오류가 나타나야 하는 부분에 직접 로그를 작성하는 방법은 logger
를 import
해온 후 오류를 작성할 부분에
import { logger } from "../utils/winstonLogger.js";
logger.info("정보를 나타내는 로그")
logger.warn("위험성을 나타내는 로그")
logger.error("에러를 나타내는 로그")
위 처럼 3단계로 나눠져있는 부분을 필요에 맞게 작성하시면 됩니다.
logger.warn
과 logger.error
로 작성된 것은 error
폴더와 warn
폴더에 따로 저장이 됩니다.
이때 error
는 warn
에도 같이 저장되고 info
에도 저장되며
warn
은 info
에도 같이 저장이 되고
info
는 혼자만 저장 됩니다.
// Production 환경이 아닌 경우(dev 등) 배포 환경에서는
// 최대한 자원을 안잡아 먹는 로그를 출력해야함
if (process.env.NODE_ENV !== "production") {
logger.add(
new winston.transports.Console({
format: combine(
colorize({ all: true }), // console 에 출력할 로그 컬러 설정 적용함
logFormat // log format 적용
),
})
);
}
위 코드는 배포 환경에서는 console에 로그를 출력하지 않고, 그 외의 환경에서만 console에 로그를 출력하도록 설정한 것 입니다!
import winston from "winston";
import winstonDaily from "winston-daily-rotate-file";
const { combine, timestamp, printf, colorize } = winston.format;
const logDir = "logs"; // logs 디렉토리 하위에 로그 파일 저장
const logFormat = printf((info) => {
return `${info.timestamp} ${info.level}: ${info.message}`;
});
/*
* Log Level
* error: 0, warn: 1, info: 2, http: 3, verbose: 4, debug: 5, silly: 6
*/
const logger = winston.createLogger({
format: combine(
timestamp({
format: "YYYY-MM-DD HH:mm:ss",
}),
logFormat
),
transports: [
// info 레벨 로그를 저장할 파일 설정
new winstonDaily({
level: "info",
datePattern: "YYYY-MM-DD",
dirname: logDir,
filename: `%DATE%.log`, // file 이름 날짜로 저장
maxFiles: 30, // 30일치 로그 파일 저장
zippedArchive: true,
}),
// warn 레벨 로그를 저장할 파일 설정
new winstonDaily({
level: "warn",
datePattern: "YYYY-MM-DD",
dirname: logDir + "/warn",
filename: `%DATE%.warn.log`, // file 이름 날짜로 저장
maxFiles: 30, // 30일치 로그 파일 저장
zippedArchive: true,
}),
// error 레벨 로그를 저장할 파일 설정
new winstonDaily({
level: "error",
datePattern: "YYYY-MM-DD",
dirname: logDir + "/error", // error.log 파일은 /logs/error 하위에 저장
filename: `%DATE%.error.log`,
maxFiles: 30,
zippedArchive: true,
}),
],
});
logger.stream = {
// morgan wiston 설정
write: (message) => {
logger.info(message);
},
};
// Production 환경이 아닌 경우(dev 등) 배포 환경에서는
// 최대한 자원을 안잡아 먹는 로그를 출력해야함
if (process.env.NODE_ENV !== "production") {
logger.add(
new winston.transports.Console({
format: combine(
colorize({ all: true }), // console 에 출력할 로그 컬러 설정 적용함
logFormat // log format 적용
),
})
);
}
export { logger };