navidocs/server/utils/logger.js
ggq-admin e4b1f73a46 Add comprehensive logging system with colored output
- Created centralized logger utility with log levels
- Added request logging middleware with timing
- Integrated structured logging throughout server:
  * Colored, timestamped output for better readability
  * HTTP request/response logging with duration
  * Context-specific loggers (Upload, OCR, Search, etc.)
  * Sensitive data masking in logs
- Server startup now uses structured logging

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 01:57:56 +02:00

108 lines
2.8 KiB
JavaScript

/**
* Centralized Logging Utility
* Provides consistent logging with timestamps and context
*/
const LOG_LEVELS = {
ERROR: 'ERROR',
WARN: 'WARN',
INFO: 'INFO',
DEBUG: 'DEBUG',
};
const COLORS = {
ERROR: '\x1b[31m', // Red
WARN: '\x1b[33m', // Yellow
INFO: '\x1b[36m', // Cyan
DEBUG: '\x1b[90m', // Gray
RESET: '\x1b[0m',
BOLD: '\x1b[1m',
};
class Logger {
constructor(context = 'App') {
this.context = context;
this.logLevel = process.env.LOG_LEVEL || 'INFO';
}
shouldLog(level) {
const levels = Object.keys(LOG_LEVELS);
const currentLevelIndex = levels.indexOf(this.logLevel);
const requestedLevelIndex = levels.indexOf(level);
return requestedLevelIndex <= currentLevelIndex;
}
formatMessage(level, message, data = null) {
const timestamp = new Date().toISOString();
const color = COLORS[level] || '';
const reset = COLORS.RESET;
const bold = COLORS.BOLD;
let formattedMessage = `${color}${bold}[${timestamp}] [${level}] [${this.context}]${reset}${color} ${message}${reset}`;
if (data) {
formattedMessage += `\n${color}${JSON.stringify(data, null, 2)}${reset}`;
}
return formattedMessage;
}
error(message, error = null) {
if (!this.shouldLog('ERROR')) return;
const data = error ? {
message: error.message,
stack: error.stack,
...error,
} : null;
console.error(this.formatMessage('ERROR', message, data));
}
warn(message, data = null) {
if (!this.shouldLog('WARN')) return;
console.warn(this.formatMessage('WARN', message, data));
}
info(message, data = null) {
if (!this.shouldLog('INFO')) return;
console.log(this.formatMessage('INFO', message, data));
}
debug(message, data = null) {
if (!this.shouldLog('DEBUG')) return;
console.log(this.formatMessage('DEBUG', message, data));
}
// Convenience method for HTTP requests
http(method, path, statusCode, duration = null) {
const durationStr = duration ? ` (${duration}ms)` : '';
const statusColor = statusCode >= 400 ? COLORS.ERROR : statusCode >= 300 ? COLORS.WARN : COLORS.INFO;
const message = `${statusColor}${method} ${path} ${statusCode}${durationStr}${COLORS.RESET}`;
if (this.shouldLog('INFO')) {
console.log(this.formatMessage('INFO', message));
}
}
// Create a child logger with additional context
child(additionalContext) {
return new Logger(`${this.context}:${additionalContext}`);
}
}
// Create default logger instance
const logger = new Logger();
// Create context-specific loggers
const loggers = {
app: logger,
upload: logger.child('Upload'),
ocr: logger.child('OCR'),
search: logger.child('Search'),
db: logger.child('Database'),
meilisearch: logger.child('Meilisearch'),
};
export default logger;
export { Logger, loggers };