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)
This commit is contained in:
mindesbunister
2025-12-05 00:32:41 +01:00
parent cc3a0a85a0
commit 302511293c
20 changed files with 2223 additions and 518 deletions

View File

@@ -5,6 +5,7 @@
*/
import { Connection, PublicKey, Keypair } from '@solana/web3.js'
import { logger } from '../utils/logger'
import { DriftClient, initialize, User, PerpMarkets } from '@drift-labs/sdk'
import bs58 from 'bs58'
import { getDriftHealthMonitor } from '../monitoring/drift-health-monitor'
@@ -43,9 +44,9 @@ export class DriftService {
: this.connection
if (config.alchemyRpcUrl) {
console.log('🔀 Hybrid RPC mode: Helius for init, Alchemy for trades')
logger.log('🔀 Hybrid RPC mode: Helius for init, Alchemy for trades')
} else {
console.log('📡 Single RPC mode: Helius for all operations')
logger.log('📡 Single RPC mode: Helius for all operations')
}
// Create wallet from private key
@@ -88,7 +89,7 @@ export class DriftService {
}
}
console.log('✅ Drift service created for wallet:', this.wallet.publicKey.toString())
logger.log('✅ Drift service created for wallet:', this.wallet.publicKey.toString())
}
/**
@@ -118,17 +119,17 @@ export class DriftService {
error?.code === 'EAI_AGAIN' ||
error?.cause?.code === 'EAI_AGAIN'
console.log(`🔍 Error detection: isTransient=${isTransient}, attempt=${attempt}/${maxRetries}`)
console.log(`🔍 Error details: message="${error?.message}", code="${error?.code}", cause.code="${error?.cause?.code}"`)
logger.log(`🔍 Error detection: isTransient=${isTransient}, attempt=${attempt}/${maxRetries}`)
logger.log(`🔍 Error details: message="${error?.message}", code="${error?.code}", cause.code="${error?.cause?.code}"`)
if (!isTransient || attempt === maxRetries) {
// Non-transient error or max retries reached - fail immediately
console.log(`❌ Not retrying: isTransient=${isTransient}, maxed=${attempt === maxRetries}`)
logger.log(`❌ Not retrying: isTransient=${isTransient}, maxed=${attempt === maxRetries}`)
throw error
}
console.log(`⚠️ ${operationName} failed (attempt ${attempt}/${maxRetries}): ${error?.message || error}`)
console.log(`⏳ Retrying in ${delayMs}ms...`)
logger.log(`⚠️ ${operationName} failed (attempt ${attempt}/${maxRetries}): ${error?.message || error}`)
logger.log(`⏳ Retrying in ${delayMs}ms...`)
// Wait before retry
await new Promise(resolve => setTimeout(resolve, delayMs))
@@ -144,12 +145,12 @@ export class DriftService {
*/
async initialize(): Promise<void> {
if (this.isInitialized) {
console.log('⚠️ Drift service already initialized')
logger.log('⚠️ Drift service already initialized')
return
}
try {
console.log('🚀 Initializing Drift Protocol client...')
logger.log('🚀 Initializing Drift Protocol client...')
// Wrap initialization in retry logic to handle DNS failures
await this.retryOperation(async () => {
@@ -170,20 +171,20 @@ export class DriftService {
// Subscribe to Drift account updates (this makes RPC calls)
await this.driftClient.subscribe()
console.log('✅ Drift client subscribed to account updates')
logger.log('✅ Drift client subscribed to account updates')
// Get user account
this.user = this.driftClient.getUser()
}, 3, 2000, 'Drift initialization')
this.isInitialized = true
console.log('✅ Drift service initialized successfully')
logger.log('✅ Drift service initialized successfully')
// CRITICAL FIX (Nov 25, 2025): Intercept errors BEFORE starting monitor
// Without this, errors aren't recorded and auto-restart never triggers
console.log('🔧 Setting up error interception for health monitoring...')
logger.log('🔧 Setting up error interception for health monitoring...')
this.interceptWebSocketErrors()
console.log('✅ Error interception active')
logger.log('✅ Error interception active')
// Start health monitoring (error-based restart instead of blind timer)
const monitor = getDriftHealthMonitor()
@@ -427,7 +428,7 @@ export class DriftService {
async disconnect(): Promise<void> {
if (this.driftClient) {
await this.driftClient.unsubscribe()
console.log('✅ Drift client disconnected')
logger.log('✅ Drift client disconnected')
}
this.isInitialized = false
}
@@ -460,9 +461,9 @@ export function getDriftService(): DriftService {
}
driftServiceInstance = new DriftService(config)
console.log('🔄 Created new Drift service singleton')
logger.log('🔄 Created new Drift service singleton')
} else {
console.log('♻️ Reusing existing Drift service instance')
logger.log('♻️ Reusing existing Drift service instance')
}
return driftServiceInstance
@@ -471,7 +472,7 @@ export function getDriftService(): DriftService {
export async function initializeDriftService(): Promise<DriftService> {
// If already initializing, return the same promise to avoid multiple concurrent inits
if (initializationPromise) {
console.log('⏳ Waiting for ongoing initialization...')
logger.log('⏳ Waiting for ongoing initialization...')
return initializationPromise
}
@@ -479,7 +480,7 @@ export async function initializeDriftService(): Promise<DriftService> {
// If already initialized, return immediately
if (service['isInitialized']) {
console.log('✅ Drift service already initialized')
logger.log('✅ Drift service already initialized')
return service
}