Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Server] Winston으로 로그 관리 #70

Merged
merged 7 commits into from
Nov 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
## 완료한 기능 혹은 수정 기능
## 🚀 완료한 기능 혹은 수정 기능

## 고민과 해결 과정

## 스크린샷
<br>

## 테스트 결과(커버리지/테스트 결과)
## 💡 고민과 해결 과정
### `배경`

### `고민`

### `해결과정`

<br>

## 📸 스크린샷

<br>

## ✅ 테스트 결과(커버리지/테스트 결과)
5 changes: 4 additions & 1 deletion server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,13 @@
"@nestjs/typeorm": "^10.0.0",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.0",
"nest-winston": "^1.9.4",
"pg": "^8.11.3",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.1",
"typeorm": "^0.3.17"
"typeorm": "^0.3.17",
"winston": "^3.11.0",
"winston-daily-rotate-file": "^4.7.1"
},
"devDependencies": {
"@nestjs/cli": "^10.0.0",
Expand Down
19 changes: 17 additions & 2 deletions server/src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { Module } from '@nestjs/common';
import {
MiddlewareConsumer,
Module,
NestModule,
RequestMethod,
} from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
Expand All @@ -11,6 +16,9 @@ import { ChecklistsModule } from './folders/private-checklists/private-checklist
import { SharedChecklistModel } from './shared-checklists/entities/shared-checklist.entity';
import { UserModel } from './users/entities/user.entity';
import { UsersModule } from './users/users.module';
import { LoggerMiddleware } from './common/middlewares/logger.middleware';
import { winstonConfig } from './utils/winston.config';
import { WinstonModule } from 'nest-winston';

@Module({
imports: [
Expand All @@ -33,6 +41,7 @@ import { UsersModule } from './users/users.module';
],
synchronize: true, // DO NOT USE IN PRODUCTION
}),
WinstonModule.forRoot(winstonConfig),
CommonModule,
UsersModule,
FoldersModule,
Expand All @@ -41,4 +50,10 @@ import { UsersModule } from './users/users.module';
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(LoggerMiddleware)
.forRoutes({ path: '*', method: RequestMethod.ALL });
}
}
26 changes: 26 additions & 0 deletions server/src/common/middlewares/logger.middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
import { WinstonModule } from 'nest-winston';
import { winstonConfig } from '../../utils/winston.config';

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
private readonly logger = WinstonModule.createLogger(winstonConfig);

use(req: Request, res: Response, next: NextFunction) {
const startTime = Date.now(); // 요청 시작 시간 기록
const { ip, method, originalUrl } = req;
const userAgent = req.get('user-agent');

res.on('finish', () => {
const duration = Date.now() - startTime; // 요청 처리 시간 계산
const { statusCode } = res;
this.logger.log({
level: 'info',
message: `${method} ${originalUrl} ${statusCode} ${ip} ${userAgent} - ${duration}ms`,
});
});

next();
}
}
44 changes: 44 additions & 0 deletions server/src/utils/winston.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { utilities } from 'nest-winston';
import * as winstonDaily from 'winston-daily-rotate-file';
import * as winston from 'winston';

const env = process.env.NODE_ENV;
const logDir = __dirname + '/../../logs'; // log 파일을 관리할 폴더

const dailyOptions = (level: string) => {
return {
level,
datePattern: 'YYYY-MM-DD',
dirname: logDir + `/${level}`,
filename: `%DATE%.${level}.log`,
maxFiles: 30, //30일치 로그파일 저장
zippedArchive: true, // 로그가 쌓이면 압축하여 관리
};
};

// rfc5424를 따르는 winston만의 log level
// error: 0, warn: 1, info: 2, http: 3, verbose: 4, debug: 5, silly: 6
export const winstonConfig = {
transports: [
new winston.transports.Console({
level: env === 'production' ? 'http' : 'silly',
// production 환경이라면 http, 개발환경이라면 모든 단계를 로그
format:
env === 'production'
? // production 환경은 자원을 아끼기 위해 simple 포맷 사용
winston.format.simple()
: winston.format.combine(
winston.format.colorize(),
winston.format.timestamp(),
utilities.format.nestLike('OpenList', {
prettyPrint: true, // nest에서 제공하는 옵션. 로그 가독성을 높여줌
}),
),
}),

// info, warn, error 로그는 파일로 관리
new winstonDaily(dailyOptions('info')),
new winstonDaily(dailyOptions('warn')),
new winstonDaily(dailyOptions('error')),
],
};
Loading