Architecture
This document explains how @nextrush/log works internally.
High-Level Overview
┌─────────────────────────────────────────────────────────────────┐
│ Your Application │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ createLogger() │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ context │ │ options │ │ metadata │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Logger Instance │
│ │
│ log.info() log.error() log.debug() log.warn() ... │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Log Pipeline │
│ │
│ 1. Level Check → Skip if below minLevel │
│ 2. Build Entry → timestamp, level, message, data │
│ 3. Serialize → Safe handling of objects, errors │
│ 4. Redact → Remove sensitive data │
│ 5. Format → Pretty (dev) or JSON (prod) │
│ 6. Output → Console + Custom Transports │
└─────────────────────────────────────────────────────────────────┘Log Flow (Mermaid)
mermaid
flowchart TD
A[log.info] --> B{Level Check}
B -->|Skip| C[Return]
B -->|Pass| D[Create LogEntry]
D --> E[Serialize Data]
E --> F[Redact Sensitive]
F --> G[Format Output]
G --> H[Console]
G --> I[Transports]Module Structure
mermaid
graph TB
subgraph Core
A[core/logger.ts] --> B[core/factory.ts]
A --> C[core/levels.ts]
A --> P[core/parse-log-args.ts]
A --> R[core/resolve-options.ts]
A --> T[core/transport-pipeline.ts]
A --> CFG[core/config.ts]
CFG --> CS[core/config-store.ts]
CFG --> NM[core/namespace-matcher.ts]
end
subgraph Processing
D[serializer/] --> E[Circular Detection]
D --> F[Error Serialization]
D --> G[Redaction]
end
subgraph Output
H[formatter/] --> I[Pretty Format]
H --> J[JSON Format]
K[transport/] --> L[Console]
K --> M[Batch]
K --> N[filtered / ratelimit]
end
subgraph Utilities
O[runtime/] --> Q2[Environment Detection]
Q[utils/] --> R2[Timestamps]
end
A --> D
A --> H
A --> K
A --> ODirectory Structure
src/
├── core/ # Logger class and global configuration
│ ├── logger.ts # Logger class — a thin facade delegating to the below
│ ├── factory.ts # createLogger function
│ ├── parse-log-args.ts # Flexible (message, data, error) argument parsing
│ ├── resolve-options.ts # Option/environment resolution, child-option derivation
│ ├── transport-pipeline.ts # Transport execution (global + instance transports)
│ ├── config.ts # Global config: configure()/disableLogging()/etc.
│ ├── config-store.ts # createConfigStore() factory backing global config
│ ├── namespace-matcher.ts # Shared, ReDoS-guarded namespace glob matching
│ └── levels.ts # Log levels (trace → fatal)
│
├── serializer/ # Data processing
│ ├── serialize.ts # Safe object serialization (dispatches by type)
│ ├── collections.ts # Map/Set/Array serializers
│ ├── redaction.ts # Sensitive data removal (whole-token key matching)
│ └── error.ts # Error serialization (single source, used everywhere)
│
├── formatter/ # Output formatting
│ ├── pretty.ts # Terminal human-readable (message sanitized before output)
│ ├── json.ts # Structured JSON
│ └── browser.ts # Browser console (CSS), message never fed into the format string
│
├── transport/ # Output destinations
│ ├── console.ts # Console output (built into every Logger — do not add as a transport)
│ ├── batch.ts # Batched sending
│ ├── filtered.ts # Level-based filtering
│ └── ratelimit.ts # Token-bucket rate limiting
│
├── runtime/ # Environment detection
│ └── index.ts # Node / browser / Deno / Bun / edge detection
│
├── context/ # Async correlation-ID/metadata propagation
│ ├── index.ts # Public runWithContext/getAsyncContext/middleware
│ ├── async-local-storage.ts # AsyncLocalStorage loading (ESM-safe)
│ ├── fallback-stack.ts # Scoped fallback for runtimes without ALS
│ └── types.ts
│
├── browser/ # Browser-specific utilities
│ ├── index.ts # Barrel
│ ├── environment.ts # isBrowser/isServer/isOnline
│ ├── error-capture.ts # window.onerror / unhandledrejection capture
│ ├── beacon-transport.ts # navigator.sendBeacon transport
│ ├── lifecycle.ts # Flush-on-unload
│ └── setup.ts # setupBrowserLogging() orchestrator
│
├── react/ # React integration
│ └── index.tsx # Provider, hooks, ErrorBoundary
│
├── testing/ # Mock logger + assertions (@nextrush/log/testing)
│ └── index.ts
│
├── utils/ # Small shared primitives
│ ├── time.ts # Timestamp formatting
│ ├── colors.ts # ANSI/terminal colors
│ ├── console-method.ts # Single console-method resolver (used by transport + formatter)
│ └── level-icons.ts # Shared level icon glyphs
│
├── types/ # TypeScript definitions
│ └── index.ts # All type exports
│
└── index.ts # Main entry point — minimal public surface (~20 exports)Log Entry Structure
typescript
interface LogEntry {
timestamp: string; // ISO 8601
level: LogLevel; // 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal'
context: string; // Logger name
message: string; // Log message
data?: object; // Structured data (metadata merged here)
error?: { // Error details
name: string;
message: string;
stack?: string;
};
correlationId?: string; // Request tracing
performance?: { duration?: number }; // e.g. timer.end()
runtime: string; // 'node' | 'browser' | 'edge' | etc.
}Level Priority
┌──────────┬──────────┬─────────────────────────────────┐
│ Level │ Priority │ Use Case │
├──────────┼──────────┼─────────────────────────────────┤
│ trace │ 0 │ Very detailed debugging │
│ debug │ 1 │ Debug information │
│ info │ 2 │ General information │
│ warn │ 3 │ Warnings │
│ error │ 4 │ Errors (recoverable) │
│ fatal │ 5 │ Critical errors (app crash) │
└──────────┴──────────┴─────────────────────────────────┘Transport System
mermaid
flowchart LR
A[LogEntry] --> B[Transport Manager]
B --> C[Console Transport]
B --> D[Batch Transport]
B --> E[Filter Transport]
B --> F[Custom Transport]
D --> G[Flush Timer]
D --> H[Batch Queue]
H --> I[Remote API]
E --> J{Level Check}
J -->|Pass| K[Wrapped Transport]Serialization Pipeline
Input Object
│
▼
┌─────────────────┐
│ Circular Check │──▶ Replace with "[Circular]"
└─────────────────┘
│
▼
┌─────────────────┐
│ Depth Check │──▶ Stop at maxDepth
└─────────────────┘
│
▼
┌─────────────────┐
│ Type Handler │──▶ Error, Map, Set, Date, etc.
└─────────────────┘
│
▼
┌─────────────────┐
│ Redaction │──▶ Replace sensitive keys
└─────────────────┘
│
▼
Safe OutputEnvironment Detection
The logger automatically detects the runtime. Detection is priority-ordered — the first matching signal wins:
typescript
// Detection priority (first match wins)
1. React Native globals → 'react-native'
2. window + document → 'browser'
3. Worker self context → 'worker'
4. Edge runtime globals → 'edge' (e.g. EdgeRuntime, Cloudflare Workers)
5. Deno.version → 'deno'
6. Bun.version → 'bun'
7. process.versions → 'node'
8. fallback → 'unknown'Performance Considerations
- Level Check First: Skip processing if level is below minimum
- Lazy Serialization: Only serialize when needed
- Circular Detection: O(n) with WeakSet
- No Dependencies: Zero external packages
- Tree-Shakeable: Only import what you use