log4js를 이용하여 로그를 남겨보자.
npm install log4js
log4js.configure에서 아래의 옵션을 설정할 수 있다.
콘솔에도 출력하고 싶다면 out의 type을 stdout으로 설정한다.
그리고 로그를 출력할 파일, 로그 파일의 최대 사이즈, backup 파일 개수 등을 설정할 수 있다.
appenders: {
out: { type: "stdout" }, // 콘솔 출력
app: {
type: "file",
filename: "D:\\github\\node-server\\log\\logFiles\\application.log",
maxLogSize: 512 /* byte */,
backups: 3,
},
exceptions: {
type: "file",
filename: "D:\\github\\node-server\\log\\logFiles\\exceptions.log",
},
},
사용 방법은 아래와 같다.
로그 레벨은 trace / debug / info / error로 나뉜다.
const logger = require("../log/logger");
logger.trace("hello!");
logger.debug("world!");
logger.info("blood!");
logger.error("strawberry!");
maxLogSize를 512byte로 설정하면 backup 파일이 제대로 생성되는지 쉽게 확인할 수 있다.
전체 코드는 다음과 같다.
logger.js
//log level : trace, debug, info, error
const log4js = require("log4js");
const logger = log4js.getLogger();
log4js.configure({
appenders: {
out: { type: "stdout" }, // 콘솔 출력
app: {
type: "file",
filename: "D:\\github\\node-server\\log\\logFiles\\application.log",
maxLogSize: 512 /* byte */,
backups: 3,
},
exceptions: {
type: "file",
filename: "D:\\github\\node-server\\log\\logFiles\\exceptions.log",
},
},
categories: {
default: { appenders: ["out", "app"], level: "trace" }, // trace 레벨 이상 기록 (모두 기록)
exceptions: { appenders: ["exceptions"], level: "error" }, // 예외 로그는 따로 처리
},
});
module.exports = logger;
logTest.js
const logger = require("../log/logger");
const test = () => {
logger.trace("hello!");
logger.debug("world!");
logger.info("blood!");
logger.error("strawberry!");
};
test();
함수 이름과 라인 넘버 추가하기
함수 이름과 줄 번호를 추가하려면 layout을 직접 커스터마이징 하면 된다.
out과 app에 layout을 아래와 같이 추가하자.
out: {
type: "stdout",
layout: { type: "customLayout" },
}, // 콘솔 출력
app: {
type: "file",
filename: "D:\\github\\node-server\\log\\logFiles\\application.log",
maxLogSize: 512 /* byte */,
backups: 3,
layout: { type: "customLayout" },
},
layout의 type을 cusomLayout으로 설정하였기 때문에, 아래와 같이 만들 수 있다.
log4js.addLayout("customLayout", function (config) {
return function (logEvent) {
let logTime = logEvent.startTime.toISOString();
let level = logEvent.level.levelStr.padStart(5, " ");
let levelColor = getColor(level);
let resetColor = " \x1b[0m";
let lineNumber = logEvent.lineNumber;
let functionName = logEvent.functionName;
let fileName = getFileName(logEvent.fileName);
return `${levelColor}[${logTime}][${level}][${fileName}][${functionName}:${lineNumber}] ${logEvent.data.join(" ")} ${resetColor}`;
};
});
참고로 logEvent를 출력하면 아래의 정보를 얻을 수 있다.
LoggingEvent {
startTime: 2023-08-24T15:11:31.499Z,
categoryName: ' ',
data: [ 'strawberry!' ],
level: Level { level: 40000, levelStr: 'ERROR', colour: 'red' },
context: {},
pid: 17128,
error: undefined,
fileName: 'D:\\github\\node-server\\macro\\logTest.js',
lineNumber: 15,
columnNumber: 12,
callStack: ' at test2 (D:\\github\\node-server\\macro\\logTest.js:15:12)\n' +
' at Object.<anonymous> (D:\\github\\node-server\\macro\\logTest.js:20:1)\n' +
' at Module._compile (node:internal/modules/cjs/loader:1165:14)\n' +
' at Object.Module._extensions..js (node:internal/modules/cjs/loader:1219:10)\n' +
' at Module.load (node:internal/modules/cjs/loader:1043:32)\n' +
' at Function.Module._load (node:internal/modules/cjs/loader:878:12)\n' +
' at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)',
className: '',
functionName: 'test2',
functionAlias: '',
callerName: 'test2'
}
이제 색상도 추가되고, [시간][로그레벨][파일이름][함수:라인] [로그] 형태로 출력되는 것을 알 수 있다.
그러나 출력된 로그 파일에는 아래와 같이 불필요한 ANSI 문자가 남는다.
간단한 해결 방법은 customLayout을 하나 더 복사해, 양 옆의 color 설정을 지우는 것이다.
log4js.addLayout("customLayoutNoANSI", function(config) {
return function(logEvent) {
let logTime = logEvent.startTime.toISOString();
let level = logEvent.level.levelStr.padStart(5, " ");
let lineNumber = logEvent.lineNumber;
let functionName = logEvent.functionName;
let fileName = getFileName(logEvent.fileName);
return `[${logTime}][${level}][${fileName}][${functionName}:${lineNumber}] ${logEvent.data.join(" ")}`;
};
});
app의 layout을 customLayoutNoANSI로 설정하자.
app: {
type: "file",
filename: "D:\\github\\node-server\\log\\logFiles\\application.log",
maxLogSize: 512 /* byte */,
backups: 3,
layout: { type: "customLayoutNoANSI" },
},
이제 파일에서 불필요한 문자가 사라진 것을 알 수 있다.
마지막으로 오브젝트를 출력하기 위해서 logMessages를 아래와 같이 변경한다. ([object Object] 출력 방지)
const util = require("util");
...
let logMessages = logEvent.data.map((data) => {
if (typeof data === "object") {
return util.inspect(data);
}
return data;
});
전체 코드는 다음과 같다.
logger.js
//log level : trace, debug, info, error
const log4js = require("log4js");
const util = require("util");
const getFileName = (path) => {
let spt = path.split("\\");
return spt[spt.length - 1];
};
const getColor = (level) => {
switch (level) {
case "TRACE":
return "\x1b[35m"; // Magenta
case "DEBUG":
return "\x1b[36m"; // Cyan
case " INFO":
return "\x1b[32m"; // Green
case "ERROR":
return "\x1b[31m"; // Red
default:
return "\x1b[0m"; // Reset
}
};
log4js.addLayout("customLayout", function (config) {
return function (logEvent) {
let logTime = logEvent.startTime.toISOString();
let level = logEvent.level.levelStr.padStart(5, " ");
let levelColor = getColor(level);
let resetColor = " \x1b[0m";
let lineNumber = logEvent.lineNumber;
let functionName = logEvent.functionName;
let fileName = getFileName(logEvent.fileName);
let logMessages = logEvent.data.map((data) => {
if (typeof data === "object") {
return util.inspect(data);
}
return data;
});
return `${levelColor}[${logTime}][${level}][${fileName}][${functionName}:${lineNumber}] ${logMessages} ${resetColor}`;
};
});
log4js.addLayout("customLayoutNoANSI", function (config) {
return function (logEvent) {
let logTime = logEvent.startTime.toISOString();
let level = logEvent.level.levelStr.padStart(5, " ");
let lineNumber = logEvent.lineNumber;
let functionName = logEvent.functionName;
let fileName = getFileName(logEvent.fileName);
let logMessages = logEvent.data.map((data) => {
if (typeof data === "object") {
return util.inspect(data);
}
return data;
});
return `[${logTime}][${level}][${fileName}][${functionName}:${lineNumber}] ${logMessages}`;
};
});
log4js.configure({
appenders: {
out: {
type: "stdout",
layout: { type: "customLayout" },
}, // 콘솔 출력
app: {
type: "file",
filename: "D:\\github\\node-server\\log\\logFiles\\application.log",
maxLogSize: 512 /* byte */,
backups: 3,
layout: { type: "customLayoutNoANSI" },
},
exceptions: {
type: "file",
filename: "D:\\github\\node-server\\log\\logFiles\\exceptions.log",
},
},
categories: {
default: {
appenders: ["out", "app"],
level: "trace",
enableCallStack: true,
}, // trace 레벨 이상 기록 (모두 기록)
exceptions: { appenders: ["exceptions"], level: "error" }, // 예외 로그는 따로 처리
},
});
const logger = log4js.getLogger();
module.exports = logger;
logTest.js
const logger = require("../log/logger");
const test = () => {
logger.trace("hello!");
logger.debug("world!");
logger.info("blood!");
logger.error("strawberry!");
};
test();
댓글