UNPKG

sfcoe-ailabs

Version:

AI-powered code review tool with static analysis integration for comprehensive code quality assessment.

220 lines (219 loc) 7.16 kB
import winston from 'winston'; import DatadogWinston from 'datadog-winston'; import * as console from 'node:console'; import { DATADOG_DEFAULT_CONSTANTS } from '../../utils/constants.js'; /** * Datadog Winston logger configuration and setup */ export class DatadogLogger { static instance = null; static config = null; /** * Initialize the Datadog logger with configuration * * @param config - The Datadog logger configuration object * @returns The initialized Winston logger instance */ static initialize(config) { if (this.instance) { return this.instance; } this.config = config; const transports = [ // Console transport for local development new winston.transports.Console({ format: winston.format.combine(winston.format.timestamp({ format: DATADOG_DEFAULT_CONSTANTS.timestampFormat, }), winston.format.colorize(), winston.format.printf(({ timestamp, level, message, ...meta }) => `${String(timestamp)} [${String(level)}]: ${String(message)} ${Object.keys(meta).length ? JSON.stringify(meta) : ''}`)), }), ]; // Add Datadog HTTP transport if API key is provided if (config.apiKey) { try { const datadogTransport = new DatadogWinston({ apiKey: config.apiKey, ddsource: config.ddsource, hostname: config.hostname, service: config.service, ddtags: config.environment ? `env:${config.environment}` : undefined, level: config.logLevel, }); transports.push(datadogTransport); } catch (error) { console.warn(`Failed to initialize Datadog HTTP transport: ${JSON.stringify(error)}. Continuing with console logging only.`); } } else { console.warn('No Datadog API key provided - using console logging only'); } this.instance = winston.createLogger({ level: config.logLevel, format: winston.format.combine(winston.format.timestamp({ format: DATADOG_DEFAULT_CONSTANTS.timestampFormat, }), winston.format.errors({ stack: true }), winston.format.json()), defaultMeta: { service: config.service, environment: config.environment, ...config.customMeta, // Include custom metadata }, transports, }); this.instance.info('Datadog logging initialized'); return this.instance; } /** * Get the configured logger instance * * @returns The Winston logger instance * @throws Error if logger is not initialized */ static getInstance() { if (!this.instance) { throw new Error('DatadogLogger not initialized. Call initialize() first.'); } return this.instance; } /** * Check if logger is initialized * * @returns True if the logger is initialized, false otherwise */ static isInitialized() { return this.instance !== null; } /** * Get current configuration * * @returns The current Datadog logger configuration or null if not set */ static getConfig() { return this.config; } /** * Log debug message * * @param message - The debug message to log * @param meta - Optional metadata object to include with the log */ static debug(message, meta) { if (this.instance) { this.instance.debug(message, meta); } else { console.debug(`[DEBUG]: ${message}`, meta ? JSON.stringify(meta) : ''); } } /** * Log info message * * @param message - The info message to log * @param meta - Optional metadata object to include with the log */ static info(message, meta) { if (this.instance) { this.instance.info(message, meta); } else { console.info(`[INFO]: ${message}`, meta ? JSON.stringify(meta) : ''); } } /** * Log warning message * * @param message - The warning message to log * @param meta - Optional metadata object to include with the log */ static warn(message, meta) { if (this.instance) { this.instance.warn(message, meta); } else { console.warn(`[WARN]: ${message}`, meta ? JSON.stringify(meta) : ''); } } /** * Log error message * * @param message - The error message to log * @param error - Optional error object or metadata to include with the log */ static error(message, error) { if (this.instance) { if (error instanceof Error) { this.instance.error(message, { error: error.message, stack: error.stack, }); } else { this.instance.error(message, error); } } else { console.error(`[ERROR]: ${message}`, error); } } /** * Log with custom level * * @param level - The log level (e.g., 'info', 'debug', 'error') * @param message - The message to log * @param meta - Optional metadata object to include with the log */ static log(level, message, meta) { if (this.instance) { this.instance.log(level, message, meta); } else { console.log(`[${level.toUpperCase()}]: ${message}`, meta ? JSON.stringify(meta) : ''); } } /** * Update custom metadata that will be included in all future logs * * @param meta - The metadata object to merge with existing custom metadata */ static updateCustomMeta(meta) { if (this.config) { this.config.customMeta = { ...this.config.customMeta, ...meta }; // Update the logger instance's defaultMeta if it exists if (this.instance) { this.instance.defaultMeta = { ...this.instance.defaultMeta, ...meta, }; } } } /** * Set a specific metadata field * * @param key - The metadata field key * @param value - The value to set for the metadata field */ static setMetaField(key, value) { this.updateCustomMeta({ [key]: value }); } /** * Remove a metadata field * * @param key - The metadata field key to remove */ static removeMetaField(key) { if (this.config?.customMeta) { delete this.config.customMeta[key]; } if (this.instance?.defaultMeta) { delete this.instance.defaultMeta[key]; } } /** * Get current custom metadata * * @returns The current custom metadata object */ static getCustomMeta() { return this.config?.customMeta ?? {}; } }