UNPKG

@rollercoaster-dev/rd-logger

Version:

A neurodivergent-friendly logger for Rollercoaster.dev projects

128 lines (127 loc) 4.57 kB
export const DEFAULT_QUERY_LOGGER_CONFIG = { enabled: process.env.NODE_ENV !== 'production', // Enable by default in non-prod slowQueryThreshold: 100, // Default slow query threshold (ms) maxLogs: 1000, // Default max logs to store logDebugQueries: process.env.DEBUG_QUERIES === 'true', // Log all queries if DEBUG_QUERIES is set }; /** * Logs database queries and identifies slow ones. */ export class QueryLogger { constructor(logger, options) { this.logs = []; this.logger = logger; this.config = Object.assign(Object.assign({}, DEFAULT_QUERY_LOGGER_CONFIG), options); } /** * Logs a query execution. * @param query The SQL query string. * @param params Query parameters (optional). * @param duration Query execution duration in milliseconds. * @param database Optional database type/name. * @param requestId Optional associated request ID. */ logQuery(query, params, duration, database, requestId) { if (!this.config.enabled) return; const entry = { query, params, duration, timestamp: new Date().toISOString(), database, requestId, }; // Add to logs (with size limit) this.logs.push(entry); if (this.logs.length > this.config.maxLogs) { this.logs.shift(); // Remove oldest entry } const context = { duration: `${duration}ms`, query, params: params, // Let the main logger handle stringification database, requestId, }; // Log slow queries if (duration >= this.config.slowQueryThreshold) { this.logger.warn(`Slow query detected`, context); } // Log all queries if debug logging for queries is enabled if (this.config.logDebugQueries) { this.logger.debug(`Database query executed`, context); } } /** * Gets all logged queries. * @returns Array of query log entries. */ getLogs() { return [...this.logs]; // Return a copy } /** * Gets slow queries (queries that took longer than the configured threshold). * @param threshold Optional custom threshold in milliseconds to override config for this call. * @returns Array of slow query log entries. */ getSlowQueries(threshold) { const actualThreshold = threshold !== null && threshold !== void 0 ? threshold : this.config.slowQueryThreshold; return this.logs.filter((log) => log.duration >= actualThreshold); } /** * Clears all stored logs. */ clearLogs() { this.logs = []; } /** * Updates the query logger's configuration dynamically. * @param options Partial configuration options to update. */ configure(options) { this.config = Object.assign(Object.assign({}, this.config), options); } /** * Gets query statistics. */ getStats() { if (this.logs.length === 0) { return { totalQueries: 0, slowQueries: 0, averageDuration: 0, maxDuration: 0, byDatabase: {}, }; } const totalDuration = this.logs.reduce((sum, log) => sum + log.duration, 0); const maxDuration = Math.max(...this.logs.map((log) => log.duration)); const slowQueriesCount = this.logs.filter((log) => log.duration >= this.config.slowQueryThreshold).length; // Group by database const byDatabase = {}; for (const log of this.logs) { const dbKey = log.database || 'unknown'; if (!byDatabase[dbKey]) { byDatabase[dbKey] = { count: 0, totalDuration: 0 }; } byDatabase[dbKey].count++; byDatabase[dbKey].totalDuration += log.duration; } // Calculate average duration by database const byDatabaseStats = {}; for (const [db, stats] of Object.entries(byDatabase)) { byDatabaseStats[db] = { count: stats.count, avgDuration: stats.totalDuration > 0 ? stats.totalDuration / stats.count : 0, }; } return { totalQueries: this.logs.length, slowQueries: slowQueriesCount, averageDuration: totalDuration > 0 ? totalDuration / this.logs.length : 0, maxDuration, byDatabase: byDatabaseStats, }; } }