mirror of
https://git.hmsn.ink/coin/bot.git
synced 2026-03-19 15:55:01 +09:00
first
This commit is contained in:
180
logger.js
Normal file
180
logger.js
Normal file
@@ -0,0 +1,180 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
// 로그 디렉토리 생성
|
||||
const logDir = './logs';
|
||||
if (!fs.existsSync(logDir)) {
|
||||
fs.mkdirSync(logDir, { recursive: true });
|
||||
}
|
||||
|
||||
// 로그 레벨 정의
|
||||
const logLevels = {
|
||||
DEBUG: 0,
|
||||
INFO: 1,
|
||||
WARN: 2,
|
||||
ERROR: 3,
|
||||
CRITICAL: 4
|
||||
};
|
||||
|
||||
const logLevelNames = Object.keys(logLevels);
|
||||
const currentLogLevel = logLevels.info; // 설정에 따라 변경 가능
|
||||
|
||||
// 타임스탬프 생성
|
||||
const getTimestamp = () => new Date().toISOString();
|
||||
|
||||
// 호출자 정보 추출 (ESM 호환)
|
||||
const getCallerInfo = () => {
|
||||
const err = new Error();
|
||||
const stack = err.stack.split('\n');
|
||||
|
||||
// 스택에서 호출자 위치 찾기
|
||||
let callerIndex = 2; // 기본값 (0: Error, 1: getCallerInfo, 2: logger function)
|
||||
|
||||
// 'at '로 시작하는 라인 찾기
|
||||
for (let i = 2; i < stack.length; i++) {
|
||||
if (stack[i].includes('at ')) {
|
||||
callerIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (stack.length > callerIndex) {
|
||||
const callerLine = stack[callerIndex].trim();
|
||||
|
||||
// 파일 경로 추출 (Windows와 Unix 경로 모두 처리)
|
||||
const fileMatch = callerLine.match(/\((.*?):\d+:\d+\)/) ||
|
||||
callerLine.match(/(.*?):\d+:\d+$/);
|
||||
|
||||
if (fileMatch && fileMatch[1]) {
|
||||
const filePath = fileMatch[1];
|
||||
const fileName = path.basename(filePath);
|
||||
return fileName;
|
||||
}
|
||||
}
|
||||
|
||||
return 'unknown';
|
||||
};
|
||||
|
||||
// 로그 포맷팅
|
||||
const formatLog = (level, message, metadata = {}) => {
|
||||
const timestamp = getTimestamp();
|
||||
const callerInfo = getCallerInfo();
|
||||
const levelName = logLevelNames[level];
|
||||
|
||||
let logMessage = `[${levelName}] ${timestamp} [${callerInfo}] ${message}`;
|
||||
|
||||
if (Object.keys(metadata).length > 0) {
|
||||
try {
|
||||
logMessage += `\n Meta: ${JSON.stringify(metadata, null, 2)}`;
|
||||
} catch (e) {
|
||||
logMessage += `\n Meta: [Circular or invalid object]`;
|
||||
}
|
||||
}
|
||||
|
||||
return logMessage;
|
||||
};
|
||||
|
||||
// 로그 파일 쓰기
|
||||
const writeLog = (logMessage, level) => {
|
||||
if (level < currentLogLevel) return;
|
||||
|
||||
// 콘솔 출력
|
||||
if (level >= logLevels.ERROR) {
|
||||
console.error(logMessage);
|
||||
} else {
|
||||
console.log(logMessage);
|
||||
}
|
||||
|
||||
// 파일 로깅
|
||||
try {
|
||||
const date = new Date().toISOString().split('T')[0];
|
||||
const logFile = path.join(logDir, `trading-${date}.log`);
|
||||
fs.appendFileSync(logFile, logMessage + '\n');
|
||||
} catch (e) {
|
||||
// 파일 로깅 실패 시 콘솔에 경고
|
||||
console.error(`[LOGGER] Failed to write log file: ${e.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
// 로거 인스턴스 생성
|
||||
const createLogger = () => {
|
||||
return {
|
||||
debug: (message, metadata = {}) => {
|
||||
const logMessage = formatLog(logLevels.DEBUG, message, metadata);
|
||||
writeLog(logMessage, logLevels.DEBUG);
|
||||
},
|
||||
|
||||
info: (message, metadata = {}) => {
|
||||
const logMessage = formatLog(logLevels.INFO, message, metadata);
|
||||
writeLog(logMessage, logLevels.INFO);
|
||||
},
|
||||
|
||||
warn: (message, metadata = {}) => {
|
||||
const logMessage = formatLog(logLevels.WARN, message, metadata);
|
||||
writeLog(logMessage, logLevels.WARN);
|
||||
},
|
||||
|
||||
error: (message, error = null, metadata = {}) => {
|
||||
const errorMetadata = { ...metadata };
|
||||
|
||||
if (error) {
|
||||
errorMetadata.error = {
|
||||
message: error.message || 'Unknown error',
|
||||
stack: error.stack ?
|
||||
error.stack.split('\n').slice(0, 5).join('\n') :
|
||||
'No stack trace'
|
||||
};
|
||||
}
|
||||
|
||||
const logMessage = formatLog(logLevels.ERROR, message, errorMetadata);
|
||||
writeLog(logMessage, logLevels.ERROR);
|
||||
},
|
||||
|
||||
critical: (message, error = null, metadata = {}) => {
|
||||
const errorMetadata = { ...metadata };
|
||||
|
||||
if (error) {
|
||||
errorMetadata.error = {
|
||||
message: error.message || 'Unknown critical error',
|
||||
stack: error.stack || 'No stack trace'
|
||||
};
|
||||
}
|
||||
|
||||
const logMessage = formatLog(logLevels.CRITICAL, message, errorMetadata);
|
||||
writeLog(logMessage, logLevels.CRITICAL);
|
||||
},
|
||||
|
||||
logPosition: (position, message) => {
|
||||
if (!position) return;
|
||||
|
||||
const metadata = {
|
||||
position: {
|
||||
id: position.id,
|
||||
side: position.side,
|
||||
entry: position.entry,
|
||||
qty: position.qty,
|
||||
sl: position.sl,
|
||||
tp: position.tp,
|
||||
openTime: position.openTime ?
|
||||
new Date(position.openTime).toISOString() : 'N/A'
|
||||
}
|
||||
};
|
||||
|
||||
if (position.closed) {
|
||||
metadata.position.exitPrice = position.exitPrice;
|
||||
metadata.position.exitReason = position.exitReason;
|
||||
metadata.position.pnl = position.pnl;
|
||||
metadata.position.closeTime = position.closeTime ?
|
||||
new Date(position.closeTime).toISOString() : 'N/A';
|
||||
}
|
||||
|
||||
this.info(message, metadata);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// 싱글톤 인스턴스 생성
|
||||
const logger = createLogger();
|
||||
|
||||
// 모듈 내보내기
|
||||
export default logger;
|
||||
Reference in New Issue
Block a user