import * as plugins from './smartlog.plugins.js'; import { LogRouter } from './smartlog.classes.logrouter.js'; import { LogGroup } from './smartlog.classes.loggroup.js'; export interface ISmartlogContructorOptions { logContext: plugins.smartlogInterfaces.ILogContext; minimumLogLevel?: plugins.smartlogInterfaces.TLogLevel; } export class Smartlog implements plugins.smartlogInterfaces.ILogDestination { // STATIC public static createForCommitinfo(commitinfo: plugins.smartlogInterfaces.ILogContext['commitinfo']) { return new Smartlog({ logContext: { commitinfo }, }); } // INSTANCE public logContext: plugins.smartlogInterfaces.ILogContext; public minimumLogLevel: plugins.smartlogInterfaces.TLogLevel; public uniInstanceId: string = plugins.isounique.uni(); private consoleEnabled: boolean; private logRouter = new LogRouter(); public addLogDestination(logDestinationArg: plugins.smartlogInterfaces.ILogDestination) { this.logRouter.addLogDestination(logDestinationArg); } constructor(optionsArg: ISmartlogContructorOptions) { this.logContext = optionsArg.logContext; this.minimumLogLevel = optionsArg.minimumLogLevel || 'silly'; } // ============ // Logger Setup // ============ /** * enables console logging */ public enableConsole(optionsArg?: { captureAll: boolean }) { if (globalThis.process && optionsArg && optionsArg.captureAll) { const process = globalThis.process; const originalStdoutWrite = process.stdout.write.bind(process.stdout); const originalStderrWrite = process.stderr.write.bind(process.stderr); process.stdout.write = (...args: any) => { const logString: string = args[0]; if (!logString || typeof logString !== 'string') { // continue as planned return originalStdoutWrite(...args); } if (!logString.startsWith('LOG')) { if (logString.includes('Error:')) { this.log('error', logString); } else { this.log('info', logString); } return true; } return originalStdoutWrite(...args); }; process.stderr.write = (...args: any) => { const logString: string = args[0]; if (!logString || typeof logString !== 'string' || !logString.startsWith('LOG')) { this.log('error', logString); return true; } return originalStderrWrite(...args); }; } this.consoleEnabled = true; } // ============= // log functions // ============= /** * main log method * @param logLevelArg - the log level * @param logMessageArg - the log message * @param logDataArg - any additional log data * @param correlationArg - info about corrleations */ public async log( logLevelArg: plugins.smartlogInterfaces.TLogLevel, logMessageArg: string, logDataArg?: any, correlationArg?: plugins.smartlogInterfaces.ILogCorrelation ) { correlationArg = { ...{ id: plugins.isounique.uni(), type: 'none', instance: this.uniInstanceId, }, ...correlationArg, }; if (this.consoleEnabled) { this.safeConsoleLog(`${logLevelArg}: ${logMessageArg}`); } const logPackage: plugins.smartlogInterfaces.ILogPackage = { timestamp: Date.now(), type: 'log', context: this.logContext, level: logLevelArg, correlation: correlationArg, message: logMessageArg, }; if (logDataArg) { logPackage.data = logDataArg; } await this.logRouter.routeLog(logPackage); } public increment( logLevelArg: plugins.smartlogInterfaces.TLogLevel, logMessageArg: string, logDataArg?: any, correlationArg: plugins.smartlogInterfaces.ILogCorrelation = { id: plugins.isounique.uni(), type: 'none', } ) { if (this.consoleEnabled) { this.safeConsoleLog(`INCREMENT: ${logLevelArg}: ${logMessageArg}`); } this.logRouter.routeLog({ timestamp: Date.now(), type: 'increment', context: this.logContext, level: logLevelArg, message: logMessageArg, correlation: correlationArg, }); } public async handleLog(logPackageArg: plugins.smartlogInterfaces.ILogPackage) { await this.logRouter.routeLog(logPackageArg); } private safeConsoleLog(logLine: string) { console.log( `LOG => ${new Date().getHours()}:${new Date().getMinutes()}:${new Date().getSeconds()} => ${logLine}` ); } public createLogGroup(transactionId: string = 'none') { return new LogGroup(this, transactionId); } }