diff --git a/src/libs/logger.ts b/src/libs/logger.ts index ab73450..54c46fd 100644 --- a/src/libs/logger.ts +++ b/src/libs/logger.ts @@ -15,9 +15,14 @@ interface ApiLogData { body: string | undefined } +/* 현재 날짜 반환 함수 (YYYY-MM-DD 형식) */ +const getCurrentDate = (): string => { + return new Date().toISOString().split('T')[0] +} + /* 날짜별 로그 파일 경로 생성 함수 */ const getLogFilePath = (): string => { - const today = new Date().toISOString().split('T')[0] // YYYY-MM-DD 형식 + const today: string = getCurrentDate() return join(process.cwd(), 'logs', `onsite-survey-${today}.log`) } @@ -25,15 +30,10 @@ const getLogFilePath = (): string => { class DailyLogger { private currentDate: string private logger: pino.Logger - private destination: ReturnType + private destination?: ReturnType constructor() { - this.currentDate = new Date().toISOString().split('T')[0] - this.destination = pino.destination({ - dest: getLogFilePath(), - mkdir: true, - sync: false, - }) + this.currentDate = getCurrentDate() this.logger = this.createLogger() /* kill signal 핸들러 등록 */ @@ -42,14 +42,31 @@ class DailyLogger { } private async handleShutdown(): Promise { - this.destination.flushSync() - this.destination.end() + if (isProduction && this.destination) { + this.destination.flushSync() + this.destination.end() + } + this.logger.flush() } private createLogger(): pino.Logger { + if (!isProduction) return pino({ level: 'silent' }) + + /* 기존 destination 종료 */ + if (this.destination) { + this.destination.flushSync() + this.destination.end() + } + /* 새로운 destination 생성 */ + this.destination = pino.destination({ + dest: getLogFilePath(), + mkdir: true, + sync: false, + }) + return pino( { - level: isProduction ? 'info' : 'silent', + level: 'info', timestamp: pino.stdTimeFunctions.isoTime, }, this.destination, @@ -57,24 +74,16 @@ class DailyLogger { } 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() + try { + const today: string = getCurrentDate() + if (today !== this.currentDate) { + this.currentDate = today + this.logger = this.createLogger() + } + this.logger.info(obj, msg) + } catch (error) { + console.error(`[DailyLogger] Failed to write log: ${error}`) } - - this.logger.info(obj, msg) } } @@ -83,13 +92,26 @@ const dailyLogger = new DailyLogger() /* API 로그 기록 함수 */ export const writeApiLog = async (request: NextRequest, responseStatus: number): Promise => { + if (!isProduction) return + + let bodyString: string | undefined + if ( + request.method === 'POST' && + (request.headers.get('content-type') === 'multipart/form-data' || request.headers.get('content-type') === 'application/x-www-form-urlencoded') + ) { + const formData = await request.formData() + bodyString = JSON.stringify(Object.fromEntries(formData)) + } else { + bodyString = await request.text() + } + const logData: ApiLogData = { responseStatus: responseStatus, method: request.method, url: request.url, // headers: Object.fromEntries(request.headers), query: Object.fromEntries(new URL(request.url).searchParams), - body: request.body ? await request.text() : undefined, + body: bodyString, } dailyLogger.info(logData, 'API Request') }