ํฐ์คํ ๋ฆฌ ๋ทฐ
nestjs๋ก ์ฌ์ด๋ ํ๋ก์ ํธ๋ฅผ ๊ฐ๋ฐํ๋ฉด์ winston์ ์ด์ฉํด logging์ ์ ์ฉํ ๊ฒฝํ์ ๊ธฐ๋กํฉ๋๋ค.
๋ค์ ์์๋ก ๊ธฐ๋กํฉ๋๋ค.
- http-logger-middleware ์ ์ฉ (morgan X)
- nest-winston + winston-daily-rotate-file
log๋ฅผ ๋จ๊ฒจ์ผํ๋ ์ด์
log๋ฅผ ๋จ๊ฒจ์ผํ๋ ์ด์ ๋ ๋ค์ํ๊ฒ ์ง๋ง ๋ด๊ฐ ํด๋น ์ฌ์ด๋ ํ๋ก์ ํธ์์ log๋ฅผ ๋จ๊ฒจ์ผ๊ฒ ๋ค๊ณ ์๊ฐํ ์ด์ ๋ ๋ค์๊ณผ ๊ฐ๋ค. ๋ณดํต ํผ๋๋ฐฑ๊ณผ ๊ด๋ จ๋ ๋ด์ฉ์ด๋ค.
- ์์ ๋ ์๋น์ค๋ฅผ ์ํด log๋ฅผ ํตํ ์๋น์ค ์ํ ๋ฐ ๋ก์ง์ ์ถ์
- error ๋ฐ์ ์์ error ์ํฉ ์ถ์
- file ํํ๋ก log๋ฅผ ๋จ๊ฒจ ์ ๊ณผ์ ์ ์ข ๋ ์ ์ฐํ๊ฒ ๋ง๋ค๊ธฐ
- ๋ก๊ทธ๋ฅผ ํ์ฉํ ๋ชจ๋ํฐ๋ง ํ๊ฒฝ ๊ตฌ์ถ
http-logger-middleware ์ ์ฉํ๊ธฐ
๋จผ์ , ๊ธฐ์กด nodejs ํ๋ก์ ํธ์์ ์ฌ์ฉํ๋ morgan module์ฒ๋ผ http ์์ฒญ ์ ๋ณด๋ฅผ logging ํด์ฃผ๋ ๊ธฐ๋กํ๋ ๊ฒ์ด ํ์ํ๋ค.
๊ทธ๋์ ๊ฐ์ฅ ๋จผ์ ๋ ์ค๋ฅธ morgan์ nest-morgan์ ์ด์ฉํด์ ์ ์ฉํด๋ณด์์ผ๋ ํด๋น package๋ deprecated ๋์ด์์๊ณ , ์ถ๋ ฅ๋๋ ๋ด์ฉ๋ ๋ด๊ฐ ์ํ๋ ํ์์ ์๋์๋ค.
๊ฒฐ๊ตญ ๊ฐ๋จํ๊ฒ http-logger-middeleware๋ ์ง์ ๊ตฌํํ๊ธฐ๋ก ํ๋ค.
๊ตฌํํ http-logger middleware๋ ๋ค์๊ณผ ๊ฐ๋ค. ๊ธฐ์กด์ ์ฌ์ฉํ๋ morgan์ ํํ์ ๋น์ทํ ํํ์ด๋ค.
Youtube http-logger๋ฅผ ๋ง๋๋ ์์์ด ์์ด ์ฐธ๊ณ ํ๋ค.
// http-logger.middleware.ts
import { Injectable, Logger, NestMiddleware } from '@nestjs/common';
import { NextFunction, Request, Response } from 'express';
@Injectable()
export class HttpLoggerMiddleware implements NestMiddleware {
private logger = new Logger('HTTP');
use(request: Request, response: Response, next: NextFunction) {
const { ip, method, originalUrl } = request;
const userAgent = request.get('user-agent') || '';
response.on('finish', () => { // (1)
const { statusCode } = response;
const contentLength = response.get('content-length');
this.logger.log(
`${method} ${originalUrl} ${statusCode} ${contentLength} - ${userAgent} ${ip}`,
);
});
next();
}
}
- (1) response์ finish eventListener : node์์ http response ์ ์ก ์์ emit ํ๋ finish ์ด๋ฒคํธ๋ฅผ catch ํ๋ค node.js event-finish
์ middleware๋ฅผ ๊ตฌํํ๊ณ , ์๋์ ๊ฐ์ด ์ต์์ ๋ชจ๋์ธ AppModule
์ HttpLoggerMiddleware๋ฅผ ์ ์ฉํ๋ค.
// app.module.ts
@Module({
imports: [
TypeOrmModule.forRoot(typeORMConfig),
AuthModule,
WorkbookModule,
UserModule,
CommonModule,
],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(HttpLoggerMiddleware).forRoutes('*');
}
}
์ดํ API๋ฅผ ํ ์คํธํด๋ณธ ๊ฒฐ๊ณผ ๋ค์๊ณผ ๊ฐ์ด ์ถ๋ ฅ๋๋ ๊ฒ์ ํ์ธํ๋ค.
file ํํ๋ก log๋ฅผ ๊ธฐ๋กํ์
๋ณดํต ์๋ฒ ๋ฐฐํฌ ์์ nohub์ ์ด์ฉํด ์ถ๋ ฅ ๋ก๊ทธ๊ฐ ๊ธฐ๋ก๋๊ธดํ์ง๋ง, ์ด๋ ๊ด๋ฆฌ๊ฐ ์ด๋ ต๊ณ ๊ฐ์ธ์ ์ผ๋ก ๋ก๊ทธ๋ฅผ ๋ฐ๋ก ํ์ผ๋ก ์ ๋ฆฌํด์ ์ ์ฅํ๋ ๊ฒ์ด ํ์ํ๋ค๊ณ ํ๋จํ๋ค. ๊ทธ๋์ file ํํ๋ก log๋ฅผ ๋ฐ๋ก ์ ์ฅํ๊ธฐ๋ก ํ๋ค.
node์์ ์ต์ํ winston module์ ์ฌ์ฉํ๊ณ ์ถ์๋๋ฐ, nest-winston ๋ชจ๋์ ๋ฐ๊ฒฌํด์ ๋น ๋ฅด๊ฒ ์ ์ฉํด๋ณผ ์ ์์๋ค.
๋ํ ๋ ์ง๋ณ๋ก ํ์ผ์ ์ ์ฅํ๊ธฐ ์ํด winston-daily-rotate-file module๋ ์ถ๊ฐ๋ก ์ด์ฉํ๋ค
npm install nest-winston winston
npm install winston-daily-rotate-file
// logger-config.ts
import {
utilities as nestWinstonModuleUtilities,
WinstonModule,
} from 'nest-winston';
import { format, Logform, transports } from 'winston';
import 'winston-daily-rotate-file';
export class LoggerConfig {
static createApplicationLogger() {
return WinstonModule.createLogger({
format: format.combine(
format.timestamp(),
nestWinstonModuleUtilities.format.nestLike('FLIP'), // (1)
),
transports: [
new transports.Console({}),
new transports.DailyRotateFile({ // (2)
format: this.logFileFormat(),
filename: 'application-%DATE%.log', // (3)
dirname: 'logs',
datePattern: 'YYYY-MM-DD-HH',
zippedArchive: true,
maxSize: '20m',
maxFiles: '14d',
}),
new transports.DailyRotateFile({
format: this.logFileFormat(),
level: 'error',
filename: 'error-%DATE%.log',
dirname: 'logs',
datePattern: 'YYYY-MM-DD',
zippedArchive: true,
maxSize: '20m',
maxFiles: '14d',
}),
],
});
}
private static logFileFormat(): Logform.Format {
return format.combine(
format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
format.printf((info) => JSON.stringify(info)), // (4)
);
}
- (1) nest-winston ๋ชจ๋์ ๊ธฐ์กด nest log์ ๋น์ทํ๊ฒ ์ถ๋ ฅ ํฌ๋ฉง์ ์ ํด์ฃผ๋ ์ ํธ์ด ์์ด ์ฌ์ฉํ๋ค. FLIP์ ์ฌ์ด๋ ํ๋ก์ ํธ ์ด๋ฆ์ด๋ค. ์๋ฌด๊ฑฐ๋ ์ ๋ ฅํด๋ ๋๋ค.
- (2)
winston-daily-rotate-file
์DailyRotateFile()
์ ์ด์ฉํด ํ์ผ์ ์๊ฐ์ ๋ฐ๋ผ ๋ฐ๊พธ๊ฒ ํ๋ค. - (3) %DATE%์๋ ์๊ฐ ํฌ๋งท(datePattern)๊ฐ์ด ์ ๋ ฅ๋๋ค. ex) application-2022-02-21.log
- (4) ํด๋น ํฌ๋ฉง์ logFile์ ์ ์ฅ๋ ํฌ๋ฉง์ด๋ค ์์ ์ด ์ํ๋ ํ์์ ์ ํํ์.
์ดํ main.ts bootstrap()์์ ๊ธฐ๋ณธ logger๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ๋ณ๊ฒฝํด์ฃผ์๋ค.
// main.ts
import { LoggerConfig } from './common/config/logger-config';
async function bootstrap() {
const appOptions: NestApplicationOptions = {
logger: LoggerConfig.createApplicationLogger(),
};
const app = await NestFactory.create(AppModule, appOptions);
// ...
}
๋ง๋ฌด๋ฆฌ
๋ค์์ ์ ์ฝ๋๋ฅผ ํ
์คํธํ ๊ฒฐ๊ณผ์ด๋ค. (http-logger, log files)
์ํ๋๋๋ก ์ ์๋ํ๊ณ , ์ดํ์ ๋ชจ๋ํฐ๋ง, ๋ก๊ทธ ๋ถ์ ๋ฑ์ ํ์ต์ ์ด์ด๊ฐ ์๊ฐ์ด๋ค
log files
- Total
- Today
- Yesterday
- golang oomkilled
- ์คํ/ํ
- ๊น์ด/๋๋น ์ฐ์ ํ์(DFS/BFS)
- HTTP
- ํธ๋์ญ์ ๊ฒฉ๋ฆฌ ์์ค
- ์๊ณ ๋ฆฌ์ฆ
- 2023 ํ๊ณ
- grpc client
- mysql ์คํ ๊ณํ
- 2023 ๊ฐ๋ฐ์ ํ๊ณ
- rate limit
- ์ข์ ์์ง๋์ด
- kotlin s3 upload
- mysql
- ์ข์ ๊ฐ๋ฐ์
- ์ข์ ์ฝ๋๋ ๋ฌด์์ธ๊ฐ?
- ํด์
- Go
- ํ(Heap)
- ๋ฐฑ์ค
- AWS re:Invent 2023
- ์ข์ ๊ฐ๋ฐ์ ๋๊ธฐ
- ๋ฑ ํฌ์๋ฌ๋ ๊ฐ๋ฐ์
- Aws Reinvent 2023
- Golang
- ์ฝ๋ฉํ ์คํธ
- ํ๋ก๊ทธ๋๋จธ์ค
- ์ฅ์ ํ๊ณ
- ์ถ์ ์ง๋
- 2๋ ์ฐจ ์๋ฒ ๊ฐ๋ฐ์
์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |