DEV Community

Ramu Narasinga
Ramu Narasinga

Posted on

Logger in Claude-Mem codebase.

In this article, we review logger in Claude-Mem codebase. We will look at:

  1. What is Claude-Mem?

  2. logger.ts file

  3. Usage

What is Claude-Mem?

Claude-Mem is a Claude Code plugin that automatically captures everything Claude does during your coding sessions, compresses it with AI (using Claude’s agent-sdk), and injects relevant context back into future sessions.

Claude-Mem is your AI’s trusty note-taking sidekick. Never lose track ever again.

Learn more about Claude-Mem.

logger.ts file

I try to write atleast one article related to how an OSS codebase handles logs. So the common pattern is to define your logging related functions in a file and reuse them across your codebase. Gives you the flexibility of applying colors, modifying message etc.,

With that said, Claude-Mem has this file, src/utils/logger.ts. There is one core method:

/**
 * Core logging method
 */
private log(
  level: LogLevel,
  component: Component,
  message: string,
  context?: LogContext,
  data?: any
): void {
  if (level < this.getLevel()) return;

  // Lazy initialize log file on first use
  this.ensureLogFileInitialized();

  const timestamp = this.formatTimestamp(new Date());
  const levelStr = LogLevel[level].padEnd(5);
  const componentStr = component.padEnd(6);

  // Build correlation ID part
  let correlationStr = '';
  if (context?.correlationId) {
    correlationStr = `[${context.correlationId}] `;
  } else if (context?.sessionId) {
    correlationStr = `[session-${context.sessionId}] `;
  }

  // Build data part
  let dataStr = '';
  if (data !== undefined && data !== null) {
    // Handle Error objects specially - they don't JSON.stringify properly
    if (data instanceof Error) {
      dataStr = this.getLevel() === LogLevel.DEBUG
        ? `\n${data.message}\n${data.stack}`
        : ` ${data.message}`;
    } else if (this.getLevel() === LogLevel.DEBUG && typeof data === 'object') {
      // In debug mode, show full JSON for objects
      dataStr = '\n' + JSON.stringify(data, null, 2);
    } else {
      dataStr = ' ' + this.formatData(data);
    }
  }

  // Build additional context
  let contextStr = '';
  if (context) {
    const { sessionId, memorySessionId, correlationId, ...rest } = context;
    if (Object.keys(rest).length > 0) {
      const pairs = Object.entries(rest).map(([k, v]) => `${k}=${v}`);
      contextStr = ` {${pairs.join(', ')}}`;
    }
  }

  const logLine = `[${timestamp}] [${levelStr}] [${componentStr}] ${correlationStr}${message}${contextStr}${dataStr}`;

  // Output to log file ONLY (worker runs in background, console is useless)
  if (this.logFilePath) {
    try {
      appendFileSync(this.logFilePath, logLine + '\n', 'utf8');
    } catch (error) {
      // Logger can't log its own failures - use stderr as last resort
      // This is expected during disk full / permission errors
      process.stderr.write(`[LOGGER] Failed to write to log file: ${error}\n`);
    }
  } else {
    // If no log file available, write to stderr as fallback
    process.stderr.write(logLine + '\n');
  }
}
Enter fullscreen mode Exit fullscreen mode

So this core log method actually write the logs to a file. They also justify why with a comment:

// Output to log file ONLY (worker runs in background, console is useless)
Enter fullscreen mode Exit fullscreen mode

and with a fallback else block to write to stderr.

and there is public logging methods defined just under this one:

// Public logging methods
  debug(component: Component, message: string, context?: LogContext, data?: any): void {
    this.log(LogLevel.DEBUG, component, message, context, data);
  }

  info(component: Component, message: string, context?: LogContext, data?: any): void {
    this.log(LogLevel.INFO, component, message, context, data);
  }

  warn(component: Component, message: string, context?: LogContext, data?: any): void {
    this.log(LogLevel.WARN, component, message, context, data);
  }

  error(component: Component, message: string, context?: LogContext, data?: any): void {
    this.log(LogLevel.ERROR, component, message, context, data);
  }

  /**
   * Log data flow: input → processing
   */
  dataIn(component: Component, message: string, context?: LogContext, data?: any): void {
    this.info(component, `→ ${message}`, context, data);
  }

  /**
   * Log data flow: processing → output
   */
  dataOut(component: Component, message: string, context?: LogContext, data?: any): void {
    this.info(component, `← ${message}`, context, data);
  }

  /**
   * Log successful completion
   */
  success(component: Component, message: string, context?: LogContext, data?: any): void {
    this.info(component, `✓ ${message}`, context, data);
  }

  /**
   * Log failure
   */
  failure(component: Component, message: string, context?: LogContext, data?: any): void {
    this.error(component, `✗ ${message}`, context, data);
  }
Enter fullscreen mode Exit fullscreen mode

Well, there is more methods, but I chose handful to give you an idea as to how these public methods are defined.

Usage

For the usage examples, I will list some logs from the Claude-Mem codebase.

logger.error

// Log error
logger.error('HTTP', `Error handling ${req.method} ${req.path}`, {
  statusCode,
  error: err.message,
  code: err instanceof AppError ? err.code : undefined
}, err);
Enter fullscreen mode Exit fullscreen mode

logger.info

async start(): Promise<void> {
  const port = getWorkerPort();
  const host = getWorkerHost();

  // Start HTTP server FIRST - make port available immediately
  await this.server.listen(port, host);
  logger.info('SYSTEM', 'Worker started', { host, port, pid: process.pid });
Enter fullscreen mode Exit fullscreen mode

About me:

Hey, my name is Ramu Narasinga. I study codebase architecture in large open-source projects.

Email: ramu.narasinga@gmail.com

I spent 200+ hours analyzing Supabase, shadcn/ui, LobeChat. Found the patterns that separate AI slop from production code. Stop refactoring AI slop. Start with proven patterns. Check out production-grade projects at thinkthroo.com

References:

  1. thedotmack/claude-mem/blob/main/src/utils/logger.ts#L236

  2. thedotmack/claude-mem/src/services/server/ErrorHandler.ts#L64

  3. thedotmack/claude-mem/src/services/worker-service.ts#L232

Top comments (0)