로그로그

This commit is contained in:
2025-12-15 09:55:43 +09:00
parent ef5f921e21
commit 6b8ea7e74c
7 changed files with 429 additions and 352 deletions

View File

@@ -9,11 +9,7 @@ import {
import { Request, Response } from 'express';
/**
* 모든 예외 필터
*
* @description
* HTTP 예외뿐만 아니라 모든 예외를 잡아서 처리합니다.
* 예상치 못한 에러도 일관된 형식으로 응답합니다.
* 모든 예외 필터 - Docker 환경에서 로그 출력 보장
*/
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
@@ -40,11 +36,7 @@ export class AllExceptionsFilter implements ExceptionFilter {
}
} else {
status = HttpStatus.INTERNAL_SERVER_ERROR;
message = '서버 내부 오류가 발생했습니다.';
if (exception instanceof Error) {
message = exception.message;
}
message = exception instanceof Error ? exception.message : '서버 내부 오류가 발생했습니다.';
}
const errorResponse = {
@@ -61,32 +53,41 @@ export class AllExceptionsFilter implements ExceptionFilter {
(errorResponse as any).stack = exception.stack;
}
// ========== 상세 로깅 ==========
this.logger.error(
`========== EXCEPTION ==========`
);
this.logger.error(
`[${request.method}] ${request.url} - Status: ${status}`
);
this.logger.error(
`Message: ${JSON.stringify(message)}`
);
// ========== 상세 로깅 (stdout으로 즉시 출력) ==========
const logMessage = [
'',
'╔══════════════════════════════════════════════════════════════╗',
'║ EXCEPTION OCCURRED ║',
'╚══════════════════════════════════════════════════════════════╝',
` Timestamp : ${errorResponse.timestamp}`,
` Method : ${request.method}`,
` Path : ${request.url}`,
` Status : ${status}`,
` Message : ${JSON.stringify(message)}`,
];
if (exception instanceof Error) {
this.logger.error(`Error Name: ${exception.name}`);
this.logger.error(`Error Message: ${exception.message}`);
this.logger.error(`Stack Trace:\n${exception.stack}`);
} else {
this.logger.error(`Exception: ${JSON.stringify(exception)}`);
logMessage.push(` Error Name: ${exception.name}`);
logMessage.push(` Stack :`);
logMessage.push(exception.stack || 'No stack trace');
}
// Request Body 로깅 (민감정보 마스킹)
const safeBody = { ...request.body };
if (safeBody.password) safeBody.password = '****';
if (safeBody.token) safeBody.token = '****';
this.logger.error(`Request Body: ${JSON.stringify(safeBody)}`);
this.logger.error(`===============================`);
logMessage.push(` Body : ${JSON.stringify(safeBody)}`);
logMessage.push('══════════════════════════════════════════════════════════════════');
logMessage.push('');
// NestJS Logger 사용 (Docker stdout으로 출력)
this.logger.error(logMessage.join('\n'));
// 추가로 console.error도 출력 (백업)
console.error(logMessage.join('\n'));
// process.stdout으로 직접 출력 (버퍼링 우회)
process.stdout.write(logMessage.join('\n') + '\n');
response.status(status).json(errorResponse);
}

View File

@@ -3,50 +3,42 @@ import {
NestInterceptor,
ExecutionContext,
CallHandler,
Logger,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
import { Request } from 'express';
/**
* 로깅 인터셉터
*
* @description
* API 요청/응답을 로깅하고 실행 시간을 측정합니다.
*
* @example
* // main.ts에서 전역 적용
* app.useGlobalInterceptors(new LoggingInterceptor());
*
* @export
* @class LoggingInterceptor
* @implements {NestInterceptor}
* 로깅 인터셉터 - Docker 환경에서 로그 출력 보장
*/
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
private readonly logger = new Logger('HTTP');
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const request = context.switchToHttp().getRequest<Request>();
const { method, url, ip } = request;
const userAgent = request.get('user-agent') || '';
const now = Date.now();
console.log(
`[${new Date().toISOString()}] Incoming Request: ${method} ${url} - ${ip} - ${userAgent}`,
);
const incomingLog = `[REQUEST] ${method} ${url} - IP: ${ip}`;
this.logger.log(incomingLog);
process.stdout.write(`${new Date().toISOString()} - ${incomingLog}\n`);
return next.handle().pipe(
tap({
next: (data) => {
next: () => {
const responseTime = Date.now() - now;
console.log(
`[${new Date().toISOString()}] Response: ${method} ${url} - ${responseTime}ms`,
);
const successLog = `[RESPONSE] ${method} ${url} - ${responseTime}ms - SUCCESS`;
this.logger.log(successLog);
process.stdout.write(`${new Date().toISOString()} - ${successLog}\n`);
},
error: (error) => {
const responseTime = Date.now() - now;
console.error(
`[${new Date().toISOString()}] Error Response: ${method} ${url} - ${responseTime}ms - ${error.message}`,
);
const errorLog = `[RESPONSE] ${method} ${url} - ${responseTime}ms - ERROR: ${error.message}`;
this.logger.error(errorLog);
process.stdout.write(`${new Date().toISOString()} - ${errorLog}\n`);
},
}),
);