diff --git a/src/cli/driver.ts b/src/cli/driver.ts index 6f68a9d..758db0b 100644 --- a/src/cli/driver.ts +++ b/src/cli/driver.ts @@ -679,19 +679,19 @@ export class Driver { */ private async checkCU(cu: CompilationUnit): Promise { const warningsPromises = this.detectors.map(async (detector) => { + const taskId = `${cu.projectName}-${detector.id}-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`; if (!this.ctx.souffleAvailable && detector.usesSouffle) { this.ctx.logger.debug( `${cu.projectName}: Skipping ${detector.id} since no Soufflé installation is available`, + taskId, ); return []; } - this.ctx.logger.debug( - `${cu.projectName}: Running ${detector.id} for ${cu.projectName}`, - ); + this.ctx.logger.setContext(taskId, `${detector.id}:${cu.projectName}`); + this.ctx.logger.debug(`Running detector for ${cu.projectName}`, taskId); try { // Conditional import for setTimeout to support both Node.js and browser environments let setTimeoutPromise: (ms: number, value?: any) => Promise; - if (typeof window !== "undefined") { setTimeoutPromise = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); @@ -706,7 +706,8 @@ export class Driver { ); }), ]); - this.ctx.logger.debug(`${cu.projectName}: Finished ${detector.id}`); + this.ctx.logger.debug(`Finished detector`, taskId); + this.ctx.logger.clearContext(taskId); return warnings; } catch (err) { let error: string = ""; @@ -723,9 +724,8 @@ export class Driver { } else { error = `${err}`; } - this.ctx.logger.error( - `${cu.projectName}: Error in ${detector.id}: ${error}`, - ); + this.ctx.logger.error(`Error in detector: ${error}`, taskId); + this.ctx.logger.clearContext(taskId); return []; } }); diff --git a/src/internals/logger.ts b/src/internals/logger.ts index bfbd1d2..1509c6c 100644 --- a/src/internals/logger.ts +++ b/src/internals/logger.ts @@ -17,6 +17,7 @@ export type LogFunction = (message: string) => void; export class Logger { private logFunctions: Map; private jsonLogs: Map; + private contextMap: Map = new Map(); constructor( logMapping?: Partial>, @@ -71,30 +72,86 @@ export class Logger { }; } + /** + * Sets the context for a specific task ID. + * @param taskId Unique identifier for the current task/thread + * @param context The context string to prepend to log messages. + */ + public setContext(taskId: string, context: string): void { + this.contextMap.set(taskId, context); + } + + /** + * Clears the context for a specific task ID. + * @param taskId Unique identifier for the current task/thread + */ + public clearContext(taskId: string): void { + this.contextMap.delete(taskId); + } + /** * Logs a message at the specified log level if a corresponding log function is defined. * @param level The severity level of the log entry. * @param msg The content of the log message. - * @param ref An optional source location. + * @param taskId Optional task identifier to retrieve the correct context */ - protected log(level: LogLevel, msg: MessageType): void { + protected log(level: LogLevel, msg: MessageType, taskId?: string): void { const logFunction = this.logFunctions.get(level); if (logFunction) { - logFunction(`${msg}`); + let contextPrefix = ""; + if (taskId && this.contextMap.has(taskId)) { + contextPrefix = `[${this.contextMap.get(taskId)}] `; + } + logFunction(`${contextPrefix}${msg}`); } } - debug(msg: MessageType): void { - this.log(LogLevel.DEBUG, msg); + /** + * Logs a debug message. + * @param msg The debug message to log. + * @param taskId Optional task identifier to retrieve the correct context + */ + public debug(msg: MessageType, taskId?: string): void { + this.log(LogLevel.DEBUG, msg, taskId); + if (this.saveJson) { + this.jsonLogs.get(LogLevel.DEBUG)!.push(msg.toString()); + } } - info(msg: MessageType): void { - this.log(LogLevel.INFO, msg); + + /** + * Logs an info message. + * @param msg The info message to log. + * @param taskId Optional task identifier to retrieve the correct context + */ + public info(msg: MessageType, taskId?: string): void { + this.log(LogLevel.INFO, msg, taskId); + if (this.saveJson) { + this.jsonLogs.get(LogLevel.INFO)!.push(msg.toString()); + } } - warn(msg: MessageType): void { - this.log(LogLevel.WARN, msg); + + /** + * Logs a warning message. + * @param msg The warning message to log. + * @param taskId Optional task identifier to retrieve the correct context + */ + public warn(msg: MessageType, taskId?: string): void { + this.log(LogLevel.WARN, msg, taskId); + if (this.saveJson) { + this.jsonLogs.get(LogLevel.WARN)!.push(msg.toString()); + } } - error(msg: MessageType): void { - this.log(LogLevel.ERROR, msg); + + /** + * Logs an error message. + * @param msg The error message to log. + * @param taskId Optional task identifier to retrieve the correct context + */ + public error(msg: MessageType, taskId?: string): void { + this.log(LogLevel.ERROR, msg, taskId); + if (this.saveJson) { + this.jsonLogs.get(LogLevel.ERROR)!.push(msg.toString()); + } } }