next js 13 에러 로거 winston 적용기

이명진·2024년 1월 17일
0

시도의 이유

에러 로그를 찾아보다가 이미 회사에서 사용하고 있는 seq 로거를 활용하기 위해서 공식문서에 node적용 케이스가 있어서 보고 적용하게 되었다. winston으로 마침 유튜브에 next js 12 + winston 이 있어서 참고 정도로 보고 해보자 라는 마음으로 시도 하게 되었다.

영상에 나온대로 코드를 따라 치면서 무슨 용도로 사용되는지 추측 해보았다.

아래는 영상에서 그대로 옮겨온 코드 내용이다.

출처는 이곳이다 : https://www.youtube.com/watch?v=3vJlXzhtxx4


import { createLogger, format, transports } from "winston";
import "winston-daily-rotate-file";
import { SeqTransport } from "@datalust/winston-seq";

const getLogger = (
  fileName = "application",
  level: "info" | "warn" | "error" = "info"
) => {

  const fileLogTransport = new transports.DailyRotateFile({
    filename: `logs/${fileName}-%DATE%.log`,
    datePattern: "YYYY-MM-DD",
    zippedArchive: true,
    maxSize: "20m",
    maxFiles: "30d",
  });

  const consoleTransport = new transports.Console({
    level: level,
    handleExceptions: false,
    // json:false,
    // colorize:true,
    format: format.printf((i) => `${i.message}`),
  });
  const serverSeqTransPort = new SeqTransport({
    serverUrl: "",
    apiKey: "api-key",
    onError: (e) => console.error(e),
    handleExceptions: true,
    handleRejections: true,
  });
  const logger = createLogger({
    level: "info",
    format: format.combine(
      format.timestamp({
        format: "YYYY-MM-DD HH:mm:ss",
      }),
      format.colorize(),
      format.json(),
      format.errors({ stack: true }),
      format.splat(),
      format.printf(
        ({
          level,
          message,
          label = `sello-web-app[${process.env.NODE_ENV}]`,
          timestamp,
        }) => `${timestamp} [${label}] ${level}: ${message}`
      )
    ),
    defaultMeta: { service: "sello-web-app" },
    transports: [consoleTransport, serverSeqTransPort],
  });
  if (process.env.NODE_ENV === "development") {
    logger.add(fileLogTransport);
  }
  return logger;

};

export default getLogger();

약간 버전 업이 되었는지 다른 부분이 있어서 수정을 약간 하였다. colorize 와 json부분이 사용되는 곳이 조금 달라서 변경을 하였으며 나는 서버로 에러를 보내야 했기에

import { SeqTransport } from "@datalust/winston-seq"; 

이 부분을 추가로 작성하였다.

코드 분석

코드를 설명해보면 아래와 같다.

const fileLogTransport = new transports.DailyRotateFile({
    filename: `logs/${fileName}-%DATE%.log`,
    datePattern: "YYYY-MM-DD",
    zippedArchive: true,
    maxSize: "20m",
    maxFiles: "30d",
  });

이부분은 filename으로 logs폴더 아래 fileName-date.log파일 형식으로 로그형식을 만드는 것같다.
날짜 패턴 부분과 , 사이즈 , 파일 소지 기간정도를 파라미터로 받았다.

  const consoleTransport = new transports.Console({
    level: level,
    handleExceptions: false,
    // json:false,
    // colorize:true,
    format: format.printf((i) => `${i.message}`),
  });

해당 부분은 콘솔 api 설정을 위해 사용되는것 같다. format으로 i.message를 내보내면서 오류 메시지를 추적할수 있는 것 같다.

import { SeqTransport } from "@datalust/winston-seq";

const serverSeqTransPort = new SeqTransport({
    serverUrl: “주소”,
    apiKey: "api-key",
    onError: (e) => console.error(e),
    handleExceptions: true,
    handleRejections: true,
  });

이 코드 부분은 seq로 보내는 역할을 한다, seq logger 라는 페이지가 있는데 해당 페이지에 로그를 보내서 쌓는다.
api-key부분은 옵셔널한 선택값으로 있어도 되고 없어도 된다. 보안을 위해서 키를 세팅하는것같다.


const logger = createLogger({
    level: "info",
    format: format.combine(
      format.timestamp({
        format: "YYYY-MM-DD HH:mm:ss",
      }),
      format.colorize(),
      format.json(),
      format.errors({ stack: true }),
      format.splat(),
      format.printf(
        ({
          level,
          message,
          label = `sello-web-app[${process.env.NODE_ENV}]`,
          timestamp,
        }) => `${timestamp} [${label}] ${level}: ${message}`
      )
    ),
    defaultMeta: { service: "sello-web-app" },
    transports: [consoleTransport, serverSeqTransPort],
  });

해당 부분은 로거부분을 남길때 형식을 세팅하는것 같다. 결국 printrf부분에서 정한 대로
${timestamp} [${label}] ${level}: ${message} 로 로거들 형식이 저장되었다.
format.combine으로 여러 커스텀 형식들을 지정할수가 있는 것 같다.
transport로 위에서 지정한 곳으로 보낸다. 나는 seq서버와 콘솔api의 형식으로 보낸것 같다.

사용법

사용법은 아래와 같다. 기본 콘솔에서 사용되던 api와 비슷한점도 있다.

//  logger.info();
//  logger.error
// logger.warn();
// logger.debug();
// logger.verbose();
// logger.silly();

유의할점은 콘솔을 찍을때 메시지를 넣고 싶으면 아래와 객체로 써야 한다. (출처:impa님 블로그)

// console.log('naver profile : ', profile);
// logger.info('naver profile : ', { message: profile });

console.log와 달리 뒤에 message 객체로 써주어야 한다.

직면한 에러들

client페이지에서 looger를 import하고 사용했는데 이러한 에러가 발견되었다.
해결 방법을 찾다가 이전 사용자분들의 의견과 댓글들을 보면서 원인을 발견할수 있었다.

내가 생각했던 것은 client 페이지.. 즉 웹 페이지 상에서 에러 로그를 찍고 에러 로그를 정리하는 것이었다.

하지만 이에 대해 문제를 찾아 보다 보니 winston 로그는 client에서 사용할수가 없다.

가장 도움이 된 페이지 : https://github.com/winstonjs/winston/issues/1631

클라이언트 사이드에서는 안된다고 한다.

다른 분들의 next js에서 적용한 방법을 확인해봐도(유튜브) winston logger 파일을 만들고
api 폴더에서 자체 api로 만들어서 거기서 logger를 찍고 활용한다.

나도 그래서 이것이 문제일것이라고 생각이 되어서 api폴더를 만들고 Route Handlers를 만들어서
테스트 해본결과 성공할수 있었다....

하지만 통신 에러를 측정하는 거면 서버에서 측정을 이미 하고 있어서 내가 하는게 의미가 있을까 ? 라는 의문이 들었다...

이에 대해 생각을 바꾸게 된것은 적응기 2에서 밝혀진다.

다음으로는 Route Handlers 를 만들어서 직접 사용해보고 후기를 올려보도록 하겠다.
정 불필요하면 걷어내는것도 생각중이다..
그래도 많은 공부가 되었던 시간이 되었다. 매번 새로운 것을 접하면 배우는 것은 신물물을 배우는 것처럼 재미있는데 에러를 만나게 되면 광활한 우주에 버려진것 같은 느낌이든다..
뭐부터 해결해야 하고 어떻게 해결해야하지? 라는 생각이 들면서 우주에서 쓸만한 정보들을 찾는데 해결되면 재밌기도 하다. 한편의 불안함과 즐거움을 느낄수 있는데 이질감이 느껴진다..

[다음글] 적응기 2

profile
프론트엔드 개발자 초보에서 고수까지!

0개의 댓글