Skip to content

Stoat is a simple and modular logging framework with support for multiple transports.

License

Notifications You must be signed in to change notification settings

Oneiriq/stoat-logger

Repository files navigation

Stoat Logger 🐹

Build Status Deno Version License: MIT JSR

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: 'user@example.com', // 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 lint

License

MIT License - see LICENSE file for details.

About

Stoat is a simple and modular logging framework with support for multiple transports.

Topics

Resources

License

Stars

Watchers

Forks