Skip to content

Commit

Permalink
refactor: upbit 모듈 리팩토링 및 로거 적용
Browse files Browse the repository at this point in the history
  • Loading branch information
SeongHyeon0409 committed Nov 26, 2024
1 parent 6f0518f commit 1ad5fd2
Show file tree
Hide file tree
Showing 24 changed files with 970 additions and 950 deletions.
1 change: 0 additions & 1 deletion .github/workflows/CICD.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ on:
- main
- dev
- dev-be
- hotfix-be-#114
jobs:
build_and_deploy:
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion packages/server/src/account/account.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { AssetRepository } from '@src/asset/asset.repository';
import { UPBIT_IMAGE_URL } from 'common/upbit';
import { UPBIT_IMAGE_URL } from '@src/upbit/constants';
import { AccountRepository } from 'src/account/account.repository';
import { MyAccountDto } from './dtos/myAccount.dto';
import { CoinDataUpdaterService } from '@src/upbit/coin-data-updater.service';
Expand Down
130 changes: 61 additions & 69 deletions packages/server/src/configs/winston.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,87 +6,79 @@ import { join } from 'path';
const { combine, timestamp, printf, colorize } = winston.format;

const levels = {
error: 0,
warn: 1,
info: 2,
http: 3,
debug: 4,
}
error: 0,
warn: 1,
info: 2,
http: 3,
debug: 4,
};

const colors = {
error: 'red',
warn: 'yellow',
info: 'green',
http: 'magenta',
debug: 'blue',
}
error: 'red',
warn: 'yellow',
info: 'green',
http: 'magenta',
debug: 'blue',
};

winston.addColors(colors);

// 로그 저장 경로
const logDir = join(__dirname, '../../logs');

// 로그 포맷 정의
const logFormat = printf(({ level, message, timestamp, stack }) => {
return `${timestamp} ${level}: ${message} ${stack || ''}`;
return `${timestamp} ${level}: ${message} ${stack || ''}`;
});

const consoleFormat = printf(({ level, message, timestamp, context }) => {
const contextColored = context ? `\x1b[33m[${context}]\x1b[0m` : '[App]';
return `[Nest] ${process.pid} - ${timestamp} ${level} ${contextColored} ${message}`;
});

export const winstonConfig = {
levels,
transports: [
// 콘솔 출력
new winston.transports.Console({
level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
format: combine(
colorize({ all: true }),
timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
utilities.format.nestLike('MyApp', {
prettyPrint: true,
colors: true,
}),
),
}),
levels,
transports: [
// 콘솔 출력
new winston.transports.Console({
level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
format: combine(
colorize({ all: true }),
timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
consoleFormat
),
}),

// info 레벨 로그 파일
new winstonDaily({
level: 'info',
datePattern: 'YYYY-MM-DD',
dirname: join(logDir, 'info'),
filename: `%DATE%.log`,
maxFiles: 30,
zippedArchive: true,
format: combine(
timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
logFormat,
),
}),
// info 레벨 로그 파일
new winstonDaily({
level: 'info',
datePattern: 'YYYY-MM-DD',
dirname: join(logDir, 'info'),
filename: `%DATE%.log`,
maxFiles: 30,
zippedArchive: true,
format: combine(timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), logFormat),
}),

// warn 레벨 로그 파일
new winstonDaily({
level: 'warn',
datePattern: 'YYYY-MM-DD',
dirname: join(logDir, 'warn'),
filename: `%DATE%.warn.log`,
maxFiles: 30,
zippedArchive: true,
format: combine(
timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
logFormat,
),
}),
// warn 레벨 로그 파일
new winstonDaily({
level: 'warn',
datePattern: 'YYYY-MM-DD',
dirname: join(logDir, 'warn'),
filename: `%DATE%.warn.log`,
maxFiles: 30,
zippedArchive: true,
format: combine(timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), logFormat),
}),

// error 레벨 로그 파일
new winstonDaily({
level: 'error',
datePattern: 'YYYY-MM-DD',
dirname: join(logDir, 'error'),
filename: `%DATE%.error.log`,
maxFiles: 30,
zippedArchive: true,
format: combine(
timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
logFormat,
),
}),
],
};
// error 레벨 로그 파일
new winstonDaily({
level: 'error',
datePattern: 'YYYY-MM-DD',
dirname: join(logDir, 'error'),
filename: `%DATE%.error.log`,
maxFiles: 30,
zippedArchive: true,
format: combine(timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), logFormat),
}),
],
};
2 changes: 1 addition & 1 deletion packages/server/src/trade/trade-ask.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { AssetRepository } from 'src/asset/asset.repository';
import { TradeRepository } from './trade.repository';
import { CoinDataUpdaterService } from 'src/upbit/coin-data-updater.service';
import { TradeHistoryRepository } from '../trade-history/trade-history.repository';
import { UPBIT_UPDATED_COIN_INFO_TIME } from 'common/upbit';
import { UPBIT_UPDATED_COIN_INFO_TIME } from '@src/upbit/constants';
import { UserRepository } from '@src/auth/user.repository';

@Injectable()
Expand Down
2 changes: 1 addition & 1 deletion packages/server/src/trade/trade-bid.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { AssetRepository } from 'src/asset/asset.repository';
import { TradeRepository } from './trade.repository';
import { CoinDataUpdaterService } from 'src/upbit/coin-data-updater.service';
import { TradeHistoryRepository } from '../trade-history/trade-history.repository';
import { UPBIT_UPDATED_COIN_INFO_TIME } from 'common/upbit';
import { UPBIT_UPDATED_COIN_INFO_TIME } from '@src/upbit/constants';
import { UserRepository } from '@src/auth/user.repository';

@Injectable()
Expand Down
2 changes: 1 addition & 1 deletion packages/server/src/trade/trade.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { AccountRepository } from 'src/account/account.repository';
import { AssetRepository } from 'src/asset/asset.repository';
import { TradeRepository } from './trade.repository';
import { CoinDataUpdaterService } from 'src/upbit/coin-data-updater.service';
import { UPBIT_IMAGE_URL } from 'common/upbit';
import { UPBIT_IMAGE_URL } from '@src/upbit/constants';
import { TradeDataDto } from './dtos/tradeData.dto';
@Injectable()
export class TradeService {
Expand Down
60 changes: 60 additions & 0 deletions packages/server/src/upbit/SSE/base-web-socket.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Logger } from '@nestjs/common';
import * as WebSocket from 'ws';

export abstract class BaseWebSocketService {
private websocket: WebSocket;
private sending: boolean = false;
protected readonly logger: Logger;

constructor(context: string) {
this.logger = new Logger(context); // 동적으로 context 설정
}

protected abstract handleMessage(data: any): void;

protected connectWebSocket(websocketUrl: string, reconnectInterval: number): void {
this.websocket = new WebSocket(websocketUrl);

this.websocket.on('open', () => {
this.logger.log('WebSocket 연결이 열렸습니다.');
this.sendWebSocket();
});

this.websocket.on('message', (data) => {
try {
const message = JSON.parse(data.toString());
this.handleMessage(message);
} catch (error) {
this.logger.error('WebSocket 메시지 처리 중 오류:', error);
}
});

this.websocket.on('close', () => {
this.logger.warn('WebSocket 연결이 닫혔습니다. 재연결 시도 중...');
setTimeout(() => this.connectWebSocket(websocketUrl, reconnectInterval), reconnectInterval);
});

this.websocket.on('error', (error) => {
this.logger.error('WebSocket 오류:', error);
});
}

protected async sendWebSocket(): Promise<void> {
if (this.sending) return;
this.sending = true;

try {
if (this.websocket.readyState !== WebSocket.OPEN) {
await new Promise((resolve) => setTimeout(resolve, 100));
}
const message = this.getSubscribeMessage();
this.websocket.send(message);
} catch (error) {
this.logger.error('WebSocket 메시지 전송 중 오류:', error);
} finally {
this.sending = false;
}
}

protected abstract getSubscribeMessage(): string;
}
50 changes: 50 additions & 0 deletions packages/server/src/upbit/SSE/coin-ticker-websocket.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { Injectable, OnModuleInit } from '@nestjs/common';
import { SseService } from './sse.service';
import { CoinListService } from '../coin-list.service';
import {
UPBIT_WEBSOCKET_URL,
UPBIT_WEBSOCKET_CONNECTION_TIME,
} from '@src/upbit/constants';
import { BaseWebSocketService } from './base-web-socket.service';
import { CoinDataUpdaterService } from '../coin-data-updater.service';

@Injectable()
export class CoinTickerService
extends BaseWebSocketService
implements OnModuleInit
{
constructor(
private readonly coinListService: CoinListService,
private readonly coinDataUpdaterService: CoinDataUpdaterService,
private readonly sseService: SseService,
) {
super(CoinTickerService.name);
}

async onModuleInit() {
await this.ensureCoinDataInitialized();
this.connectWebSocket(UPBIT_WEBSOCKET_URL, UPBIT_WEBSOCKET_CONNECTION_TIME);
}

private async ensureCoinDataInitialized(): Promise<void> {
if (this.coinListService.getCoinNameList().length === 1) {
await this.coinDataUpdaterService.updateCoinList();
}
}

protected handleMessage(data: any) {
if (data.error) {
console.error('CoinTicker WebSocket 오류:', data);
return;
}
this.sseService.sendEvent('price', data);
}

protected getSubscribeMessage(): string {
const coinList = this.coinListService.getCoinNameList();
return JSON.stringify([
{ ticket: 'test' },
{ type: 'ticker', codes: coinList },
]);
}
}
50 changes: 50 additions & 0 deletions packages/server/src/upbit/SSE/orderbook-websocket.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
import { SseService } from './sse.service';
import { CoinListService } from '../coin-list.service';
import {
UPBIT_WEBSOCKET_URL,
UPBIT_WEBSOCKET_CONNECTION_TIME,
} from '@src/upbit/constants';
import { BaseWebSocketService } from './base-web-socket.service';
import { CoinDataUpdaterService } from '../coin-data-updater.service';

@Injectable()
export class OrderbookService
extends BaseWebSocketService
implements OnModuleInit
{
constructor(
private readonly coinListService: CoinListService,
private readonly coinDataUpdaterService: CoinDataUpdaterService,
private readonly sseService: SseService,
) {
super(OrderbookService.name);
}

async onModuleInit() {
await this.ensureCoinDataInitialized();
this.connectWebSocket(UPBIT_WEBSOCKET_URL, UPBIT_WEBSOCKET_CONNECTION_TIME);
}

private async ensureCoinDataInitialized(): Promise<void> {
if (this.coinListService.getCoinNameList().length === 1) {
await this.coinDataUpdaterService.updateCoinList();
}
}

protected handleMessage(data: any) {
if (data.error) {
this.logger.error('Orderbook WebSocket 오류:', data);
return;
}
this.sseService.sendEvent('orderbook', data);
}

protected getSubscribeMessage(): string {
const coinList = this.coinListService.getCoinNameList();
return JSON.stringify([
{ ticket: 'test' },
{ type: 'orderbook', codes: coinList },
]);
}
}
Loading

0 comments on commit 1ad5fd2

Please sign in to comment.