본문 바로가기
개발/Node JS

Node JS - log4js로 함수 이름과 줄 번호 로그 남기기 (log4js with Function Name, Line Number)

by 피로물든딸기 2023. 8. 25.
반응형

Node JS 전체 링크

 

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을 직접 커스터마이징 하면 된다.

 

outapplayout을 아래와 같이 추가하자.

    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" },
    },

 

layouttypecusomLayout으로 설정하였기 때문에, 아래와 같이 만들 수 있다.

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(" ")}`;
  };
});

 

applayoutcustomLayoutNoANSI로 설정하자.

    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();
반응형

댓글