Skip to content

Commit

Permalink
Merge pull request #282 from boostcampwm-2024/Feature/be/logger
Browse files Browse the repository at this point in the history
[Feature] 로깅 인터셉터와 필터 적용
  • Loading branch information
gamgyul163 authored Nov 27, 2024
2 parents c3dd89d + 8d02f2d commit 2605c80
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 8 deletions.
14 changes: 13 additions & 1 deletion Backend/apps/api/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ import { RedisModule } from '@nestjs-modules/ioredis';
import { redisConfig } from './config/redis.config';
import { WinstonModule } from 'nest-winston';
import { winstonConfig } from './config/logger.config';
import { APP_INTERCEPTOR, APP_FILTER } from '@nestjs/core';
import { LoggingInterceptor } from './common/interceptors/logging.interceptor';
import { HttpExceptionFilter } from './common/filters/http-exception.filter';

@Module({
imports: [
Expand All @@ -42,6 +45,15 @@ import { winstonConfig } from './config/logger.config';
FollowModule,
],
controllers: [AppController],
providers: [AppService],
providers: [
AppService,
{
provide: APP_INTERCEPTOR,
useClass: LoggingInterceptor,
},
{
provide: APP_FILTER,
useClass: HttpExceptionFilter,
},],
})
export class AppModule {}
45 changes: 45 additions & 0 deletions Backend/apps/api/src/common/filters/http-exception.filter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {
ExceptionFilter,
Catch,
ArgumentsHost,
HttpException,
HttpStatus,
Inject,
} from '@nestjs/common';
import { Request, Response } from 'express';
import { Logger } from 'winston';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';

@Catch()
export class HttpExceptionFilter implements ExceptionFilter {
constructor(
@Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger,
) {}

catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToHttp();

const request = ctx.getRequest<Request>();
const response = ctx.getResponse<Response>();

const status =
exception instanceof HttpException
? exception.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR;

const message =
exception instanceof HttpException
? exception.getResponse()
: exception;

this.logger.error(
`HTTP Status: ${status} Error Message: ${JSON.stringify(message)}`,
);

response.status(status).json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
});
}
}
45 changes: 45 additions & 0 deletions Backend/apps/api/src/common/interceptors/logging.interceptor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {
CallHandler,
ExecutionContext,
Injectable,
NestInterceptor,
Inject,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
import { Request, Response } from 'express';
import { Logger } from 'winston';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
constructor(
@Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger,
) {}

intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const now = Date.now();

const ctx = context.switchToHttp();
const request = ctx.getRequest<Request>();
const response = ctx.getResponse<Response>();

const { method, originalUrl } = request;
const headers = { ...request.headers };
delete headers['authorization']; // Authorization 헤더 제외 - 보안상

return next.handle().pipe(
tap(() => {
const statusCode = response.statusCode;
const contentLength = response.get('content-length') || '0';

this.logger.info(
`${method} ${originalUrl} ${statusCode} ${contentLength} - ${
Date.now() - now
}ms`,
{ headers }, // 제외한 헤더를 로그에 포함
);
}),
);
}
}
20 changes: 15 additions & 5 deletions Backend/apps/api/src/config/logger.config.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
import * as winston from 'winston';
import 'winston-daily-rotate-file';

const logLevel = 'warn';
const logDir = './logs';

export const winstonConfig: winston.LoggerOptions = {
level: 'error', // 'error' 레벨 이상의 로그만 출력
level: logLevel,
format: winston.format.combine(
winston.format.timestamp(),
winston.format.printf(({ timestamp, level, message, stack }) => {
return `${timestamp} [${level.toUpperCase()}]: ${message} ${
stack ? '\n' + stack : ''
}`;
winston.format.printf(({ timestamp, level, message }) => {
return `${timestamp} [${level.toUpperCase()}]: ${message}`;
}),
),
transports: [
new winston.transports.Console(),
new winston.transports.DailyRotateFile({
dirname: logDir,
filename: 'application-%DATE%.log',
datePattern: 'YYYY-MM-DD',
zippedArchive: true,
maxSize: '20m',
maxFiles: '14d',
}),
],
};
1 change: 1 addition & 0 deletions Backend/apps/api/src/follow/follow.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export class FollowService {
usersNickname: streamer.nickname,
usersProfileImage: streamer.profileImage,
onAir: streamer.live?.onAir || false,
viewers: streamer.live?.viewers || 0
}));
}

Expand Down
39 changes: 38 additions & 1 deletion Backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@
"rxjs": "^7.8.1",
"socket.io": "^4.8.1",
"typeorm": "^0.3.20",
"winston": "^3.15.0"
"winston": "^3.15.0",
"winston-daily-rotate-file": "^5.0.0"
},
"devDependencies": {
"@nestjs/cli": "^10.0.0",
Expand Down

0 comments on commit 2605c80

Please sign in to comment.