Advanced Winston logger with TypeORM support & structured logging.
Blanc Logger는 NestJS 및 TypeORM 애플리케이션을 위한 고급 로깅 라이브러리입니다.
이 라이브러리는 Winston을 기반으로 콘솔 및 파일 로깅을 지원하며,
자동 구조화된 JSON 포맷, SQL 쿼리 하이라이팅, 모듈 기반 로그 추적 등 다양한 기능을 제공합니다.
npm install blanc-logger
Blanc Logger를 전역 로거로 적용하면, 애플리케이션 전체에서 동일한 로깅 설정을 사용할 수 있습니다.
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { blancLogger, BlancLoggerMiddleware } from 'blanc-logger';
async function bootstrap() {
const app = await NestFactory.create(AppModule, {
logger: blancLogger, // 전역 Logger 적용
});
// 미들웨어를 적용하여 요청 시 모듈명 등 컨텍스트 정보를 추가
app.use(new BlancLoggerMiddleware().use);
await app.listen(3000);
}
bootstrap();
TypeORM 설정에서 Blanc Logger의 전용 로거를 사용하여, SQL 쿼리 및 데이터베이스 관련 로그를 효과적으로 기록할 수 있습니다.
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { TypeOrmBlancLogger } from 'blanc-logger';
@Module({
imports: [
TypeOrmModule.forRoot({
// ... DB 설정
logging: true,
logger: new TypeOrmBlancLogger(), // TypeORM용 로거 사용
}),
// 다른 모듈들...
],
})
export class AppModule {}
Blanc Logger를 사용하여 기존의 NestJS 내장 로거를 대체할 수 있습니다.
// 기존 NestJS 내장 로거 사용:
this.logger.error('Error message', error.stack);
this.logger.log('Log message');
// 에러 발생 시, 스택 정보와 함께 기록
blancLogger.error('Error message', { moduleName: 'ModuleName', stack: error.stack });
blancLogger.log('Log message', { moduleName: 'ModuleName' });
blancLogger.warn('Warn message', { moduleName: 'ModuleName' });
blancLogger.verbose('Verbose message', { moduleName: 'ModuleName' });
blancLogger.debug('Debug message', { moduleName: 'ModuleName' });
로그 파일이 자동으로 날짜별로 생성되어 logs 폴더 아래에 다음과 같이 쌓입니다.
logs/
├── combined-2025-03-03.log # 모든 로그 메시지
├── error-2025-03-03.log # error 레벨 로그
├── exceptions-2025-03-03.log # 처리되지 않은 예외 로그
└── rejections-2025-03-03.log # 미처리된 Promise 거부 로그
예시 로그 (error-2025-03-03.log 파일):
{"level":"error","message":"HTTP Exception: DUPLICATION","stack":[{"moduleName":"user","path":"/api/user/profile","stack":"ConflictException: DUPLICATION\n at UserService.getProfile (/path/to/src/user/user.service.ts:60:13)\n at process.processTicksAndRejections (node:internal/process/task_queues:95:5)"}],"timestamp":"2025-03-03 14:29:51"}
Feature | Description |
---|---|
다중 전송 로깅 (Multi-Transport Logging) | - 콘솔 출력과 파일 저장을 동시에 지원 - 일정 크기(예: 20MB) 또는 일정 주기(예: 15일)에 따라 자동으로 로그 파일 회전 - 로그 파일 예시: combined-YYYY-MM-DD.log , error-YYYY-MM-DD.log , exceptions-YYYY-MM-DD.log , rejections-YYYY-MM-DD.log
|
구조화된 로그 출력 (Structured Logging) | - UUIDv5를 사용해 고유 LogID 생성 - {timestamp, level, message} 형식의 표준 JSON 포맷으로 출력되어 외부 시스템 연동 용이 |
모듈별 컨텍스트 추적 (Contextual Tracing) | - BlancLoggerMiddleware 를 활용하여 HTTP 요청에서 모듈명 자동 추출- [UserService → AuthModule → Subsystem] 과 같이 계층 구조로 표시 |
동적 로그 레벨 관리 (Dynamic Log Levels) | - 개발 및 운영 환경에 따라 debug, verbose, info, warn, error 로그 레벨을 실시간으로 조절 가능- 필요한 정보만 선별 기록하여 로그의 가독성과 관리 효율성을 향상 |
SQL 구문 하이라이팅 (SQL Syntax Highlighting) | - SQL 쿼리의 키워드, 값, 테이블명을 색상 강조 및 들여쓰기로 구분 - 파라미터 값 컨텍스트 인식 강조 |
쿼리 성능 분석 (Query Analysis) | - SQL 성능 저하 유발 패턴 자동 감지 (SELECT * , JOIN 조건 누락 등) |
에러 진단 및 스택 추적 (Error Diagnostics) | - 에러 발생 시 다중 스택 레이어와 추가 메타데이터를 포함하여 상세한 에러 로그 기록 |
성능 모니터링 (Performance Monitoring) | - HTTP 요청 처리 시간 및 Slow Query (예: 500ms) 경고 로그 생성- 실행 계획(Explain Plan) 리포트 시각화 |
커스터마이징 (Customization) | - logger-config.yaml 파일을 통해 로그 저장 경로, 로그 레벨, 파일 크기, 회전 주기 등을 쉽게 조정 가능 |
Blanc Logger는 기본 설정을 제공하지만, 필요에 따라 사용자 환경에 맞게 커스터마이징 할 수 있습니다.
설정을 변경하려면프로젝트 루트
에logger-config.yaml
파일을 생성하고 아래와 같이Override
할 수 있습니다.
LOG_DIR: logs # 로그 파일 저장 경로 (기본: 프로젝트 루트/logs)
CONSOLE_LOG_LEVEL: info # 콘솔 출력 로그 레벨 (debug, verbose, info, warn, error)
FILE_LOG_LEVEL: error # 파일 출력 로그 레벨 (debug, verbose, info, warn, error)
ROTATION_DAYS: 30d # 로그 파일 보관 기간 (예: 30일)
MAX_FILE_SIZE: 20m # 단일 파일 최대 크기 (예: 20MB)
SQL Query Log Example
╔═ SQL Query ═════════════════════════════════
SELECT
"user"."id" AS "userId",
"user"."email" AS "userEmail"
FROM "user" "user"
WHERE "user"."age" > $1
╠═ Parameters ═══════════════════════════════
[18]
╠═ Analysis ═════════════════════════════════
⚠️ Avoid SELECT * - specify columns explicitly
╚═════════════════════════════════════════════
Console Output Log Example
Console Error Log Example
HTTP 요청 처리 시간을 측정하여 로그로 기록하는 인터셉터 예제입니다.
BlancLoggerMiddleware를 통해 설정된 모듈명 정보가 자동으로 포함됩니다.
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { blancLogger } from 'blanc-logger';
import * as chalk from 'chalk';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const startTime = Date.now();
const req = context.switchToHttp().getRequest();
const decodedUrl = decodeURIComponent(req.url);
const moduleName = (req as any).moduleName || 'UnknownModule';
return next.handle().pipe(
tap(() => {
const delay = Date.now() - startTime;
const delayStr =
delay > 500 ? chalk.bold.red(`${delay}ms 🚨`) : chalk.magenta(`${delay}ms`);
const message = `Request processed: ${chalk.yellow(req.method)} ${chalk.green(
decodedUrl,
)} ${delayStr}`;
blancLogger.log(message, moduleName);
}),
);
}
}
전역 인터셉터로 적용하려면 AppModule에 아래와 같이 등록합니다
import { Module } from '@nestjs/common';
import { APP_INTERCEPTOR } from '@nestjs/core';
import { LoggingInterceptor } from './commons/interceptors/logging.interceptor';
@Module({
providers: [
{
provide: APP_INTERCEPTOR,
useClass: LoggingInterceptor, // 전역 인터셉터로 등록
},
],
})
export class AppModule {}
Console Output Log Example
- 응답 시간 (예: 500ms) 초과 시 강조
Blanc Logger를 사용하여 예외 발생 시 상세한 에러 정보를 로그로 기록하는 전역 익셉션 필터 예제입니다.
BlancLoggerMiddleware를 통해 설정된 모듈명 정보가 자동으로 포함됩니다.
import {
ArgumentsHost,
Catch,
ExceptionFilter,
HttpException,
InternalServerErrorException,
} from '@nestjs/common';
import { blancLogger } from 'blanc-logger';
import { Request, Response } from 'express';
interface ExceptionResponse {
status: number;
message: string;
stack?: string;
}
/** 예외 객체를 처리하여 상태, 메시지, 스택을 반환하는 함수 */
const handleException = (exception: unknown, _request: Request): ExceptionResponse => {
if (exception instanceof HttpException) {
const status = exception.getStatus();
const res = exception.getResponse();
const message =
typeof res === 'object' && res !== null
? (res as any).message ?? exception.message
: exception.message;
return {
status,
message: `HTTP Exception: ${message}`,
stack: exception instanceof Error ? exception.stack : '',
};
}
if (exception instanceof Error) {
const status = new InternalServerErrorException().getStatus();
return {
status,
message: `Unhandled exception: ${exception.message}`,
stack: exception.stack,
};
}
return { status: 500, message: 'Unknown error' };
};
@Catch()
export class GlobalExceptionFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost): void {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
const moduleName = (request as any)?.moduleName ?? 'Global';
const { status, message, stack } = handleException(exception, request);
blancLogger.error(message, {
moduleName,
path: request.url,
stack,
});
response.status(status).json({
statusCode: status,
status: message,
timestamp: new Date().toISOString(),
path: request.url,
});
}
}
전역 필터로 적용하려면 AppModule에 아래와 같이 등록합니다
import { Module } from '@nestjs/common';
import { APP_FILTER } from '@nestjs/core';
import { GlobalExceptionFilter } from './commons/filters/global-exception.filter';
@Module({
providers: [
{
provide: APP_FILTER,
useClass: GlobalExceptionFilter, // 전역 필터로 등록
},
],
})
export class AppModule {}
전역 익셉션 필터를 적용한 후, 다음과 같이 예외를 던질 경우
throw new ConflictException('DUPLICATION');
Console Output Log Example
또한, 동일하게 로그 파일도 생성됩니다.
{"level":"error","message":"HTTP Exception: DUPLICATION","stack":[{"moduleName":"user","path":"/api/user/profile","stack":"ConflictException: DUPLICATION\n at UserService.getProfile (/path/to/src/user/user.service.ts:60:13)\n at process.processTicksAndRejections (node:internal/process/task_queues:95:5)"}],"timestamp":"2025-03-03 14:29:51"}
이 프로젝트는 MIT License에 따라 배포 및 사용이 가능합니다.