Search

Next.js pino 로그 처리

Nextjs 공식 문서를 찾아보면, 로그에 관련되서 구조화된 로크 패키지를 원한다면 Pino를 사용할 것을 권하고 있습니다.

Pino로 로깅하기

해당 로그들을 파일로 뽑아내야 할 일이 있어 Pino를 사용해 getServerSideProps에서 나오는 로그들을 뽑아내보았습니다.
아래는 버전 참고하시면 될듯합니다.
// package.json { "name": "my-app", "version": "0.1.0", "private": true, "scripts": { "dev": "next dev -p 3000", "build": "next build", "start": "NODE_ENV=production node server.js" }, "dependencies": { "next": "^12.2.2", "pino": "^8.1.0", "react": "^18.2.0", "react-dom": "^18.2.0" } }
JavaScript
복사

Pino를 사용한 기본 로깅

우선 pino를 사용한 코드를 작성해줍니다.
// logger.jsimport pino from 'pino'; const logger = pino(); export const log = (msg) => logger.info(msg);
Plain Text
복사
다음으로 페이지 코드를 작성하는데, getServerSideProps의 에러를 잡아내기 위한 코드만 적었습니다.
// pages/index.jsimport { log } from '../next-pino/logger'; ... export const getServerSideProps = async () => { try { // 에러 강제 발생throw new Error('make error'); return { props: {}, }; } catch (error) { console.log('에러 로그를 찍습니다'); log(error); return { props: {} }; } };
Plain Text
복사
해당 페이지를 실행시키면 에러가 발생하고 서버에서 아래와 같이 출력됩니다.
로그를 간단히 살펴보면 아래와 같습니다.
level : trace : 10, debug: 20, info : 30, warn: 40, error: 50, fatal: 60으로 지정되어져있고 커스텀 가능합니다.
time : 에러가 기록된 시간입니다.
err : msg로 넣은 메시지가 들어가게 됩니다.
이를 통해서 getServerSideProps에서 발생하는 에러들을 출력시켰습니다.

Pino 환경 설정 커스텀

level에 따른 로그 저장이 다르다고 했는데, 아래와 같이 각자 저장하는 곳을 따로 가지고 있습니다.
// logger.jsimport pino from 'pino'; const traceLogger = pino(); const debugLogger = pino(); const infoLogger = pino(); const warnLogger = pino(); const errorLogger = pino(); const fatalLogger = pino(); export const traceLog = (msg) => traceLogger.trace(msg); export const debugLog = (msg) => debugLogger.debug(msg); export const infoLog = (msg) => infoLogger.info(msg); export const warnLog = (msg) => warnLogger.warn(msg); export const errorLog = (msg) => errorLogger.error(msg); export const fatalLog = (msg) => fatalLogger.fatal(msg);
Plain Text
복사
단 아래와 같이 모든 trace와 debug의 경우 에러에서는 로그를 작성하지 않고 있는데 상황에 따라 저장되는 사항이 다릅니다. 참고
export const getServerSideProps = async () => { try { throw new Error('make error'); return { props: {}, }; } catch (error) { console.log('에러 로그를 찍습니다'); traceLog(error); debugLog(error); infoLog(error); warnLog(error); errorLog(error); fatalLog(error); return { props: {} }; } };
Plain Text
복사
해당 결과는 이렇게 발생합니다. trace와 debug는 찍히지 않고, 보면 level이 30부터 시작하는 것을 알 수 있습니다.

시간 표현 변경

로그에 문제가 있는데 우선 time이 유닉스 시간으로 되어있다는 점입니다. 해당 표현은 가독성이 나빠 이를 수정해보려고 합니다. 참고
// logger.jsimport pino from 'pino'; /** custom time */const logger = pino({ timestamp: pino.stdTimeFunctions.isoTime }); export const infoTimeLogger = (msg) => logger.info(msg)
Plain Text
복사
// index.jsexport const getServerSideProps = async () => { try { throw new Error('make error'); return { props: {}, }; } catch (error) { console.log('에러 로그를 찍습니다'); infoTimeLogger(error); return { props: {} }; } };
Plain Text
복사
해당 코드를 실행하게 되면 아래와 같이 시간 표현 방식이 바뀝니다.

Pino-Pretty 적용

하지만 아직까지 데이터 표현방식의 가독성이 나쁩니다.
이를 위해서 pino-pretty를 사용할 예정인데 주의점이 있습니다.
1.
import 로 pino-pretty 라이브러리를 불러올 시 해당 파일은 nodejs에 맞게 되어있는 라이브러리라서 에러가 발생한다.
2.
transport를 이용하면 되는데 v7부터 생겼으므로 설치된 버전을 확인해야 합니다.
import pino from 'pino'; /** pino pretty */const log = pino( { timestamp: pino.stdTimeFunctions.isoTime, transport: { target: 'pino-pretty', options: { // colorize: true, // boolean// levelFirst: true, // level이 가장 앞으로 오도록 설정// ignore: 'pid,hostname', // 해당 형식 무시// destination: './log/info.log', }, }, }, );
Plain Text
복사
export const getServerSideProps = async () => { try { throw new Error('make error') return { props: {}, }; } catch (error) { console.log('에러 로그를 찍습니다'); prettyLog(error); return { props: {} }; } };
Plain Text
복사
이렇게 되면 아래와 같이 정리된 방식으로 출력이 됩니다.
위에 transport에 있는 옵션들은 해당 페이지를 참고하면 됩니다.

파일에 로그 남기기

option에서 사용된 변수 중 destination은 파일에 로그를 저장하는데, 다른 방식으로도 호출할 수 있습니다.
단 경로의 경우 /는 c드라이브로 잡히게 되고 ./는 프로젝트의 루트가 잡히게 됩니다.
const logger = pino(pino.destination('./log/info.log'));
Plain Text
복사

로그 일괄 처리하기

아래 함수를 통해서 getServerSideProps를 받아서 로그를 동일하게 처리할 수 있습니다.
// logger.jsexport function withGetServerSideProps(getServerSideProps) { return async (context) => { try { return await getServerSideProps(context); } catch (error) { log.info(error); return { props: {}, }; // throw error; } }; }
Plain Text
복사
// index.jsexport const getServerSideProps = withGetServerSideProps() => { // 동작 작성return { props: { }, }; });
Plain Text
복사
위와 같이 함수를 작성해 줘서 로그 동작을 일괄로 처리 할 수 도있다.