Understanding the Logging Mechanism in Karakeep: Winston Implementation Guide

Karakeep implements a centralized logging mechanism using a Winston singleton exported from packages/shared/logger.ts, which reads the LOG_LEVEL and LOG_NO_COLOR environment variables to configure timestamped, optionally colorized console output across the entire monorepo.

The logging mechanism in Karakeep provides a consistent, configurable approach to observability across workers, API routes, and server components. Built on the Winston library, the system uses a singleton pattern to ensure uniform log formatting while supporting both standard logging and rate-limited logging for high-frequency events.

Winston Logger Singleton Architecture

The core logging infrastructure resides in packages/shared/logger.ts. This file creates a single Winston logger instance configured with a custom format combining timestamps, optional colorization, and printf-style message formatting.

All logs route through a single Console transport, making the setup lightweight and container-friendly:

// packages/shared/logger.ts
import winston from "winston";
import serverConfig from "./config";

const logger = winston.createLogger({
  level: serverConfig.logLevel,
  format: winston.format.combine(
    winston.format.timestamp(),
    ...(serverConfig.logNoColor ? [] : [winston.format.colorize()]),
    winston.format.printf(info => `${info.timestamp} ${info.level}: ${info.message}`),
  ),
  transports: [new winston.transports.Console()],
});

The logger is exported as the default export, allowing any module in the monorepo to import the same instance via the alias @karakeep/shared/logger.

Environment-Based Configuration

Log behavior is controlled through packages/shared/config.ts, which validates environment variables using Zod schemas. Two key variables govern logger initialization:

// packages/shared/config.ts
export const LOG_LEVEL = z.string().default("debug");
export const LOG_NO_COLOR = stringBool("false");

The LOG_LEVEL variable defaults to "debug" but can be set to "error", "warn", "info", or "debug" to filter verbosity. The LOG_NO_COLOR variable disables ANSI color codes when set to "true", useful for log aggregation systems that expect plain text.

Usage Patterns Across the Monorepo

Standard Logging in Services

Modules import the singleton and call standard Winston methods—logger.info(), logger.warn(), logger.error(), and logger.debug(). For example, the admin router in packages/trpc/routers/admin.ts logs administrative actions for audit trails:

// packages/trpc/routers/admin.ts
import logger from "@karakeep/shared/logger";

logger.info(`[admin] Admin ${ctx.user.id} accessed debug info for bookmark ${input.bookmarkId}`);

Throttled Logging for High-Frequency Events

For background workers processing high-volume events, Karakeep exports a throttledLogger helper that guarantees a message emits at most once per specified millisecond interval. This prevents log spam while maintaining observability:

// packages/shared/logger.ts
export function throttledLogger(periodMs: number) {
  let lastLogTime = 0;
  return (level: string, message: string) => {
    const now = Date.now();
    if (now - lastLogTime >= periodMs) {
      lastLogTime = now;
      logger.log(level, message);
    }
  };
}

Workers import both the standard logger and the throttled helper to handle different logging frequencies appropriately.

Practical Implementation Examples

Basic Service Logging

Import the singleton and use structured logging levels to track application flow:

import logger from "@karakeep/shared/logger";

export async function doSomething() {
  logger.debug("Starting doSomething");
  try {
    // …your logic…
    logger.info("doSomething succeeded");
  } catch (err) {
    logger.error(`doSomething failed: ${(err as Error).message}`);
    throw err;
  }
}

Worker Integration with Throttling

Prevent log flooding in high-throughput workers by wrapping repetitive log calls:

import logger, { throttledLogger } from "@karakeep/shared/logger";

const logOncePerSecond = throttledLogger(1000);

export function processEvent(event: any) {
  // This could fire many times per second
  logOncePerSecond("info", `Processing event ${event.id}`);
  // …processing…
}

Runtime Log Level Adjustment

Change verbosity without code changes by setting the environment variable before starting the server:

LOG_LEVEL=error pnpm web

This configuration immediately restricts output to error-level messages only, as the Winston instance reads serverConfig.logLevel during initialization.

Summary

  • Centralized Singleton: The packages/shared/logger.ts file exports a single Winston instance used across the entire monorepo via the @karakeep/shared/logger alias.
  • Environment Control: Log levels and colorization are configured through LOG_LEVEL and LOG_NO_COLOR variables defined in packages/shared/config.ts.
  • Flexible API: Supports standard Winston methods (info, warn, error, debug) plus a throttledLogger helper for rate-limiting high-frequency events.
  • Consistent Formatting: All logs include timestamps and optional colorization, outputting to Console for easy container integration.

Frequently Asked Questions

How do I change the log level in Karakeep?

Set the LOG_LEVEL environment variable before starting the application. Valid values include "error", "warn", "info", and "debug". The default is "debug", which outputs the most verbose logging. Changes take effect immediately on server restart as the Winston instance reads the configuration during creation.

What is the throttledLogger used for?

The throttledLogger function creates a rate-limited wrapper around the standard Winston logger that emits messages at most once per specified millisecond interval. This prevents log spam in high-frequency contexts like background workers processing webhooks or crawling operations, where standard logging would generate excessive noise.

Where does Karakeep output its logs?

By default, Karakeep logs to the console only via winston.transports.Console(). The logger configuration in packages/shared/logger.ts does not include file transports, making it suitable for containerized environments where stdout aggregation is preferred. You can modify the transports array to add file logging if needed.

How does Karakeep handle log formatting in production?

The logger uses winston.format.combine() to chain formatting rules: timestamps are always included, colorization is applied unless LOG_NO_COLOR is set to "true", and a custom printf template renders the final string as ${timestamp} ${level}: ${message}. This produces consistent, parseable log lines suitable for both human reading in development and machine parsing in production environments.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →