diff --git a/src/libs/logger.ts b/src/libs/logger.ts index 5901429..00564a7 100644 --- a/src/libs/logger.ts +++ b/src/libs/logger.ts @@ -2,43 +2,86 @@ import { NextRequest } from 'next/server' import { join } from 'path' import pino from 'pino' -/* 로그 파일 경로 */ -const logFilePath = join('.', 'logs', 'onsite-survey.log') +/* 로그 데이터 인터페이스 */ +interface LogData { + timestamp: string + status: number + method: string + url: string + // headers: { [k: string]: string } + query: { [k: string]: string } + body: string | undefined +} -/* 로거 생성 함수 */ -const createLogger = (): pino.Logger => { - try { - return pino({ - level: 'info', - timestamp: pino.stdTimeFunctions.isoTime, - transport: { - targets: [ - { - target: 'pino/file', - options: { - destination: logFilePath, - mkdir: true, - sync: false, - }, - }, - ], +/* 날짜별 로그 파일 경로 생성 함수 */ +const getLogFilePath = (): string => { + const today = new Date().toISOString().split('T')[0] // YYYY-MM-DD 형식 + return join(process.cwd(), 'logs', `onsite-survey-${today}.log`) +} + +/* 날짜별 로거 생성 클래스 */ +class DailyLogger { + private currentDate: string + private logger: pino.Logger + private destination: ReturnType + + constructor() { + this.currentDate = new Date().toISOString().split('T')[0] + this.destination = pino.destination({ + dest: getLogFilePath(), + mkdir: true, + sync: false, + }) + this.logger = this.createLogger() + + /* kill signal 핸들러 등록 */ + process.on('SIGTERM', this.handleShutdown.bind(this)) + process.on('SIGINT', this.handleShutdown.bind(this)) + } + + private async handleShutdown(): Promise { + this.destination.flushSync() + this.destination.end() + } + + private createLogger(): pino.Logger { + return pino( + { + level: 'info', + timestamp: pino.stdTimeFunctions.isoTime, }, - }) - } catch (error) { - console.error('Pino transport 생성 실패, 기본 로거 사용:', error) - return pino({ - level: 'info', - timestamp: pino.stdTimeFunctions.isoTime, - }) + this.destination, + ) + } + + public info(obj: any, msg?: string): void { + const today = new Date().toISOString().split('T')[0] + + if (today !== this.currentDate) { + /* 기존 destination 종료 */ + this.destination.flushSync() + this.destination.end() + + /* 새로운 destination 생성 */ + this.destination = pino.destination({ + dest: getLogFilePath(), + mkdir: true, + sync: false, + }) + this.currentDate = today + this.logger = this.createLogger() + } + + this.logger.info(obj, msg) } } /* 로거 인스턴스 */ -export const logger = createLogger() +const dailyLogger = new DailyLogger() /* 로그 기록 함수 */ export const writeLog = async (request: NextRequest, responseStatus: number): Promise => { - const logData = { + const logData: LogData = { timestamp: new Date().toISOString(), status: responseStatus, method: request.method, @@ -47,5 +90,5 @@ export const writeLog = async (request: NextRequest, responseStatus: number): Pr query: Object.fromEntries(new URL(request.url).searchParams), body: request.body ? await request.clone().text() : undefined, } - logger.info(logData, 'API Request') + dailyLogger.info(logData, 'API Request') }