-
Notifications
You must be signed in to change notification settings - Fork 2
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
[Feat] logger 적용 #333
[Feat] logger 적용 #333
Changes from 7 commits
3e5bd80
da7fafc
ae8239e
c4e876f
785c71b
46f71bc
78d062e
eeefb25
aceac7e
8c8c792
5244322
d344eb3
525194c
ec2bdbb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import path from 'path'; | ||
|
||
import { Injectable } from '@nestjs/common'; | ||
import { Cron, CronExpression } from '@nestjs/schedule'; | ||
|
||
import { LoggerService } from './logger.service'; | ||
import { NcpService } from '../ncp/ncp.service'; | ||
|
||
@Injectable() | ||
export class LogBatchService { | ||
constructor( | ||
private readonly ncpService: NcpService, | ||
private readonly loggerService: LoggerService | ||
) {} | ||
|
||
@Cron(CronExpression.EVERY_DAY_AT_1AM) | ||
async uploadLogToObjectStorage() { | ||
const logsDir = path.join(__dirname, '../../../logs'); | ||
console.log('logsDir : ', logsDir); | ||
const today = new Date(); | ||
today.setHours(today.getHours() + 9); | ||
today.setDate(today.getDate() - 1); | ||
|
||
console.log('today : ', today); | ||
const logFileName = `application-${today.toISOString().split('T')[0]}.log`; | ||
const localFilePath = path.join(logsDir, logFileName); | ||
|
||
console.log('localFilePath : ', localFilePath); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. p3 : 필요없는 log나 주석은 삭제해주셔도 좋을 것 같아요~! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. p1: 현재 lint 상에 console.log는 오류가 발생하도록 되어있어 CI/CD시 오류가 발생할 것으로 보입니다 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 헉 테스트하고 그대로 뒀습니다 삭제하겠습니다~! |
||
try { | ||
const remoteFileName = `logs/${logFileName}`; | ||
const result = await this.ncpService.uploadFile(localFilePath, remoteFileName); | ||
this.loggerService.log(`Log file uploaded successfully: ${result}`, 'logBatchService'); | ||
} catch (error) { | ||
this.loggerService.log(`Failed to upload log file: ${error}`, 'logBatchService'); | ||
} | ||
} | ||
} |
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 { LoggerService } from './logger.service'; | ||
|
||
@Injectable() | ||
export class LoggerMiddleware implements NestMiddleware { | ||
constructor(private readonly logger: LoggerService) {} | ||
|
||
use(req: Request, res: Response, next: NextFunction) { | ||
const { method, originalUrl } = req; | ||
const userAgent = req.headers['user-agent'] || 'Unknown'; | ||
|
||
res.on('finish', () => { | ||
const { statusCode } = res; | ||
const contentLength = res.get('content-length') || 0; | ||
|
||
this.logger.log( | ||
`[${method}] ${originalUrl} - ${statusCode} - ${contentLength} bytes - UserAgent: ${userAgent}`, | ||
'HTTP' | ||
); | ||
}); | ||
|
||
next(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { Global, Module } from '@nestjs/common'; | ||
import { ScheduleModule } from '@nestjs/schedule'; | ||
import { WinstonModule } from 'nest-winston'; | ||
|
||
import { WinstonConfig } from '@/config/winston.confing'; | ||
|
||
import { LogBatchService } from './logger.batch'; | ||
import { LoggerService } from './logger.service'; | ||
import { NcpModule } from '../ncp/ncp.module'; | ||
|
||
@Global() | ||
@Module({ | ||
imports: [WinstonModule.forRoot(WinstonConfig), ScheduleModule.forRoot(), NcpModule], | ||
providers: [LoggerService, LogBatchService], | ||
exports: [LoggerService], | ||
}) | ||
export class LoggerModule {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { Inject, Injectable, LoggerService as NestLoggerService } from '@nestjs/common'; | ||
import { WINSTON_MODULE_PROVIDER } from 'nest-winston'; | ||
import { Logger } from 'winston'; | ||
|
||
@Injectable() | ||
export class LoggerService implements NestLoggerService { | ||
constructor(@Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger) {} | ||
|
||
log(message: string, context: string) { | ||
this.logger.info(message, { context }); | ||
} | ||
|
||
error(message: string, trace: string, context: string) { | ||
this.logger.error(message, { trace, context }); | ||
} | ||
|
||
warn(message: string, context: string) { | ||
this.logger.warn(message, { context }); | ||
} | ||
|
||
debug(message: string, context: string) { | ||
this.logger.debug(message, { context }); | ||
} | ||
|
||
verbose(message: string, context: string) { | ||
this.logger.verbose(message, { context }); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { Module } from '@nestjs/common'; | ||
|
||
import { NcpConfig } from '@/config/ncp.config'; | ||
|
||
import { NcpService } from './ncp.service'; | ||
|
||
@Module({ | ||
providers: [NcpService, NcpConfig], | ||
exports: [NcpService], | ||
}) | ||
export class NcpModule {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import * as fs from 'fs'; | ||
|
||
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'; | ||
import { Injectable } from '@nestjs/common'; | ||
import { ConfigService } from '@nestjs/config'; | ||
import { ErrorMessage } from '@repo/types'; | ||
|
||
import { NcpConfig } from '@/config/ncp.config'; | ||
|
||
@Injectable() | ||
export class NcpService { | ||
private s3: S3Client; | ||
|
||
constructor( | ||
private ncpConfig: NcpConfig, | ||
private configService: ConfigService | ||
) { | ||
this.s3 = ncpConfig.s3Client; | ||
} | ||
|
||
async uploadFile(localFilePath: string, remoteFileName: string): Promise<string> { | ||
const bucketName = this.configService.get<string>('NCP_OBJECT_STORAGE_BUCKET'); | ||
const endpoint = this.configService.get<string>('NCP_OBJECT_STORAGE_ENDPOINT'); | ||
|
||
const fileStream = fs.createReadStream(localFilePath); | ||
const params = { | ||
Bucket: bucketName, | ||
Key: remoteFileName, | ||
Body: fileStream, | ||
}; | ||
|
||
try { | ||
const uploadResponse = await this.s3.send(new PutObjectCommand(params)); | ||
// console.log('File uploaded:', uploadResponse); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 여기도용 |
||
|
||
const url = `${endpoint}/${bucketName}/${remoteFileName}`; | ||
return remoteFileName; | ||
} catch (error) { | ||
throw new Error(ErrorMessage.FILE_UPLOAD_FAILED); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { S3Client } from '@aws-sdk/client-s3'; | ||
import { Injectable } from '@nestjs/common'; | ||
import { ConfigService } from '@nestjs/config'; | ||
|
||
@Injectable() | ||
export class NcpConfig { | ||
s3Client: S3Client; | ||
|
||
constructor(private configService: ConfigService) { | ||
const accessKeyId = this.configService.get<string>('NCP_ACCESS_KEY'); | ||
const secretAccessKey = this.configService.get<string>('NCP_SECRET_KEY'); | ||
const region = this.configService.get<string>('NCP_OBJECT_STORAGE_REGION'); | ||
const endpoint = this.configService.get<string>('NCP_OBJECT_STORAGE_ENDPOINT'); | ||
|
||
this.s3Client = new S3Client({ | ||
region: region, | ||
credentials: { | ||
accessKeyId: accessKeyId, | ||
secretAccessKey: secretAccessKey, | ||
}, | ||
endpoint: endpoint, | ||
forcePathStyle: true, | ||
}); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import path from 'path'; | ||
|
||
import * as winston from 'winston'; | ||
import 'winston-daily-rotate-file'; | ||
|
||
export const WinstonConfig = { | ||
transports: [ | ||
new winston.transports.Console({ | ||
format: winston.format.combine( | ||
winston.format.timestamp(), | ||
winston.format.colorize(), | ||
winston.format.printf(({ level, message, timestamp }) => { | ||
return `[${timestamp}] ${level}: ${message}`; | ||
}) | ||
), | ||
}), | ||
new winston.transports.DailyRotateFile({ | ||
dirname: path.join(__dirname, '../../logs'), | ||
filename: 'application-%DATE%.log', | ||
datePattern: 'YYYY-MM-DD', | ||
zippedArchive: true, | ||
maxSize: '20m', | ||
maxFiles: '14d', | ||
}), | ||
], | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
p3
사용하지않는 IMPORT 제거부탁드립니다!