@juspay/neurolink
Version:
Universal AI Development Platform with working MCP integration, multi-provider support, and professional CLI. Built-in tools operational, 58+ external MCP servers discoverable. Connect to filesystem, GitHub, database operations, and more. Build, test, and
201 lines (200 loc) • 6.52 kB
JavaScript
/**
* NeuroLink Unified Logger Utility
*
* Centralized logging for the entire NeuroLink ecosystem
* Supports both CLI --debug flag and NEUROLINK_DEBUG environment variable
* Migrated from MCP logging with enhanced features
*/
// Pre-computed uppercase log levels for performance optimization
const UPPERCASE_LOG_LEVELS = {
debug: "DEBUG",
info: "INFO",
warn: "WARN",
error: "ERROR",
};
class NeuroLinkLogger {
logLevel = "info";
logs = [];
maxLogs = 1000;
isDebugMode;
constructor() {
// Cache debug mode check to avoid repeated array searches
this.isDebugMode =
process.argv.includes("--debug") ||
process.env.NEUROLINK_DEBUG === "true";
// Check NEUROLINK_LOG_LEVEL for consistency with the unified NeuroLink logger
const envLevel = process.env.NEUROLINK_LOG_LEVEL?.toLowerCase();
if (envLevel && ["debug", "info", "warn", "error"].includes(envLevel)) {
this.logLevel = envLevel;
}
}
setLogLevel(level) {
this.logLevel = level;
}
shouldLog(level) {
// Dynamic debug mode check to handle CLI middleware timing
const currentDebugMode = process.argv.includes("--debug") ||
process.env.NEUROLINK_DEBUG === "true";
// Hide all logs except errors unless debugging
if (!currentDebugMode && level !== "error") {
return false;
}
const levels = ["debug", "info", "warn", "error"];
return levels.indexOf(level) >= levels.indexOf(this.logLevel);
}
getLogPrefix(timestamp, level) {
return `[${timestamp}] [NEUROLINK:${UPPERCASE_LOG_LEVELS[level]}]`;
}
/**
* Outputs a log entry to the console based on the log level.
*
* @param level - The log level (debug, info, warn, error).
* @param prefix - The formatted log prefix.
* @param message - The log message.
* @param data - Optional additional data to log.
*/
outputToConsole(level, prefix, message, data) {
const logMethod = {
debug: console.debug,
info: console.info,
warn: console.warn,
error: console.error,
}[level];
if (data !== undefined && data !== null) {
logMethod(prefix, message, data);
}
else {
logMethod(prefix, message);
}
}
log(level, message, data) {
if (!this.shouldLog(level)) {
return;
}
const entry = {
level,
message,
timestamp: new Date(),
data,
};
// Store log entry
this.logs.push(entry);
// Trim old logs
if (this.logs.length > this.maxLogs) {
this.logs = this.logs.slice(-this.maxLogs);
}
// Console output
const timestamp = entry.timestamp.toISOString();
const prefix = this.getLogPrefix(timestamp, level);
this.outputToConsole(level, prefix, message, data);
}
debug(message, data) {
this.log("debug", message, data);
}
info(message, data) {
this.log("info", message, data);
}
warn(message, data) {
this.log("warn", message, data);
}
error(message, data) {
this.log("error", message, data);
}
getLogs(level) {
if (level) {
return this.logs.filter((log) => log.level === level);
}
return [...this.logs];
}
clearLogs() {
this.logs = [];
}
/**
* Logs messages unconditionally using `console.log`.
*
* This method is part of a legacy simple logger interface for backward compatibility.
* It bypasses the structured logging mechanism and should only be used when
* unstructured, unconditional logging is required.
*
* @param args - The arguments to log. These are passed directly to `console.log`.
*/
always(...args) {
console.log(...args);
}
/**
* Displays tabular data unconditionally using `console.table`.
*
* @param data - The data to display in table format
*/
table(data) {
console.table(data);
}
}
// Export singleton instance
const neuroLinkLogger = new NeuroLinkLogger();
// Helper function to process arguments with minimal overhead
function processLoggerArgs(args, logMethod) {
if (args.length === 0) {
return;
}
// Serialize the first argument robustly to handle complex objects
const message = (() => {
try {
return typeof args[0] === "string" ? args[0] : JSON.stringify(args[0]);
}
catch {
return "[Unserializable Object]";
}
})();
const data = args.length === 2 ? args[1] : args.length > 2 ? args.slice(1) : undefined;
logMethod(message, data);
}
// Main unified logger export
export const logger = {
debug: (...args) => {
if (neuroLinkLogger.shouldLog("debug")) {
processLoggerArgs(args, (message, data) => neuroLinkLogger.debug(message, data));
}
},
info: (...args) => {
if (neuroLinkLogger.shouldLog("info")) {
processLoggerArgs(args, (message, data) => neuroLinkLogger.info(message, data));
}
},
warn: (...args) => {
if (neuroLinkLogger.shouldLog("warn")) {
processLoggerArgs(args, (message, data) => neuroLinkLogger.warn(message, data));
}
},
error: (...args) => {
if (neuroLinkLogger.shouldLog("error")) {
processLoggerArgs(args, (message, data) => neuroLinkLogger.error(message, data));
}
},
always: (...args) => {
neuroLinkLogger.always(...args);
},
table: (data) => {
neuroLinkLogger.table(data);
},
// Expose structured logging methods
setLogLevel: (level) => neuroLinkLogger.setLogLevel(level),
getLogs: (level) => neuroLinkLogger.getLogs(level),
clearLogs: () => neuroLinkLogger.clearLogs(),
};
// MCP compatibility exports - all use the same unified logger
export const mcpLogger = neuroLinkLogger;
export const autoDiscoveryLogger = neuroLinkLogger;
export const registryLogger = neuroLinkLogger;
export const unifiedRegistryLogger = neuroLinkLogger;
// Global log level setter
export function setGlobalMCPLogLevel(level) {
neuroLinkLogger.setLogLevel(level);
}
// Export LogLevel enum for runtime use
export const LogLevels = {
debug: "debug",
info: "info",
warn: "warn",
error: "error",
};