OmniRoute Logging Mechanisms: Pino-Based Structured Logging with Automatic Rotation
OmniRoute provides enterprise-grade logging mechanisms built on Pino, featuring worker-thread transports, automatic credential redaction via pre-serialization hooks, and configurable file rotation with retention policies.
OmniRoute implements a high-performance logging architecture designed for proxy workloads requiring both observability and security. The system leverages Pino as its underlying JSON logger to minimize overhead while providing human-readable output during development. This implementation is centralized in src/shared/utils/logger.ts and supported by dedicated rotation and redaction modules in src/lib/ and src/shared/utils/.
Core Logger Architecture
The logging subsystem revolves around a singleton logger instance exported from src/shared/utils/logger.ts. This module configures base Pino options—including log level, timestamp formatting, and service tagging—and installs a critical log-method hook that executes redactLogArgs to strip credential-like values before they reach the transport layer (lines 10-43).
Transport Layer and Worker Threads
Transport creation is handled by buildTransportStream (lines 54-78), which evaluates the APP_LOG_TO_FILE environment flag to determine the output strategy:
- Worker-thread transport: Preferred for production to prevent I/O blocking on the main thread
- Synchronous fallback: Used when worker threads are unavailable or during specific debugging scenarios
The transport attaches an error listener that writes warnings to stderr without crashing the process, ensuring resilience during disk-pressure events.
Environment Profiles
The buildLoggerResource function (lines 36-91) assembles transports based on the runtime environment:
- Development (
isDev: true): Combinespino-prettyfor console output with a JSON file stream viapino/file - Production: Dual
pino/filestreams writing raw JSON to both stdout and a persistent log file for ingestion by external log aggregators
The function returns a SharedLoggerResource object that exposes a close method for graceful shutdown during HMR reloads or process termination.
Singleton Resource Management
The src/shared/utils/loggerResource.ts module ensures only one Pino transport stream is created per process. It manages the SharedLoggerResource lifecycle, preventing transport leaks during development hot-reloading and providing centralized cleanup capabilities.
Security and Credential Redaction
OmniRoute prevents accidental secret leakage through src/shared/utils/logRedaction.ts. This module implements the redactLogArgs function used by the logger's pre-serialization hook. Before Pino formats any log entry, this utility scans arguments for credential-like patterns—such as API keys, tokens, or passwords—and replaces them with redaction markers, ensuring sensitive data never persists to disk or external log streams.
Log Rotation and Retention Policies
File-based logging incorporates automatic rotation and cleanup via src/lib/logRotation.ts. The initLogRotation() function establishes background maintenance that respects three environment variables:
APP_LOG_MAX_FILE_SIZE: Byte threshold triggering rotation (default implementation checks file size)APP_LOG_RETENTION_DAYS: Duration to preserve archived logs before deletionAPP_LOG_MAX_FILES: Maximum number of rotated files to maintain in the log directory
Rotation Strategy
When enabled, the system monitors the active log file through rotateIfNeeded (lines 78-88). Upon exceeding the configured size limit, the current file is atomically renamed to app.YYYY-MM-DD_HHmmss.log. A recurring timer—initialized by initLogRotation (lines 84-101) and defaulting to 60-second intervals—continuously evaluates rotation conditions and purges expired archives based on retention policies.
Practical Usage and Child Loggers
Developers interact with the system through the createLogger factory function, which produces child loggers scoped to specific modules. This pattern is demonstrated in src/lib/usage/resilienceExplain.ts, where a module-level logger prefixes all entries with a custom name (resilience-explain) for traceability.
// Import the shared logger and create a child scoped to your module
import { logger, createLogger } from "@/shared/utils/logger";
const log = createLogger("proxy"); // → { module: "proxy" } attached to every entry
log.info({ model: "gpt-4o" }, "Incoming request");
// Logging an error – the hook redacts any secret fields before Pino formats
try {
await upstreamCall();
} catch (err) {
log.error({ err }, "Upstream failure");
}
// The logger automatically writes to both stdout and a rotating file
// (file path and rotation behaviour are driven by env vars)
process.env.APP_LOG_TO_FILE = "true"; // enable file logging
process.env.APP_LOG_MAX_FILE_SIZE = "52428800"; // 50 MiB rotation threshold
Summary
- Pino Foundation: OmniRoute uses Pino for high-throughput JSON logging with configurable pretty-printing in development
- Worker-Thread Transports: Asynchronous logging via
buildTransportStreamprevents I/O blocking, with graceful error handling that avoids process crashes - Automatic Redaction: The
redactLogArgshook inlogRedaction.tssanitizes credentials before serialization - Configurable Rotation:
initLogRotationmanages file size limits, datetime-stamped archives, and retention policies via environment variables - Singleton Pattern:
loggerResource.tsensures a single transport instance per process with proper cleanup support
Frequently Asked Questions
What underlying logging library does OmniRoute use?
OmniRoute uses Pino, a fast JSON logger for Node.js. The implementation in src/shared/utils/logger.ts configures Pino with custom transport streams, pre-serialization hooks for security, and environment-specific formatting options for both human-readable development output and machine-parseable production logs.
How does OmniRoute prevent sensitive data from appearing in log files?
The system implements a redaction hook via src/shared/utils/logRedaction.ts. Before any log entry is serialized, the redactLogArgs function scans the arguments for credential-like values and removes them. This ensures that API keys, passwords, or tokens accidentally passed to log methods never reach the transport layer or persistent storage.
Does OmniRoute support automatic log file rotation?
Yes. When APP_LOG_TO_FILE is enabled, the initLogRotation function in src/lib/logRotation.ts actively monitors log files. It rotates files when they exceed APP_LOG_MAX_FILE_SIZE by renaming them with timestamps (app.YYYY-MM-DD_HHmmss.log) and periodically cleans up expired files based on APP_LOG_RETENTION_DAYS and APP_LOG_MAX_FILES settings.
How do I create a module-specific logger in OmniRoute?
Import createLogger from @/shared/utils/logger and invoke it with your module name to create a child logger. This automatically attaches the module name to every log entry's metadata, as shown in src/lib/usage/resilienceExplain.ts. Child loggers inherit the parent's transport configuration and redaction hooks while allowing scoped log contexts.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →