UNPKG

@bernierllc/logging

Version:

A comprehensive logging package with Winston integration for audit and system logging

385 lines (384 loc) 14.4 kB
"use strict"; /* Copyright (c) 2025 Bernier LLC This file is licensed to the client under a limited-use license. The client may use and modify this code *only within the scope of the project it was delivered for*. Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.ServiceLoggingConfigurationLoader = exports.DEFAULT_LOGGING_SERVICE_CONFIG = void 0; exports.loadServiceLoggingConfiguration = loadServiceLoggingConfiguration; exports.loadServiceLoggingConfigurationWithSources = loadServiceLoggingConfigurationWithSources; const cosmiconfig_1 = require("cosmiconfig"); const coreLogger_1 = require("../mocks/coreLogger"); /** * Default configuration values for the logging service */ exports.DEFAULT_LOGGING_SERVICE_CONFIG = { level: coreLogger_1.LogLevel.INFO, enableCorrelation: true, sanitize: true, sanitizeFields: [ "password", "token", "secret", "key", "authorization", "cookie", "apiKey", "accessToken", "refreshToken", "creditCard", "ssn", "socialSecurityNumber", "sessionId", "jwt", "bearer" ], context: { service: 'service-logging', version: process.env.npm_package_version || '0.1.12', environment: process.env.NODE_ENV || 'development', hostname: process.env.HOSTNAME || process.env.HOST || 'localhost', pid: process.pid, thread: undefined }, system: { enabled: true, level: coreLogger_1.LogLevel.INFO, console: { enabled: process.env.NODE_ENV !== 'production', level: coreLogger_1.LogLevel.DEBUG, formatter: 'text', formatterOptions: { prettyPrint: false, colorize: true, includeTimestamp: true, includeHostname: false } }, file: { enabled: process.env.NODE_ENV === 'production', filename: 'logs/system.log', level: coreLogger_1.LogLevel.INFO, formatter: 'json', maxSize: 10 * 1024 * 1024, // 10MB maxFiles: 5, createDir: true, formatterOptions: { prettyPrint: false, includeTimestamp: true, includeHostname: true } } }, audit: { enabled: true, level: coreLogger_1.LogLevel.INFO, console: { enabled: false, level: coreLogger_1.LogLevel.INFO, formatter: 'json', formatterOptions: { prettyPrint: false, colorize: false, includeTimestamp: true, includeHostname: true } }, file: { enabled: true, filename: 'logs/audit.log', level: coreLogger_1.LogLevel.INFO, formatter: 'json', maxSize: 50 * 1024 * 1024, // 50MB maxFiles: 10, createDir: true, formatterOptions: { prettyPrint: false, includeTimestamp: true, includeHostname: true } } }, errorHandling: { enableCallback: false, logFailures: true } }; /** * Environment variable mappings for the logging service */ const ENV_MAPPINGS = { // Global settings level: 'LOGGING_SERVICE_LEVEL', enableCorrelation: 'LOGGING_SERVICE_ENABLE_CORRELATION', sanitize: 'LOGGING_SERVICE_SANITIZE', // Context settings 'context.service': 'LOGGING_SERVICE_NAME', 'context.version': 'LOGGING_SERVICE_VERSION', 'context.environment': 'NODE_ENV', 'context.hostname': 'HOSTNAME', 'context.thread': 'LOGGING_SERVICE_THREAD', // System logging settings 'system.enabled': 'LOGGING_SERVICE_SYSTEM_ENABLED', 'system.level': 'LOGGING_SERVICE_SYSTEM_LEVEL', 'system.console.enabled': 'LOGGING_SERVICE_SYSTEM_CONSOLE_ENABLED', 'system.console.level': 'LOGGING_SERVICE_SYSTEM_CONSOLE_LEVEL', 'system.console.formatter': 'LOGGING_SERVICE_SYSTEM_CONSOLE_FORMATTER', 'system.file.enabled': 'LOGGING_SERVICE_SYSTEM_FILE_ENABLED', 'system.file.filename': 'LOGGING_SERVICE_SYSTEM_FILE_FILENAME', 'system.file.level': 'LOGGING_SERVICE_SYSTEM_FILE_LEVEL', 'system.file.formatter': 'LOGGING_SERVICE_SYSTEM_FILE_FORMATTER', 'system.file.maxSize': 'LOGGING_SERVICE_SYSTEM_FILE_MAX_SIZE', 'system.file.maxFiles': 'LOGGING_SERVICE_SYSTEM_FILE_MAX_FILES', 'system.http.enabled': 'LOGGING_SERVICE_SYSTEM_HTTP_ENABLED', 'system.http.url': 'LOGGING_SERVICE_SYSTEM_HTTP_URL', 'system.http.level': 'LOGGING_SERVICE_SYSTEM_HTTP_LEVEL', // Audit logging settings 'audit.enabled': 'LOGGING_SERVICE_AUDIT_ENABLED', 'audit.level': 'LOGGING_SERVICE_AUDIT_LEVEL', 'audit.console.enabled': 'LOGGING_SERVICE_AUDIT_CONSOLE_ENABLED', 'audit.console.level': 'LOGGING_SERVICE_AUDIT_CONSOLE_LEVEL', 'audit.console.formatter': 'LOGGING_SERVICE_AUDIT_CONSOLE_FORMATTER', 'audit.file.enabled': 'LOGGING_SERVICE_AUDIT_FILE_ENABLED', 'audit.file.filename': 'LOGGING_SERVICE_AUDIT_FILE_FILENAME', 'audit.file.level': 'LOGGING_SERVICE_AUDIT_FILE_LEVEL', 'audit.file.formatter': 'LOGGING_SERVICE_AUDIT_FILE_FORMATTER', 'audit.file.maxSize': 'LOGGING_SERVICE_AUDIT_FILE_MAX_SIZE', 'audit.file.maxFiles': 'LOGGING_SERVICE_AUDIT_FILE_MAX_FILES', 'audit.database.enabled': 'LOGGING_SERVICE_AUDIT_DATABASE_ENABLED', 'audit.database.connectionString': 'LOGGING_SERVICE_AUDIT_DATABASE_CONNECTION_STRING', 'audit.database.tableName': 'LOGGING_SERVICE_AUDIT_DATABASE_TABLE_NAME', 'audit.database.level': 'LOGGING_SERVICE_AUDIT_DATABASE_LEVEL', // Error handling settings 'errorHandling.enableCallback': 'LOGGING_SERVICE_ERROR_HANDLING_ENABLE_CALLBACK', 'errorHandling.logFailures': 'LOGGING_SERVICE_ERROR_HANDLING_LOG_FAILURES' }; /** * Configuration loader with source tracking */ class ServiceLoggingConfigurationLoader { sources = []; coreLoggerConfig = null; /** * Load core logger configuration to be overridden by service config */ setCoreLoggerConfiguration(coreConfig) { this.coreLoggerConfig = coreConfig; if (coreConfig) { this.sources.push({ key: 'core-dependency', value: coreConfig, source: 'core-dependency', description: 'Configuration from @bernierllc/logger core package' }); } } /** * Parse environment variable value to appropriate type */ parseEnvironmentValue(value) { // Boolean values if (value === 'true') return true; if (value === 'false') return false; // Number values if (/^\d+$/.test(value)) return parseInt(value); if (/^\d+\.\d+$/.test(value)) return parseFloat(value); // Size values (e.g., "10m", "100k") if (/^\d+[kmg]$/i.test(value)) { return this.parseSizeToBytes(value); } // Array values (comma-separated) if (value.includes(',')) { return value.split(',').map(item => item.trim()); } return value; } /** * Parse size string to bytes */ parseSizeToBytes(size) { const units = { 'k': 1024, 'm': 1024 * 1024, 'g': 1024 * 1024 * 1024 }; const match = size.toLowerCase().match(/^(\d+)([kmg])$/); if (!match) return parseInt(size); const value = parseInt(match[1]); const unit = match[2]; return value * (units[unit] || 1); } /** * Set nested object value using dot notation */ setNestedValue(obj, path, value) { const keys = path.split('.'); let current = obj; for (let i = 0; i < keys.length - 1; i++) { const key = keys[i]; if (!(key in current)) { current[key] = {}; } current = current[key]; } current[keys[keys.length - 1]] = value; } /** * Load and resolve configuration from all sources */ loadConfiguration() { const resolvedConfig = JSON.parse(JSON.stringify(exports.DEFAULT_LOGGING_SERVICE_CONFIG)); // Track default configuration source this.sources.push({ key: 'defaults', value: exports.DEFAULT_LOGGING_SERVICE_CONFIG, source: 'default', description: 'Package default configuration' }); // Load configuration file if it exists const explorer = (0, cosmiconfig_1.cosmiconfigSync)('logging-service', { searchPlaces: [ 'logging-service.config.js', 'logging-service.config.json', '.logging-servicerc', '.logging-servicerc.js', '.logging-servicerc.json' ] }); try { const result = explorer.search(); if (result && result.config) { this.mergeConfiguration(resolvedConfig, result.config); this.sources.push({ key: 'file', value: result.config, source: 'file', description: `Configuration file: ${result.filepath}` }); } } catch (error) { console.warn('Failed to load logging service configuration file:', error); } // Apply core logger configuration overrides if (this.coreLoggerConfig) { this.applyCoreLoggerOverrides(resolvedConfig); } // Apply environment variable overrides this.applyEnvironmentOverrides(resolvedConfig); // Log configuration sources for transparency if (this.sources.length > 1) { console.log('⚙️ Logging Service: Configuration loaded from multiple sources'); this.sources.forEach(source => { if (source.source !== 'default') { console.log(` └── ${source.source}: ${source.description}`); } }); } return resolvedConfig; } /** * Apply core logger configuration as base overrides */ applyCoreLoggerOverrides(config) { if (!this.coreLoggerConfig) return; const coreConfig = this.coreLoggerConfig; // Override level if core logger has different level if (coreConfig.level && coreConfig.level !== config.level) { config.level = coreConfig.level; } // Override context from core logger if (coreConfig.context) { config.context = { ...config.context, ...coreConfig.context }; } // Override transports configuration from core logger if (coreConfig.transports) { if (coreConfig.transports.console) { config.system.console = { ...config.system.console, ...coreConfig.transports.console }; } if (coreConfig.transports.file) { config.system.file = { ...config.system.file, ...coreConfig.transports.file }; } } // Override sanitization settings if (coreConfig.sanitize !== undefined) { config.sanitize = coreConfig.sanitize; } if (coreConfig.sanitizeFields) { config.sanitizeFields = [...new Set([...config.sanitizeFields, ...coreConfig.sanitizeFields])]; } } /** * Apply environment variable overrides */ applyEnvironmentOverrides(config) { const envOverrides = []; Object.entries(ENV_MAPPINGS).forEach(([configPath, envVar]) => { const envValue = process.env[envVar]; if (envValue !== undefined) { const parsedValue = this.parseEnvironmentValue(envValue); this.setNestedValue(config, configPath, parsedValue); envOverrides.push({ key: configPath, value: parsedValue, source: 'environment', description: `Environment variable: ${envVar}=${envValue}` }); } }); if (envOverrides.length > 0) { this.sources.push(...envOverrides); } } /** * Merge configuration objects recursively */ mergeConfiguration(target, source) { Object.keys(source).forEach(key => { if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) { if (!target[key]) target[key] = {}; this.mergeConfiguration(target[key], source[key]); } else { target[key] = source[key]; } }); } /** * Get configuration sources for transparency */ getConfigurationSources() { return [...this.sources]; } /** * Get environment variable documentation */ getEnvironmentVariableDocumentation() { const docs = {}; Object.entries(ENV_MAPPINGS).forEach(([configPath, envVar]) => { docs[envVar] = `Controls ${configPath} configuration`; }); return docs; } } exports.ServiceLoggingConfigurationLoader = ServiceLoggingConfigurationLoader; /** * Load service logging configuration with core logger inheritance */ function loadServiceLoggingConfiguration(coreLoggerConfig) { const loader = new ServiceLoggingConfigurationLoader(); if (coreLoggerConfig) { loader.setCoreLoggerConfiguration(coreLoggerConfig); } return loader.loadConfiguration(); } /** * Load configuration with source tracking */ function loadServiceLoggingConfigurationWithSources(coreLoggerConfig) { const loader = new ServiceLoggingConfigurationLoader(); if (coreLoggerConfig) { loader.setCoreLoggerConfiguration(coreLoggerConfig); } const config = loader.loadConfiguration(); const sources = loader.getConfigurationSources(); return { config, sources }; } //# sourceMappingURL=loadConfiguration.js.map