Files
trading_bot_v4/lib/utils/persistent-logger.ts
mindesbunister 302511293c feat: Add production logging gating (Phase 1, Task 1.1)
- Created logger utility with environment-based gating (lib/utils/logger.ts)
- Replaced 517 console.log statements with logger.log (71% reduction)
- Fixed import paths in 15 files (resolved comment-trapped imports)
- Added DEBUG_LOGS=false to .env
- Achieves 71% immediate log reduction (517/731 statements)
- Expected 90% reduction in production when deployed

Impact: Reduced I/O blocking, lower log volume in production
Risk: LOW (easy rollback, non-invasive)
Phase: Phase 1, Task 1.1 (Quick Wins - Console.log Production Gating)

Files changed:
- NEW: lib/utils/logger.ts (production-safe logging)
- NEW: scripts/replace-console-logs.js (automation tool)
- Modified: 15 lib/*.ts files (console.log → logger.log)
- Modified: .env (DEBUG_LOGS=false)

Next: Task 1.2 (Image Size Optimization)
2025-12-05 00:32:41 +01:00

152 lines
4.1 KiB
TypeScript

/**
* Persistent File Logger - Survives Container Restarts
* Critical for debugging database save failures and system issues
*/
import * as fs from 'fs'
import { logger } from '../utils/logger'
import * as path from 'path'
const LOG_DIR = '/app/logs'
const ERROR_LOG = path.join(LOG_DIR, 'errors.log')
const TRADE_LOG = path.join(LOG_DIR, 'trades.log')
const MAX_LOG_SIZE = 10 * 1024 * 1024 // 10MB per log file
// Ensure log directory exists
function ensureLogDir() {
try {
if (!fs.existsSync(LOG_DIR)) {
fs.mkdirSync(LOG_DIR, { recursive: true })
}
} catch (error) {
console.error('Failed to create log directory:', error)
}
}
// Rotate log if too large
function rotateLogIfNeeded(logPath: string) {
try {
if (fs.existsSync(logPath)) {
const stats = fs.statSync(logPath)
if (stats.size > MAX_LOG_SIZE) {
const timestamp = new Date().toISOString().replace(/[:.]/g, '-')
const rotatedPath = `${logPath}.${timestamp}`
fs.renameSync(logPath, rotatedPath)
logger.log(`📦 Rotated log: ${rotatedPath}`)
}
}
} catch (error) {
console.error('Failed to rotate log:', error)
}
}
// Format log entry
function formatLogEntry(level: string, message: string, details?: any): string {
const timestamp = new Date().toISOString()
const detailsStr = details ? `\n${JSON.stringify(details, null, 2)}` : ''
return `[${timestamp}] ${level}: ${message}${detailsStr}\n`
}
// Append to log file
function appendToLog(logPath: string, entry: string) {
try {
ensureLogDir()
rotateLogIfNeeded(logPath)
fs.appendFileSync(logPath, entry, 'utf8')
} catch (error) {
console.error(`Failed to write to ${logPath}:`, error)
}
}
/**
* Log critical error (database failures, position issues)
*/
export function logCriticalError(message: string, details?: any) {
const entry = formatLogEntry('CRITICAL', message, details)
console.error('🔴 CRITICAL:', message, details || '')
appendToLog(ERROR_LOG, entry)
}
/**
* Log trade execution (success or failure)
*/
export function logTradeExecution(
success: boolean,
tradeDetails: {
symbol: string
direction: string
entryPrice: number
positionSize: number
transactionSignature?: string
error?: string
}
) {
const level = success ? 'SUCCESS' : 'FAILURE'
const message = success
? `Trade opened: ${tradeDetails.symbol} ${tradeDetails.direction} @ $${tradeDetails.entryPrice}`
: `Trade failed: ${tradeDetails.symbol} ${tradeDetails.direction} - ${tradeDetails.error}`
const entry = formatLogEntry(level, message, tradeDetails)
logger.log(success ? '✅' : '❌', message)
appendToLog(TRADE_LOG, entry)
}
/**
* Log database operation (create, update, query)
*/
export function logDatabaseOperation(
operation: string,
success: boolean,
details: {
table?: string
recordId?: string
error?: any
retryAttempt?: number
}
) {
const level = success ? 'DB_SUCCESS' : 'DB_FAILURE'
const message = success
? `${operation} succeeded: ${details.table || 'unknown'}`
: `${operation} failed: ${details.error?.message || 'Unknown error'}`
const entry = formatLogEntry(level, message, details)
logger.log(success ? '💾' : '❌', message)
appendToLog(ERROR_LOG, entry)
}
/**
* Read recent error logs (for debugging)
*/
export function getRecentErrors(lines: number = 50): string[] {
try {
if (!fs.existsSync(ERROR_LOG)) {
return []
}
const content = fs.readFileSync(ERROR_LOG, 'utf8')
const allLines = content.split('\n').filter(line => line.trim())
return allLines.slice(-lines)
} catch (error) {
console.error('Failed to read error log:', error)
return []
}
}
/**
* Read recent trade logs
*/
export function getRecentTrades(lines: number = 50): string[] {
try {
if (!fs.existsSync(TRADE_LOG)) {
return []
}
const content = fs.readFileSync(TRADE_LOG, 'utf8')
const allLines = content.split('\n').filter(line => line.trim())
return allLines.slice(-lines)
} catch (error) {
console.error('Failed to read trade log:', error)
return []
}
}