@oneiriq/stoat-logger
v1.1.1
Published
Stoat Logger is a simple and modular logging framework with support for multiple transports for Deno and NodeJS.
Maintainers
Readme
Stoat Logger 🐹
Stoat is a simple and modular logging framework with support for multiple transports.
Features
Originally developed as a structured logging framework, the Stoat Logger now supports a suite of common logging functionalities to support various logging needs such as FS integration, child loggers, observability/tracing, and custom serialization.
Additional Features
Performance
Stoat offers memory-efficient logging with zero-allocation paths for simple log entries, making it ideal for low-footprint applications.
- Dynamic Log Levels: Custom log levels with advanced management
- Modular Transport Systems: Console, file, HTTP, WebSocket, and custom transports for integration
- Safe Fallbacks: Fallbacks for sync logging under memory pressure
Security & Reliability
A strong emphasis on security, reliability, and best practices went into ensuring safe logging in production environments.
- Input Sanitization with configurable redaction policies
- Data Classification (sensitive data marking and handling)
- Error-Safe Design (never throws, graceful fallbacks)
Observability & Tracing
It also easily integrates with OpenTelemetry for distributed tracing, making it suitable for microservices and complex architectures.
- OpenTelemetry Integration (trace/span correlation)
- Rich Context Propagation for logging within microservices
- Request Correlation across distributed systems
- Performance Timing with built-in operation tracking
Quick Start
Basic Usage
import { stoat } from '@oneiriq/stoat-logger'
const logger = stoat.create({
level: 'info',
prettyPrint: true
})
logger.trace('This is a trace message')
logger.info('Application started')
logger.warn('High process count', { process: 'app.exe', usage: 73 })
logger.error('Order execution failed', { orderId: 'ORD-123', error: 'timeout' })Example Output
2025-07-25T21:13:50.918Z INFO [session:7fe340ff module:basic-stoat-examples_fileLogger] This goes to both console and file
2025-07-25T21:13:50.919Z ERROR [session:7fe340ff module:basic-stoat-examples_fileLogger] Error logged to file | {"error":"database_error"}Advanced Logging with LogEntry
import {
stoat,
StructuredLogger,
createAsyncLogger,
ASYNC_CONFIGS
} from '@oneiriq/stoat-logger'
const structuredLogger = new StructuredLogger({
pretty: true,
maxDepth: 15,
includeStackTrace: true,
timestampFormat: 'iso'
})
const logEntry = structuredLogger.createLogEntry({
level: 'info',
message: 'Trade executed successfully',
data: {
orderId: 'ORD-123',
symbol: 'NVDA',
quantity: 100,
price: 150.25,
venue: 'NYSE'
},
context: {
traceId: 'trace-abc-123',
spanId: 'span-def-456',
requestId: 'req-789',
strategy: 'momentum',
agentId: 'agent-001'
}
})
const jsonOutput = structuredLogger.serialize(logEntry)
console.log(jsonOutput)Feature Overview
Async Logging
// async loggers
const asyncLogger = createAsyncLogger(
ASYNC_CONFIGS.trading,
(entry) => {
console.log(JSON.stringify(entry))
}
)
// Log thousands of entries without blocking
for (let i = 0; i < 10000; i++) {
await asyncLogger.log({
timestamp: new Date().toISOString(),
level: 'info',
levelValue: 30,
message: `Low-footprint entry ${i}`,
data: { tickId: i, latency: performance.now() }
})
}
// Flush as required (or just allow auto-flush)
await asyncLogger.flush()Supports Multiple Transports
const logger = stoat.create({
transports: [
createConsoleTransport({
format: 'json',
minLevel: 'debug'
}),
createFileTransport({
path: './logs/app.log',
format: 'text',
minLevel: 'info',
async: true,
bufferSize: 1000
}),
createHttpTransport({
endpoint: 'https://logs.company.com/ingest',
minLevel: 'warn',
batchSize: 100
})
]
})Custom Serializers
const serializer = createSerializer({
maxDepth: 10,
maxStringLength: 5000,
enableCircularDetection: true,
fastPaths: true,
customSerializers: {
'BigNumber': (value) => ({
__type: 'bignumber',
value: value.toString(),
precision: value.decimalPlaces()
}),
'OrderId': (value) => ({
__type: 'orderId',
value: String(value)
})
}
})
const result = serializer.serialize(complexTradingObject)
console.log(`Serialized in ${result.serializationTime}ms`)Stoat Example
import { stoat } from '@oneiriq/stoat-logger'
// Rich development logger with pretty-printing
const devLogger = stoat.create({
level: 'trace',
prettyPrint: true,
structured: true,
transports: [{
type: 'console',
format: 'json'
}],
serializer: {
maxDepth: 20,
includeStackTrace: true,
includeNonEnumerable: true
}
})
// Debug complex objects with full detail
const complexObject = {
user: { id: 123, profile: { /* deep nesting */ } },
orders: [/* large arrays */],
metadata: new Map(),
customTypes: new BigNumber('123.456')
}
devLogger.debug('Complex object analysis', complexObject)
// Performance debugging
const perfLogger = devLogger.child({
component: 'performance-analysis'
})
const start = performance.now()
// ... some operation
perfLogger.trace('Operation timing', {
operation: 'data-processing',
duration: performance.now() - start,
memoryBefore: process.memoryUsage(),
memoryAfter: process.memoryUsage()
})For more, see the examples/ directory.
Security Features
Data Sanitization & Redaction
import { createSanitizer } from '@oneiriq/stoat/security'
const logger = stoat.create({
security: {
enableSanitization: true,
sanitizer: createSanitizer({
redactFields: ['password', 'apiKey', 'ssn', 'creditCard'],
redactRegexes: [
/\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/g, // Credit cards
/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g // Emails
],
maxLogSize: 1024 * 1024, // 1MB limit
enableTruncation: true
})
}
})
// Automatically redacts sensitive data
logger.info('User login', {
userId: 123,
email: '[email protected]', // Will be redacted
password: 'secret123', // Will be redacted
apiKey: 'key-abc-123' // Will be redacted
})
// Output: { userId: 123, email: '[REDACTED]', password: '[REDACTED]', apiKey: '[REDACTED]' }Type-Safe Security Classification
import { markSensitive, createSanitized } from '@oneiriq/stoat/types'
// Compile-time security classification
const customerData = markSensitive({
ssn: '123-45-6789',
creditScore: 750,
income: 75000
})
const sanitizedInput = createSanitized(userInput) // Validated input
logger.info('Customer profile updated', {
customerId: 123,
data: customerData, // Automatically handled as sensitive
source: sanitizedInput // Marked as safe
})Development
# Clone repository
git clone https://github.com/oneiriq/stoat.git
cd stoat
# Run tests
deno task test
# Run benchmarks
deno task bench
# Format code
deno task fmt
# Lint code
deno task lintLicense
MIT License - see LICENSE file for details.
