npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

bandeng-logger

v1.3.11

Published

Logger from bandeng developer team.

Readme

Bandeng Logger

English | 中文


English

A powerful logging library from Bandeng developer team.

Installation

npm install bandeng-logger

Usage

const Logger = require('bandeng-logger')

Features

  • 📝 Multiple log levels (fatal, error, warn, info, debug, trace)
  • 🔄 Automatic log rotation by size and time
  • 🎨 Colorful console output with customizable colors
  • 📊 Built-in performance monitoring for slow logs (explicitly enabled)
  • 🎯 Force print conditions for selective debugging regardless of log level
  • 🔍 Multi-process support with process ID tracking and concurrent rotation safety
  • 📦 Log compression (gzip)
  • 🏷️ Child loggers for modular logging
  • ⚡ Zero-blocking buffered writing with synchronous semantics
  • 🕒 High-precision UTC timezone support with millisecond timestamps
  • 📈 Advanced log write performance monitoring with timeout protection (requires explicit enablement)
  • 📋 Support for both JSON and text log formats
  • 🔒 Configurable error log storage with custom level separation
  • 🕐 Customizable log rotation interval and buffer flush timing
  • 🛡️ Enhanced error handling with circular reference detection and recursion prevention
  • 🧹 Intelligent automatic file management and concurrent cleanup
  • 📁 Smart log file splitting with size limit enforcement
  • 🔧 Comprehensive process lifecycle management with signal handling
  • ✅ Advanced configuration validation with boundary checking
  • 🚀 Atomic file operations with concurrent safety
  • 📊 Real-time statistics and monitoring
  • 🔄 Intelligent buffer management with dynamic thresholds
  • 🔮 Modern JavaScript data type support (BigInt, Symbol, Map, Set, TypedArray, Promise)
  • 🛡️ Serialization depth protection and memory leak prevention
  • 🔒 Context content sanitization with length limits and security filtering
  • ⚙️ Runtime configuration updates with hot reloading
  • 📈 Advanced request performance tracking with context handling
  • 🔧 Customizable ctx field processing with injection functions
  • 🛡️ Resource leak prevention with automatic stream cleanup
  • 🚫 Path traversal protection with filename sanitization
  • 🔄 Intelligent retry mechanism with exponential backoff
  • 📊 Real-time memory usage monitoring and leak prevention
  • 🎯 Unified error handling strategy across all operations
  • 🌐 HTTP request logging with framework auto-detection
  • 🧠 Smart IP extraction supporting multiple proxy headers
  • 📘 Full TypeScript support with complete type definitions

Quick Start

Basic Usage

const Logger = require('bandeng-logger')
const logger = new Logger({logLevel: 'info', logFormat: 'text'})

logger.info('Info log')
logger.error('Error log')
logger.warn('Warning log')

const moduleLogger = logger.createChildLogger('UserModule')
moduleLogger.info('User login success')

TypeScript Usage

// CommonJS import (recommended for existing projects)
// Note: When package is published, use: const Logger = require('bandeng-logger')
const Logger = require('./index') // Use relative path during development

// Or use ES6 module import
// import Logger from 'bandeng-logger'

// Type definitions (manual declaration needed with CommonJS)
type LogLevel = 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace'
type LogFormat = 'json' | 'text'
type FrameworkStyle = 'koa' | 'express'

interface LoggerOptions {
    logLevel?: LogLevel
    logFormat?: LogFormat
    logDir?: string
    rotate?: number
    maxFiles?: number
    traceLogWrite?: boolean
}

// Complete type-safe configuration
const loggerOptions: LoggerOptions = {
    logLevel: 'info' as LogLevel,
    logFormat: 'json' as LogFormat,
    logDir: './logs'
}

// Create Logger instance
const logger = new Logger(loggerOptions)

// All methods have complete type hints and comments
logger.info('TypeScript info log')
logger.error('TypeScript error log', {error: 'Something went wrong'})
logger.debug('Debug with structured data', {userId: 123, action: 'login'})

// Static methods also have type hints
const ctxProcessor = Logger.getCtxProcessor('whitelist', ['userId', 'action'])

// Complete type safety and intelligent code completion support
const stats = logger.getStatistics()
const success = logger.updateOptions({logLevel: 'debug'})

Basic Configuration Examples

const Logger = require('bandeng-logger')

// Minimal configuration - uses all default values
const simpleLogger = new Logger()

// Or basic configuration - basic customizations
const basicLogger = new Logger({
    logLevel: 'info',
    logFormat: 'json'
})

Recommended Production Configuration

const Logger = require('bandeng-logger')
const config = require('./config.js')

// Create production-ready logger instance with essential customizations
const defaultLogger = new Logger({
    // Essential: Dynamic log level based on environment
    logLevel: config.isTest ? 'trace' : 'warn',
    // Essential: Dynamic log format based on environment
    logFormat: config.isTest ? 'text' : 'json',

    // Custom: Adjust log rotation size if 100MB is not suitable
    rotate: 20, // 20MB instead of default 100MB
    // Custom: Adjust rotation check interval if 1 hour is not suitable
    interval: 600, // Every 10 minutes instead of default 1 hour

    // Optional: Enable performance monitoring (disabled by default)
    traceLogWrite: config.enablePerformanceMonitoring || false,

    // Optional: Custom color scheme for different environments
    colors: {
        trace: 'gray',
        debug: 'blue',
        info: 'white',
        warn: config.isTest ? 'yellow' : 'white',
        error: 'red',
        fatal: 'magenta'
    },

    // Optional: Custom timezone (default is auto-detected)
    utcFormat: 8 // UTC+8 for timestamps

    // Note: HTTP request logging is enabled via method calls, no configuration needed
    // Use logger.logHttpRequest() to log HTTP requests

    // Note: The following use default values, no need to specify:
    // logDir: './logs' (default)
    // compress: 'none' (default)
    // maxFiles: 15 (default)
    // bufferSize: 65536 (default)
    // flushInterval: 1000 (default)
    // forceSyncLevels: ['fatal'] (default)
    // ctxProcessor: null (default)
})

// Export essential logging utilities
module.exports = {
    // Core logger instance
    logger: defaultLogger,

    // Essential methods for application use
    createChildLogger: defaultLogger.createChildLogger.bind(defaultLogger),
    traceRequestPerformance: defaultLogger.traceRequestPerformance.bind(defaultLogger),

    // HTTP request logging (recommended for production)
    logHttpRequest: defaultLogger.logHttpRequest.bind(defaultLogger),

    // Configuration management (for advanced use)
    getOptions: defaultLogger.getOptions.bind(defaultLogger),
    updateOptions: defaultLogger.updateOptions.bind(defaultLogger),

    // Statistics and monitoring (for operational use)
    getStatistics: defaultLogger.getStatistics.bind(defaultLogger),
    resetStatistics: defaultLogger.resetStatistics.bind(defaultLogger)
}

Parameter Usage Examples

// ✅ Single parameter - any type supported
logger.info('Simple message')
logger.debug(42)
logger.warn({error: 'Something went wrong', code: 500})

// ✅ Two parameters - first must be string, second can be any type
logger.info('User Login', {userId: 123, ip: '192.168.1.100'})
logger.debug('Database Query', 'SELECT * FROM users WHERE id = ?')

// ✅ Complex logging with structured data
logger.info('Payment Processed', {
    transactionId: 'txn_123456',
    amount: 99.99,
    currency: 'USD',
    userId: 456,
    timestamp: new Date(),
    metadata: {
        paymentMethod: 'credit_card',
        gateway: 'stripe'
    }
})

// ❌ Avoid - multiple separate parameters (extra parameters ignored)
logger.debug('Event', 'param1', 'param2', 'param3') // Only first 2 processed

// ❌ Avoid - first parameter not a string (warning issued)
logger.debug(123, 'This will generate a warning')

Parameter Passing Rules in Detail

Basic Parameter Rules

  • Maximum 2 parameters supported, extra parameters are ignored
  • 1 parameter: Supports any type, including strings, numbers, objects, arrays, etc.
  • 2 parameters: First parameter must be string type, otherwise warning is issued

How to Pass Multiple Values

When you need to log multiple related values, wrap them in an object as the second parameter:

// ✅ Recommended: Wrap multiple values in an object
logger.debug('User Login', {
    userId: 123,
    username: 'john_doe',
    ip: '192.168.1.100',
    timestamp: Date.now(),
    metadata: {source: 'web'}
})

// ❌ Avoid: Multiple separate parameters (will be ignored)
logger.debug('User Login', 'john_doe', 123, '192.168.1.100') // Only first 2 processed

// ✅ Single parameter with object
logger.debug({
    event: 'user_login',
    userId: 123,
    username: 'john_doe',
    ip: '192.168.1.100'
})

JSON Format Object Type Special Handling

Important Note: When using JSON format, the second parameter has special handling rules for Object types. Additionally, complex data types in the msg field include type information:

Expansion Rules

  • Object Expansion: When the second parameter is a plain object (not array, not null, not undefined), all its properties are directly expanded into the log object
  • Other Types Use msg Key: Arrays, strings, numbers, booleans, null, undefined and other types are assigned to the msg field

Examples

// ✅ Objects are expanded - properties appear at root level
logger.info('User Login', {userId: 123, ip: '192.168.1.100'})
// Output: {"time":"...", "level":"INFO", "tag":"User Login", "userId":123, "ip":"192.168.1.100"}

// ✅ Arrays use msg key - preserve array structure
logger.debug('Data List', [1, 2, 3, 4])
// Output: {"time":"...", "level":"DEBUG", "tag":"Data List", "msg":[1,2,3,4]}

// ✅ Strings use msg key
logger.warn('Warning Message', 'Disk space low')
// Output: {"time":"...", "level":"WARN", "tag":"Warning Message", "msg":"Disk space low"}

// ✅ Numbers use msg key
logger.error('Error Code', 500)
// Output: {"time":"...", "level":"ERROR", "tag":"Error Code", "msg":500}

Design Intent

This design enables:

  1. Structured Logging: Object expansion provides clearer field structure for log analysis and querying
  2. Backward Compatibility: Arrays and other types still use msg key for compatibility
  3. Type Safety: Prevents accidental property overwrites, maintaining clear log structure

Configuration Options

| Option | Type | Default | Description | | -------------------- | -------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | logLevel | String | 'warn' | Log level, options: fatal, error, warn, info, debug, trace | | logFormat | String | 'json' | Log format, options: json, text | | utcFormat | Number | auto | UTC timezone, range: -12 to 14. If not provided, uses server's current timezone | | maxLength | Number | 1000 | Maximum log message length, will be truncated if exceeded | | logDir | String | './logs' | Log directory (will be converted to absolute path automatically), will be created if not exists | | logFileName | String | 'server.log' | Main log filename, must end with .log extension | | errorLogFileName | String | 'error.log' | Error log filename, must end with .log extension, only effective when separateErrorLog is true | | separateErrorLog | Boolean | true | Whether to separate error logs into a different file | | separateErrorLevels | Array | ['error','fatal'] | Which log levels to separate into error file, customizable | | traceLogWrite | Boolean | false | Enable log write performance monitoring (disabled by default, must be explicitly set to true), logs exceeding 100ms will be recorded | | rotate | Number | 100 | Log rotation size in MB. Log rotation is triggered when this size is exceeded | | interval | Number | 3600 | Log rotation check interval (seconds), min: 60, max: 604800 (7 days) | | compress | String | 'none' | Log compression method, options: none, gzip | | maxFiles | Number | 15 | Maximum number of log files to keep, oldest files will be deleted when exceeded | | bufferSize | Number | 65536 | Buffer size in bytes (64KB), min: 1024, max: 10MB | | flushInterval | Number | 1000 | Buffer flush interval (ms), min: 100, max: 60000 | | forceSyncLevels | Array | ['fatal'] | Log levels that should always be written synchronously. Configure as ['error', 'fatal'] to ensure ERROR and FATAL logs are immediately written to disk (useful for debugging and crash scenarios). | | forcePrintConditions | Array | [] | Array of condition functions for forced log printing regardless of log level, useful for business debugging | | ctxProcessor | Function | null | Custom ctx field processor ONLY for traceRequestPerformance method (designed for internal RPC communication), null uses default sanitizeContextForLogging | | colors | Object | see below | Log color configuration, supports custom colors for each level |

Color Configuration

| Level | Default Color | Description | | ----- | ------------- | ------------------------------ | | fatal | brightRed | Fatal errors, using bright red | | error | red | Errors, using red | | warn | brightYellow | Warnings, using bright yellow | | info | gray | Information, using gray | | debug | blue | Debug, using blue | | trace | white | Trace, using white |

Available Colors: black, red, green, yellow, blue, magenta, cyan, white, gray, brightBlack, brightRed, brightGreen, brightYellow, brightBlue, brightMagenta, brightCyan, brightWhite

Log Levels

logger.fatal('Fatal error')
logger.error('Error')
logger.warn('Warning')
logger.info('Info')
logger.debug('Debug')
logger.trace('Trace')

Note: Business error objects (e.g., {code: 2005, msg: '', data: ''}) are fully supported. All properties are correctly serialized and logged, even when values are empty strings or null.

Advanced Features

Modern JavaScript Data Types Support

Logger fully supports modern JavaScript data types with intelligent serialization:

// BigInt support
logger.debug('BigInt value:', 123n) // Output: "123n"

// Symbol support
logger.debug('Symbol value:', Symbol('test')) // Output: "[Symbol: test]"

// Map and Set support
const myMap = new Map([
    ['key1', 'value1'],
    ['key2', 'value2']
])
const mySet = new Set([1, 2, 3, 'test'])

logger.debug('Map object:', myMap) // Output: {"[Map]": {"key1": "value1", "key2": "value2"}}
logger.debug('Set object:', mySet) // Output: {"[Set]": [1, 2, 3, "test"]}

// TypedArray support
const typedArray = new Uint8Array([1, 2, 3, 4, 5])
logger.debug('TypedArray:', typedArray) // Output: {"[TypedArray]": "Uint8Array", "length": 5}

// Promise support
const promise = Promise.resolve('test')
logger.debug('Promise:', promise) // Output: "[Promise]"

Performance Monitoring

Performance monitoring is disabled by default and must be explicitly enabled:

// Enable performance monitoring
const logger = new Logger({
    traceLogWrite: true // Explicitly enable performance monitoring
})

// Now performance monitoring is active for all log operations
// Note: Performance monitoring uses a default threshold of 100ms for log write operations
logger.debug('This log write will be monitored for performance')
// Recommended approach - advanced request performance tracking for internal RPC communication
// This method is specifically designed for tracking performance between internal services
logger.traceRequestPerformance(
    {
        source: 'client-1',
        path: '/api/users',
        userId: 123,
        method: 'GET',
        ip: '192.168.1.100'
    },
    150,
    100
) // 150ms latency, 100ms threshold

// Force print all requests regardless of log level (v1.3.4+)
logger.traceRequestPerformance(
    {
        source: 'client-1',
        path: '/api/users',
        userId: 123,
        method: 'GET'
    },
    50, // 50ms latency (below threshold)
    100, // 100ms threshold
    true // Force print: true = ignore log level, false = follow log level
)

// Enable force print for debugging all requests
logger.traceRequestPerformance(ctx, latency, threshold, true)

// Custom tag for filtering performance logs (v1.3.5+)
logger.traceRequestPerformance(
    {
        source: 'client-1',
        path: '/api/users',
        userId: 123
    },
    150,
    100,
    false, // forcePrint
    'api-performance' // custom tag
)
// Logs will include {"tag":"api-performance"} for easy filtering

Context Content Sanitization

Logger automatically sanitizes context content for security and readability:

// Context content is automatically sanitized
logger.traceRequestPerformance(
    {
        userId: 123,
        requestData: 'A'.repeat(2000), // Long string will be truncated
        largeArray: Array(100).fill('item'), // Large array will be truncated
        sensitiveData: () => 'secret', // Functions will be filtered
        buffer: Buffer.from('data'), // Buffers will be filtered
        nested: {
            veryDeep: 'B'.repeat(1500), // Nested long strings also truncated
            complex: {
                data: new Map([['key', 'value']]) // Complex objects handled
            }
        }
    },
    150,
    100
)

// Output:
// - Strings longer than 1000 chars are truncated with "...[truncated X chars]"
// - Arrays larger than 50 items are truncated with "...[truncated X items]"
// - Functions and Buffers are replaced with "[function]" and "[Buffer]"
// - Complex objects are safely serialized

Automatic Error Logging

Logger automatically handles uncaughtException and unhandledRejection events, so applications using this package do not need to manually listen and handle these errors.

  • Automatic FATAL Logging for uncaughtException:

    • Logger automatically registers a handler for uncaughtException events
    • When an unhandled exception occurs, logger automatically generates a FATAL level log with tag [logger] Uncaught exception:
    • The log includes full stack trace information for quick error location
    • The process will exit after logging (as per Node.js default behavior)
  • Automatic ERROR Logging for unhandledRejection:

    • Logger automatically registers a handler for unhandledRejection events
    • When an unhandled promise rejection occurs, logger automatically generates an ERROR level log with tag [logger] Unhandled promise rejection:
    • The log includes stack trace information (extracted from Error objects or auto-generated)
    • The process continues running (does not exit)
  • Automatic FATAL Logging for process.exit:

    • Logger automatically registers a handler for process.exit events
    • When the process exits (via process.exit() or natural termination), logger automatically generates a FATAL level log with tag [logger] Process exit
    • The log includes the exit code and stack trace information (if available) to help locate where the exit was triggered
    • Uses synchronous file writing to ensure the log is written before the process terminates

Note: Since logger handles these events automatically, you don't need to manually add process.on('uncaughtException'), process.on('unhandledRejection'), or process.on('exit') handlers in your application code. The logger will capture and log these events automatically.

Log File Splitting Mechanism

Logger implements a concurrent-safe log file splitting mechanism that automatically splits large log files when they exceed the configured size limit. This is especially important in PM2 multi-process environments where multiple processes write to the same log file.

How It Works:

  1. Timer-Based Periodic Check: Logger uses a timer-based mechanism (not real-time file size monitoring). A periodic check is scheduled using setInterval that runs every interval seconds (default: 3600 seconds / 1 hour, configurable via interval option). The check also runs immediately when the logger is initialized.

  2. Size-Based Trigger: During each periodic check, the logger examines the log file size. Splitting is only triggered when the file size exceeds the configured limit (default: 100MB, configurable via rotate option). If the file size is below the threshold, no splitting occurs even though the check runs.

  3. Concurrent-Safe Locking:

    • Uses a lock file (.splitting.lock) with exclusive write mode (wx) to ensure only one process performs splitting at a time
    • If the lock file exists, other processes detect it and skip splitting (prevents race conditions)
    • Lock file is automatically released in finally block, even if errors occur
    • Stale Lock Detection: Automatically detects and removes stale lock files (e.g., when a process crashes). The system checks:
      • Lock file age: If the lock file is older than 5 minutes, it's considered stale
      • Process existence: Checks if the process ID (PID) stored in the lock file is still running
      • Automatic cleanup: Stale locks are automatically removed before attempting to acquire a new lock
  4. Double-Check Pattern:

    • After acquiring the lock, re-checks file existence and size
    • If file no longer exists or size is below threshold, releases lock and skips splitting
    • Prevents duplicate splitting when multiple processes detect the need simultaneously
  5. File Splitting Process:

    • Reads the entire log file into memory
    • Splits content into multiple files, each not exceeding 90% of the size limit (safety margin)
    • Creates split files with timestamp-based names: YYYY-MM-DD_HH-MM-SS-N-server.log
    • Closes file descriptors before deleting the original file
    • Reinitializes file descriptors for continued logging
  6. Old File Cleanup:

    • After splitting, checks total number of log files
    • Deletes oldest files if count exceeds maxFiles limit (default: 15)
    • Handles concurrent deletion attempts gracefully (detects if file already deleted)

Example Scenario (PM2 with 4 processes):

Time: 18:09:15.890
Process 1: Detects file size exceeded → Acquires lock → Starts splitting
Process 2: Detects file size exceeded → Tries to acquire lock → Fails (EEXIST) → Skips
Process 3: Detects file size exceeded → Tries to acquire lock → Fails (EEXIST) → Skips
Process 4: Detects file size exceeded → Tries to acquire lock → Fails (EEXIST) → Skips

Time: 18:09:17.267
Process 1: Completes splitting → Releases lock → Creates 4 split files
Process 2-4: Continue normal logging operations

Configuration:

const logger = new Logger({
    rotate: 100, // Split when file exceeds 100MB (checked periodically)
    interval: 3600, // Check every 1 hour (3600 seconds) - timer interval
    maxFiles: 15 // Keep maximum 15 log files
})

Important Notes:

  • Timer-Based: File splitting is not triggered in real-time when the file size limit is exceeded. It only happens during the periodic check (default: every 1 hour).
  • 📏 Size Threshold: The rotate option sets the size limit, but splitting only occurs when the periodic check detects the file has exceeded this limit.
  • Initial Check: An immediate check runs when the logger initializes, so splitting can occur right away if the file already exceeds the limit.
  • 🔄 Check Frequency: For high-volume logging scenarios, consider reducing the interval value (minimum: 60 seconds) to check more frequently, but be aware this increases CPU usage.

Benefits:

  • Concurrent Safety: Prevents multiple processes from splitting simultaneously
  • Data Integrity: Ensures log files are not corrupted during splitting
  • Performance: Only one process performs the expensive splitting operation
  • Automatic Cleanup: Old files are automatically removed to save disk space
  • Error Recovery: Lock is always released, even if splitting fails
  • Stale Lock Recovery: Automatically detects and removes stale locks from crashed processes, ensuring splitting continues to work even after process failures

Runtime Configuration Updates

// Update configuration at runtime (hot reloading)
const success = logger.updateOptions({
    logLevel: 'debug', // Change log level
    maxLength: 2000, // Increase max message length
    traceLogWrite: true // Enable performance monitoring
})

if (success) {
    console.log('Configuration updated successfully')
}

// Get current configuration
const currentConfig = logger.getOptions()
console.log('Current configuration:', currentConfig)

Statistics and Monitoring

// Get real-time statistics and monitoring information
const stats = logger.getStatistics()
console.log('Logger Statistics:', stats)
// Output includes: totalLogs (as string), flushedLogs (as string), buffer stats, etc.
// Note: Large numbers are returned as strings to avoid JavaScript number precision limits

// Reset all statistics counters to zero
logger.resetStatistics()
console.log('Statistics have been reset')

Usage Examples

HTTP Request Logging

Koa Framework Usage
const logger = new Logger({utcFormat: 8})

// Basic middleware usage (high-precision timing)
app.use(async (ctx, next) => {
    // Use high-precision timer
    const start = process.hrtime()
    await next()
    // Calculate and format precise response time (milliseconds, max 3 decimal places)
    // Format examples: 1.030 -> 1.03, 1.031 -> 1.031, 1.000 -> 1
    const [seconds, nanoseconds] = process.hrtime(start)
    let responseTime = seconds * 1000 + nanoseconds / 1000000
    // Format: max 3 decimal places, remove trailing zeros
    responseTime = parseFloat(responseTime.toFixed(3))

    // Automatically parse all information from ctx
    logger.logHttpRequest(ctx, {
        frameworkStyle: 'koa', // Required: must specify framework type
        responseTime: responseTime
    })
})

// With extra parameters (high-precision timing)
app.use(async (ctx, next) => {
    // Use high-precision timer
    const start = process.hrtime()
    await next()
    // Calculate and format precise response time (milliseconds, max 3 decimal places)
    // Format examples: 1.030 -> 1.03, 1.031 -> 1.031, 1.000 -> 1
    const [seconds, nanoseconds] = process.hrtime(start)
    let responseTime = seconds * 1000 + nanoseconds / 1000000
    // Format: max 3 decimal places, remove trailing zeros
    responseTime = parseFloat(responseTime.toFixed(3))

    // Log user information and request details
    logger.logHttpRequest(ctx, {
        frameworkStyle: 'koa', // Required: must specify framework type
        responseTime: responseTime,
        extraParams: [`userId:${ctx.state.user?.id || 'anonymous'}`, `userAgent:${ctx.get('User-Agent')}`]
    })
})
Express Framework Usage
const logger = new Logger({utcFormat: 8})

// Basic middleware usage (high-precision timing)
app.use((req, res, next) => {
    // Use high-precision timer
    const start = process.hrtime()

    res.on('finish', () => {
        // Calculate precise response time (milliseconds, max 3 decimal places)
        // Format examples: 1.030 -> 1.03, 1.031 -> 1.031, 1.000 -> 1
        const [seconds, nanoseconds] = process.hrtime(start)
        const responseTime = seconds * 1000 + nanoseconds / 1000000
        // Format: max 3 decimal places, remove trailing zeros
        responseTime = parseFloat(responseTime.toFixed(3))

        // Use logHttpRequest to log HTTP request information
        logger.logHttpRequest(
            {req, res},
            {
                frameworkStyle: 'express',
                responseTime: responseTime
            }
        )
    })

    next()
})

// With extra parameters (high-precision timing)
app.use((req, res, next) => {
    // Use high-precision timer
    const start = process.hrtime()

    res.on('finish', () => {
        // Calculate precise response time (milliseconds, max 3 decimal places)
        // Format examples: 1.030 -> 1.03, 1.031 -> 1.031, 1.000 -> 1
        const [seconds, nanoseconds] = process.hrtime(start)
        const responseTime = seconds * 1000 + nanoseconds / 1000000
        // Format: max 3 decimal places, remove trailing zeros
        responseTime = parseFloat(responseTime.toFixed(3))

        logger.logHttpRequest(
            {req, res},
            {
                frameworkStyle: 'express', // Required: must specify framework type
                responseTime: responseTime,
                extraParams: [`userId:${req.user?.id || 'anonymous'}`, `sessionId:${req.session?.id || 'none'}`]
            }
        )
    })

    next()
})
Output Examples
2025-09-20 17:53:01.113 UTC+8 GET /api/users 200 125.68 ms 192.168.1.100 - 12345 [userId:123]
2025-09-20 17:53:01.114 UTC+8 POST /api/login 401 234.57 ms 10.0.0.50 - 12345 [userId:anonymous]
2025-09-20 17:53:01.115 UTC+8 PUT /api/user 200 100 ms 192.168.1.100 - 12345

Format explanation:

  • Timestamp: UTC+8 timezone, high-precision milliseconds
  • Request method: HTTP method
  • Path: Request path
  • Status code: HTTP response status code
  • Response time: milliseconds (fixed unit), 3 decimal places precision
  • IP address: Real client IP
  • Process ID: Node.js process ID
  • Extra parameters: [Optional] User ID and other information

Error Handling

// Note: Logger automatically handles uncaughtException and unhandledRejection events
// You don't need to manually register these handlers - logger does it automatically

// Business error objects (e.g., {code, msg, data}) are fully supported
logger.error('Controller.RealTime.pay', {
    error: {code: 2005, msg: 'Order not found', data: 'order_id: 12345'},
    data: {type: '2', order_id: '123'},
    msg: 'catch error'
})
// All properties (code, msg, data) are correctly serialized and logged

Database Logging

const dbLogger = logger.createChildLogger('Database')
async function queryDatabase(sql, params) {
    try {
        const start = Date.now()
        const result = await db.query(sql, params)
        const duration = Date.now() - start
        dbLogger.info({sql, params, duration: `${duration}ms`, rows: result.length})
        return result
    } catch (error) {
        dbLogger.error('Database query error', {sql, params, error: error.message})
        throw error
    }
}

Custom Ctx Processing

You can customize how traceRequestPerformance processes the ctx parameter by providing a custom processor function. This is particularly useful for internal RPC communication between services where you need specific context filtering:

const Logger = require('bandeng-logger')

// 1. Using predefined processors
const logger1 = new Logger({
    logLevel: 'info',
    ctxProcessor: Logger.getCtxProcessor('whitelist', ['userId', 'ip', 'method'])
})

// 2. Using whitelist with nested field paths (supports dot notation)
const loggerNested = new Logger({
    logLevel: 'info',
    ctxProcessor: Logger.getCtxProcessor('whitelist', ['user.id', 'user.name', 'request.method'])
})

// 3. Using blacklist to exclude sensitive fields (supports nested paths)
const logger2 = new Logger({
    logLevel: 'info',
    ctxProcessor: Logger.getCtxProcessor('blacklist', ['user.password', 'auth.token', 'sensitive.data'])
})

// 4. Field renaming
const logger3 = new Logger({
    logLevel: 'info',
    ctxProcessor: Logger.getCtxProcessor('rename', {
        userId: 'user_id',
        sessionId: 'session_id'
    })
})

// 4. Complex transformation
const logger4 = new Logger({
    logLevel: 'info',
    ctxProcessor: Logger.getCtxProcessor('transform', {
        include: ['userId', 'ip', 'headers'],
        exclude: ['authorization'],
        rename: {
            userId: 'user_id',
            headers: 'request_headers'
        }
    })
})

// 5. Custom processor function
const logger5 = new Logger({
    logLevel: 'info',
    ctxProcessor: ctx => {
        // Custom processing logic
        const result = {}
        for (const [key, value] of Object.entries(ctx)) {
            if (typeof value === 'string' && key !== 'sensitive') {
                result[key] = value.toUpperCase()
            }
        }
        return result
    }
})

// Usage example
const requestCtx = {
    userId: 'user123',
    ip: '192.168.1.100',
    method: 'POST',
    password: 'secret',
    headers: {'content-type': 'application/json'}
}

logger1.traceRequestPerformance(requestCtx, 150, 100) // Only logs userId, ip, method
logger2.traceRequestPerformance(requestCtx, 150, 100) // Excludes password field

Nested Field Path Support:

Both whitelist and blacklist processors support nested field paths using dot notation:

  • 'user.id' - matches ctx.user.id
  • 'request.headers.authorization' - matches ctx.request.headers.authorization
  • 'data.items[0].name' - matches ctx.data.items[0].name

Examples with nested paths:

// Include nested user fields only
const userLogger = new Logger({
    ctxProcessor: Logger.getCtxProcessor('whitelist', ['user.id', 'user.name', 'user.email'])
})

// Exclude nested sensitive data
const secureLogger = new Logger({
    ctxProcessor: Logger.getCtxProcessor('blacklist', ['user.password', 'auth.token', 'payment.cardNumber'])
})

Force Print Conditions (v1.3.0)

Force print conditions allow you to override log level restrictions for specific logs that match certain criteria. This is extremely useful for business debugging and troubleshooting in production environments.

Key Features:

  • ✅ Override log levels - logs matching conditions print regardless of configured log level
  • ✅ Function-based conditions - support complex logic and multiple criteria
  • ✅ Context information - access to level, message, and timestamp
  • ✅ Error-safe - individual condition failures don't break logging
  • ✅ Performance optimized - conditions only evaluated when log level filtering fails

Basic Usage:

const logger = new Logger({
    logLevel: 'error', // Only error+ levels normally print
    forcePrintConditions: [
        // Force print all logs containing 'payment'
        logData => logData.message.includes('payment'),
        // Force print all debug level login-related logs
        logData => logData.level === 'debug' && logData.message.includes('login')
    ]
})

// Usage examples:
logger.error('Payment processing failed') // ✅ Prints (level >= error)
logger.debug('User payment successful') // ✅ Prints (matches 'payment' condition)
logger.debug('User login successful') // ✅ Prints (debug + login condition)
logger.debug('Normal debug message') // ❌ Doesn't print (no matching condition)
logger.info('Normal info message') // ❌ Doesn't print (level < error)

Advanced Examples:

1. Time-window Based Conditions:

const logger = new Logger({
    logLevel: 'warn',
    forcePrintConditions: [
        // Force print all errors in the last 5 minutes
        logData => logData.level === 'error' && logData.timestamp > Date.now() - 5 * 60 * 1000,
        // Force print payment logs for next 1 hour
        logData => logData.message.includes('payment') && logData.timestamp < Date.now() + 60 * 60 * 1000
    ]
})

2. Complex Business Logic:

const logger = new Logger({
    logLevel: 'error',
    forcePrintConditions: [
        // Force print user authentication failures
        logData => logData.level === 'warn' && logData.message.match(/login.*fail|auth.*error/i),
        // Force print high-value transaction logs
        logData => {
            const msg = logData.message.toLowerCase()
            return msg.includes('transaction') && (msg.includes('amount:') || msg.includes('$'))
        },
        // Force print database errors with specific patterns
        logData => logData.level === 'error' && logData.message.includes('database') && logData.message.includes('timeout')
    ]
})

3. Environment-Based Conditions:

const isProduction = process.env.NODE_ENV === 'production'
const debugUserIds = process.env.DEBUG_USER_IDS?.split(',') || []

const logger = new Logger({
    logLevel: isProduction ? 'warn' : 'debug',
    forcePrintConditions: [
        // In production, force print logs for specific debug users
        ...(isProduction
            ? [
                  logData => {
                      const userIdMatch = logData.message.match(/user[_\s]+(\d+)/i)
                      return userIdMatch && debugUserIds.includes(userIdMatch[1])
                  }
              ]
            : [])
    ]
})

4. Performance Monitoring:

const logger = new Logger({
    logLevel: 'info',
    forcePrintConditions: [
        // Force print slow operations regardless of level
        logData => {
            const durationMatch = logData.message.match(/(\d+)ms/i)
            return durationMatch && parseInt(durationMatch[1]) > 1000 // > 1 second
        },
        // Force print memory warnings
        logData => logData.message.includes('memory') && logData.level === 'warn'
    ]
})

5. Service-Specific Debugging:

const logger = new Logger({
    logLevel: 'error',
    forcePrintConditions: [
        // Debug payment service issues
        logData => logData.message.includes('payment-service') && ['error', 'warn'].includes(logData.level),
        // Debug user session problems
        logData => logData.message.match(/session.*(?:expired|invalid|timeout)/i),
        // Debug API rate limiting
        logData => logData.message.includes('rate limit') || logData.message.includes('429')
    ]
})

Condition Function Parameters:

Each condition function receives a logData object with:

  • level: Log level ('fatal', 'error', 'warn', 'info', 'debug', 'trace')
  • message: Log message string
  • timestamp: Log timestamp (Date.now() format)

Best Practices:

  1. Keep conditions simple - Complex conditions can impact performance
  2. Use specific patterns - Avoid overly broad conditions that print too much
  3. Time-limit conditions - Use timestamps to automatically disable debug logging
  4. Monitor impact - Force printing can generate significant log volume
  5. Clean up - Remove or disable conditions when debugging is complete

Performance Notes:

  • Conditions are only evaluated when log level filtering would normally suppress the log
  • Failed condition functions are safely caught and don't break logging
  • Use efficient string operations (includes, startsWith) over complex regex when possible

Comparison with Other Logging Libraries

| Feature | Bandeng Logger | Winston | Pino | Log4js | Bunyan | | ----------------------------- | -------------- | ----------- | ----------- | ----------- | ----------- | | Log Rotation | ✅ Built-in | ❌ Plugin | ❌ Plugin | ✅ Built-in | ❌ Plugin | | Performance Monitor | ✅ Built-in | ❌ Plugin | ❌ Plugin | ❌ Plugin | ❌ Plugin | | PM2 Support | ✅ Built-in | ❌ Plugin | ❌ Plugin | ❌ Plugin | ❌ Plugin | | Zero-blocking I/O | ✅ Built-in | ❌ Plugin | ❌ Plugin | ❌ Plugin | ❌ Plugin | | High-precision Timestamps | ✅ Built-in | ❌ Plugin | ❌ Plugin | ❌ Plugin | ❌ Plugin | | Concurrent Safety | ✅ Built-in | ❌ Plugin | ❌ Plugin | ❌ Plugin | ❌ Plugin | | Real-time Statistics | ✅ Built-in | ❌ Plugin | ❌ Plugin | ❌ Plugin | ❌ Plugin | | Smart Buffering | ✅ Built-in | ❌ Plugin | ❌ Plugin | ❌ Plugin | ❌ Plugin | | Child logger | ✅ Built-in | ✅ Built-in | ✅ Built-in | ✅ Built-in | ✅ Built-in | | Color Console Output | ✅ Built-in | ❌ Plugin | ❌ Plugin | ✅ Built-in | ❌ Plugin | | Log Compression | ✅ Built-in | ❌ Plugin | ❌ Plugin | ✅ Built-in | ❌ Plugin | | UTC Timezone Support | ✅ Built-in | ❌ Plugin | ❌ Plugin | ❌ Plugin | ❌ Plugin | | Error Log Separation | ✅ Built-in | ❌ Plugin | ❌ Plugin | ❌ Plugin | ❌ Plugin | | Log Write Performance Monitor | ✅ Built-in | ❌ Plugin | ❌ Plugin | ❌ Plugin | ❌ Plugin |

API Reference

Logger Methods

  • fatal(message, ...args) - Log fatal error
  • error(message, ...args) - Log error
  • warn(message, ...args) - Log warning
  • info(message, ...args) - Log info
  • debug(message, ...args) - Log debug
  • trace(message, ...args) - Log trace

Child Logger Methods

  • createChildLogger(moduleName) - Create a child logger with module name prefix

Performance Monitoring Methods

  • traceRequestPerformance(ctx, latency, timeThreshold, [forcePrint], [tag]) - Advanced request performance tracking for internal RPC communication between services, with context sanitization and custom tags
  • Logger.getCtxProcessor(type, options) - Get predefined ctx processing functions for traceRequestPerformance
Ctx Processor Types
  • whitelist - Only include specified fields
  • blacklist - Exclude specified fields
  • rename - Rename fields using mapping object
  • transform - Complex transformation with include/exclude/rename
  • depthLimit - Limit object depth to prevent deep nesting
  • combine - Combine multiple processors

Configuration Methods

  • updateOptions(newOptions) - Update configuration at runtime with hot reloading
  • getOptions() - Get current configuration settings

Utility Methods

  • logHttpRequest(request, options) - Log HTTP request information (console output only)
  • getStatistics() - Get real-time logger statistics and metrics
  • resetStatistics() - Reset all statistics counters
  • flushBuffers() - Manually flush all buffered logs to disk (asynchronous)
  • destroy() - Clean up all resources (timers, file descriptors, buffers, queues) and stop the logger (asynchronous)

Static Methods

  • Logger.getCtxProcessor(type, options) - Get predefined ctx processing functions
Ctx Processor Types
  • whitelist - Only include specified fields
  • blacklist - Exclude specified fields
  • rename - Rename fields using mapping object
  • transform - Complex transformation with include/exclude/rename
  • depthLimit - Limit object depth to prevent deep nesting
  • combine - Combine multiple processors

Important Notes

Default Behaviors

  1. Log Directory: Defaults to ./logs (automatically created)
  2. Log Level: Defaults to 'warn' level
  3. Log Format: Defaults to 'json' format
  4. Timezone: Auto-detects server timezone (use utcFormat to override)
  5. Performance Monitoring: Disabled by default (set traceLogWrite: true to enable)
  6. Log Rotation: 100MB size limit, 1-hour check interval
  7. File Retention: Maximum 15 log files kept
  8. Buffer Settings: 64KB buffer, 1-second flush interval
  9. Error Separation: 'error' and 'fatal' levels separated by default

Operational Notes

  1. PM2 Support: Automatically adds process identifiers in PM2 environment
  2. Console Output: Warn level uses console.info to avoid PM2 color issues
  3. File Validation: Log filenames must end with .log extension
  4. Rotation Units: rotate parameter is in MB (e.g., 100 = 100MB)
  5. Interval Limits: Check interval must be 60 seconds to 7 days
  6. Buffer System: Zero-blocking I/O with synchronous API semantics
  7. High-Precision Timestamps: Millisecond precision prevents filename conflicts

Advanced Features

  1. Enhanced Error Handling: Automatic circular reference detection and prevention
  2. Concurrent Safety: Thread-safe operations with queue management
  3. Automatic File Management: Periodic cleanup and old file removal
  4. Process Lifecycle: Comprehensive signal handling and graceful shutdown
  5. Real-time Statistics: Built-in metrics and monitoring capabilities
  6. Smart Buffer Management: Dynamic thresholds and intelligent flushing
  7. Context Sanitization: Automatic content filtering and security protection
  8. Runtime Configuration: Hot reloading without service restart
  9. Request Performance Tracking: Advanced monitoring with context handling
  10. HTTP Request Logging: Framework-aware logging with automatic parameter extraction
  11. Smart IP Extraction: Intelligent parsing supporting multiple proxy headers

Parameter Rules

  1. Parameter Validation: First parameter must be string when using multiple arguments
  2. Parameter Limits: Maximum 2 parameters supported, extras are ignored
  3. Resource Management: Automatic cleanup prevents memory and file descriptor leaks
  4. Security Features: Path traversal protection and input sanitization
  5. Retry Mechanism: Intelligent retry with exponential backoff
  6. Memory Monitoring: Real-time tracking and leak prevention
  7. Unified Error Handling: Consistent error processing across all operations
  8. HTTP Request Logging: Framework-aware logging with automatic parameter extraction
  9. Smart IP Extraction: Intelligent parsing supporting multiple proxy headers

Smart IP Extraction

The HTTP request logger automatically extracts the real client IP address from multiple sources, supporting common proxy configurations:

Supported Headers (in priority order):
  • x-real-ip: Nginx real IP header
  • x-client-ip: Apache real IP header
  • x-forwarded-for: Standard proxy header (takes first IP)
  • cf-connecting-ip: Cloudflare real IP header
  • x-cluster-client-ip: Cluster client IP header
  • x-forwarded: RFC 7239 standard header
  • forwarded-for: Alternative forwarded header
  • forwarded: RFC 7239 complete header
Fallback Sources:
  1. Request object IP property (request.ip)
  2. Connection remote address (request.connection.remoteAddress)
  3. Socket remote address (request.socket.remoteAddress)
Filtering:
  • Automatically excludes local addresses (127.0.0.1, ::1, etc.)
  • Validates IPv4 and IPv6 address formats
  • Returns '-' if no valid IP is found

🚀 Version 1.3.11 updates (2026-03-07)

⚠️ BREAKING CHANGES - API Removal

This version includes breaking changes. Please read the migration guide below before upgrading.

  • 🗑️ Removed Methods: The following methods have been permanently removed from the Logger class:

    • logBeforeExit(error) - Process exit logging
    • logProcessStart(info) - Process startup logging
    • logPivotalInfo(taskname, info) - Pivotal business logging
  • 📋 Migration Guide:

    Before (v1.3.10 and earlier):

    const logger = new Logger()
    
    // Process startup logging
    logger.logProcessStart({version: '1.0.0', env: 'production'})
    
    // Process exit logging
    logger.logBeforeExit(new Error('Exit error'))
    
    // Pivotal business logging
    logger.logPivotalInfo('user_payment', {
        userId: 123,
        amount: 100,
        status: 'success'
    })

    After (v1.3.11+):

    const logger = new Logger()
    
    // Process startup logging - use standard info method
    logger.info('Process started', {version: '1.0.0', env: 'production'})
    
    // Process exit logging - use standard error/fatal method
    logger.fatal('Process exiting', {error: new Error('Exit error')})
    // Or with error details:
    logger.error('Process exit', {
        name: error.name,
        message: error.message,
        stack: error.stack
    })
    
    // Pivotal business logging - use standard info method with structured data
    logger.info('user_payment', {
        userId: 123,
        amount: 100,
        status: 'success'
    })

    Impact: If your code uses any of these removed methods, it will throw a TypeError: logger.methodName is not a function error. Please update your code before upgrading to v1.3.11.

  • 📝 Documentation Updates: Updated README.md to reflect API changes and removed all references to deprecated methods.

🐛 Bug Fixes

  • FileHandle Resource Leak Fix: Fixed issue where FileHandle objects were not properly closed, causing deprecation warnings during garbage collection. All FileHandle objects are now explicitly closed using .close() method instead of fs.close().

  • Concurrent File Splitting Fix: Enhanced file splitting mechanism with improved lock handling. Fixed race condition where multiple processes could simultaneously split the same log file, creating duplicate split files.

  • Concurrent File Cleanup Fix: Added file lock mechanism (.cleanup.lock) for file cleanup operations to prevent multiple processes from cleaning up files simultaneously, eliminating "File already deleted" warnings.

  • HTTP Request Logging Fix: Fixed response time formatting issue in logHttpRequest method.

    • Problem: When responseTime option was not provided or was null/undefined, the log output would incorrectly display nullms or undefinedms instead of a valid value.

    • Example of the bug:

      // Before fix - missing responseTime
      logger.logHttpRequest(ctx, {frameworkStyle: 'koa'})
      // Output: "2026-02-26 16:51:34.651 UTC+8 GET /api/users 200 nullms - 192.168.1.100 - 12345"
            
      // Before fix - responseTime is undefined
      logger.logHttpRequest(ctx, {frameworkStyle: 'koa', responseTime: undefined})
      // Output: "2026-02-26 16:51:34.651 UTC+8 GET /api/users 200 undefinedms - 192.168.1.100 - 12345"
    • Fix: Now properly validates and formats response time. When responseTime is null, undefined, or not provided, the log displays - instead of invalid values.

    • After fix:

      // Missing responseTime - now displays "-"
      logger.logHttpRequest(ctx, {frameworkStyle: 'koa'})
      // Output: "2026-02-26 16:51:34.651 UTC+8 GET /api/users 200 - - 192.168.1.100 - 12345"
            
      // Valid responseTime - displays correctly
      logger.logHttpRequest(ctx, {frameworkStyle: 'koa', responseTime: 125.68})
      // Output: "2026-02-26 16:51:34.651 UTC+8 GET /api/users 200 125.68ms - 192.168.1.100 - 12345"

中文

来自 Bandeng 开发团队的强大日志库。

安装

npm install bandeng-logger

使用方法

const Logger = require('bandeng-logger')

特性

  • 📝 多种日志级别 (fatal, error, warn, info, debug, trace)
  • 🔄 自动日志轮转,支持按大小和时间轮转
  • 🎨 彩色控制台输出,支持自定义颜色
  • 📊 内置性能监控,可追踪慢日志(需要显式启用)
  • 🎯 强制打印条件,支持选择性调试,无论日志级别如何
  • 🔍 支持多进程环境并跟踪进程 ID,支持并发轮转安全
  • 📦 支持日志压缩 (gzip)
  • 🏷️ 支持子日志记录器,便于模块化
  • ⚡ 零阻塞缓冲写入,保持同步语义
  • 🕒 高精度 UTC 时区支持,毫秒级时间戳
  • 📈 高级日志写入性能监控,带超时保护(需要显式启用)
  • 📋 支持 JSON 和文本两种日志格式
  • 🔒 可配置错误日志存储,支持自定义级别分离
  • 🕐 自定义日志轮转间隔和缓冲刷新时机
  • 🛡️ 增强的错误处理,支持循环引用检测和递归预防
  • 🧹 智能自动文件管理和并发清理
  • 📁 智能日志文件分割和大小限制执行
  • 🔧 全面的进程生命周期管理,支持信号处理
  • ✅ 高级配置验证,支持边界检查
  • 🚀 原子文件操作,支持并发安全
  • 📊 实时统计信息和监控
  • 🔄 智能缓冲管理,支持动态阈值
  • 🔮 现代 JavaScript 数据类型支持(BigInt、Symbol、Map、Set、TypedArray、Promise)
  • 🛡️ 序列化深度保护和内存泄漏预防
  • 🔒 上下文内容清理,带长度限制和安全过滤
  • ⚙️ 运行时配置更新,支持热重载
  • 📈 高级请求性能追踪,支持上下文处理
  • 🔧 可自定义的 ctx 字段处理,支持注入函数
  • 🛡️ 资源泄漏预防,支持自动流清理
  • 🚫 路径遍历保护,支持文件名清理
  • 🔄 智能重试机制,支持指数退避
  • 📊 实时内存使用监控和泄漏预防
  • 🎯 统一错误处理策略,跨所有操作
  • 🌐 HTTP 请求日志记录,支持框架自动识别
  • 🧠 智能 IP 提取,支持多种代理头
  • 📘 完整 TypeScript 支持,包含完整的类型定义

快速开始

基础用法

const Logger = require('bandeng-logger')
const logger = new Logger({logLevel: 'info', logFormat: 'text'})

logger.info('信息日志')
logger.error('错误日志')
logger.warn('警告日志')

const moduleLogger = logger.createChildLogger('UserModule')
moduleLogger.info('用户登录成功')

TypeScript 使用

// CommonJS 导入方式(推荐用于现有项目)
// 注意:当包发布后,使用:const Logger = require('bandeng-logger')
const Logger = require('./index') // 开发时使用相对路径

// 或者使用 ES6 模块导入
// import Logger from 'bandeng-logger'

// 类型定义(由于使用 CommonJS,需要手动声明类型)
type LogLevel = 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace'
type LogFormat = 'json' | 'text'
type FrameworkStyle = 'koa' | 'express'

interface LoggerOptions {
    logLevel?: LogLevel
    logFormat?: LogFormat
    logDir?: string
    rotate?: number
    maxFiles?: number
    traceLogWrite?: boolean
}

// 完整的类型安全配置
const loggerOptions: LoggerOptions = {
    logLevel: 'info' as LogLevel,
    logFormat: 'json' as LogFormat,
    logDir: './logs'
}

// 创建Logger实例
const logger = new Logger(loggerOptions)

// 所有方法都有完整的类型提示和注释
logger.info('TypeScript 信息日志')
logger.error('TypeScript 错误日志', {error: '出现错误'})
logger.debug('调试结构化数据', {userId: 123, action: 'login'})

// 静态方法也有类型提示
const ctxProcessor = Logger.getCtxProcessor('whitelist', ['userId', 'action'])

// 完整的类型安全和智能提示支持
const stats = logger.getStatistics()
const success = logger.updateOptions({logLevel: 'debug'})

基础配置示例

const Logger = require('bandeng-logger')

// 极简配置 - 使用所有默认值
const simpleLogger = new Logger()

// 或基础配置 - 基本自定义
const basicLogger = new Logger({
    logLevel: 'info',
    logFormat: 'json'
})

推荐生产配置

const Logger = require('bandeng-logger')
const config = require('./config.js')

// 创建生产就绪的日志记录器实例,只包含必要自定义配置
const defaultLogger = new Logger({
    // 必要的:根据环境动态设置日志级别
    logLevel: config.isTest ? 'trace' : 'warn',
    // 必要的:根据环境动态设置日志格式
    logFormat: config.isTest ? 'text' : 'json',

    // 自定义:根据需要调整日志轮转大小(默认100MB)
    rotate: 20, // 20MB而不是默认的100MB
    // 自定义:根据需要调整轮转检查间隔(默认1小时)
    interval: 600, // 10分钟而不是默认的1小时

    // 可选:启用性能监控(默认关闭)
    traceLogWrite: config.enablePerformanceMonitoring || false,

    // 可选:根据环境自定义颜色方案
    colors: {
        trace: 'gray',
        debug: 'blue',
        info: 'white',
        warn: config.isTest ? 'yellow' : 'white',
        error: 'red',
        fatal: 'magenta'
    },

    // 可选:自定义时区(默认自动检测)
    utcFormat: 8 // UTC+8时区

    // 注意:HTTP请求日志功能通过方法调用启用,无需配置
    // 使用 logger.logHttpRequest() 记录HTTP请求

    // 注意:以下使用默认值,无需指定:
    // logDir: './logs' (默认)
    // compress: 'none' (默认)
    // maxFiles: 15 (默认)
    // bufferSize: 65536 (默认)
    // flushInterval: 1000 (默认)
    // forceSyncLevels: ['fatal'] (默认)
    // ctxProcessor: null (默认)
})

// 导出日志工具
module.exports = {
    // 核心日志器实例
    logger: defaultLogger,

    // 应用必用的方法
    createChildLogger: defaultLogger.createChildLogger.bind(defaultLogger),
    traceRequestPerformance: defaultLogger.traceRequestPerformance.bind(defaultLogger),

    // HTTP请求日志(生产环境推荐使用)
    logHttpRequest: defaultLogger.logHttpRequest.bind(defaultLogger),

    // 配置管理(高级使用)
    getOptions: defaultLogger.getOptions.bind(defaultLogger),
    updateOptions: defaultLogger.updateOptions.bind(defaultLogger),

    // 运维监控
    getStatistics: defaultLogger.getStatistics.bind(defaultLogger),
    resetStatistics: defaultLogger.resetStatistics.bind(defaultLogger)
}

参数使用示例

// ✅ 单参数 - 支持任意类型
logger.info('简单消息')
logger.debug(42)
logger.warn({error: '出现错误', code: 500})

// ✅ 两参数 - 第一个必须是字符串,第二个可以是任意类型
logger.info('用户登录', {userId: 123, ip: '192.168.1.100'})
logger.debug('数据库查询', 'SELECT * FROM users WHERE id = ?')

// ✅ 复杂日志记录使用结构化数据
logger.info('支付处理完成', {
    transactionId: 'txn_123456',
    amount: 99.99,
    currency: 'CNY',
    userId: 456,
    timestamp: new Date(),
    metadata: {
        paymentMethod: 'alipay',
        gateway: 'stripe'
    }
})

// ❌ 避免 - 多个独立参数(多余参数会被忽略)
logger.debug('事件', '参数1', '参数2', '参数3') // 只处理前2个

// ❌ 避免 - 第一个参数不是字符串(会发出警告)
logger.debug(123, '这会产生警告')

参数传递规则详解

基本传参规则

  • 最多支持 2 个参数,超过 2 个参数将忽略多余参数
  • 1 个参数:支持任意类型,可以是字符串、数字、对象、数组等
  • 2 个参数:第一个参数必须为字符串类型,否则发出警告

如何传递多个值

当你需要记录多个相关值时,请将它们包装在一个对象中作为第二个参数:

// ✅ 推荐做法:将多个值包装在对象中
logger.debug('用户登录', {
    userId: 123,
    username: 'john_doe',
    ip: '192.168.1.100',
    timestamp: Date.now(),
    metadata: {source: 'web'}
})

// ❌ 避免做法:多个独立参数(会被忽略)
logger.debug('用户登录', 'john_doe', 123, '192.168.1.100') // 只处理前2个

// ✅ 单参数对象形式
logger.debug({
    event: 'user_login',
    userId: 123,
    username: 'john_doe',
    ip: '192.168.1.100'
})

JSON 格式 Object 类型特殊处理

重要说明:当使用 JSON 格式时,第二个参数的 Object 类型有特殊的处理规则:

展开规则

  • 对象展开:当第二个参数是普通对象(非数组、非 null、非 undefined)时,该对象的所有属性会被直接展开到日志对象中
  • 其他类型使用 msg 键:数组、字符串、数字、布尔值、null、undefined 等其他类型都会被赋值给msg字段

示例

// ✅ 对象会被展开 - 属性直接出现在日志根级别
logger.info('用户登录', {userId: 123, ip: '192.168.1.100'})
// 输出: {"time":"...", "level":"INFO", "tag":"用户登录", "userId":123, "ip":"192.168.1.100"}

// ✅ 数组使用msg键 - 保持数组结构
logger.debug('数据列表', [1, 2, 3, 4])
// 输出: {"time":"...", "level":"DEBUG", "tag":"数据列表", "msg":[1,2,3,4]}

// ✅ 字符串使用msg键
logger.warn('警告信息', '磁盘空间不足')
// 输出: {"time":"...", "level":"WARN", "tag":"警告信息", "msg":"磁盘空间不足"}

// ✅ 数字使用msg键
logger.error('错误码', 500)
// 输出: {"time":"...", "level":"ERROR", "tag":"错误码", "msg":500}

设计意图

这种设计允许:

  1. 结构化日志:对象展开提供更清晰的字段结构,便于日志分析和查询
  2. 向后兼容:数组和其他类型仍然使用msg键保持兼容性
  3. 类型安全:防止意外的属性覆盖,保持日志结构的清晰性

配置参数

| 参数 | 类型 | 默认值 | 说明 | | -------------------- | -------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | | logLevel | String | 'warn' | 日志级别,可选值:fatal, error, warn, info, debug, trace | | logFormat | String | 'json' | 日志格式,可选值:json, text | | utcFormat | Number | auto | UTC 时区,范围:-12 到 14。如果不传参则默认使用服务器当前时区 | | maxLength | Number | 1000 | 日志消息最大长度,超过会被截断 | | logDir | String | './logs' | 日志目录(会自动转换为绝对路径),如果不存在会自动创建 | | logFileName | String | 'server.log' | 主日志文件名,必须以 .log 结尾 | | errorLogFileName | String | 'error.log' | 错误日志文件名,必须以 .log 结尾,仅在 separateErrorLog 为 true 时生效 | | separateErrorLog | Boolean | true | 是否将错误日志分离到单独文件 | | separateErrorLevels | Array | ['error','fatal'] | 哪些日志级别需要分离到错误文件,可自定义 | | traceLogWrite | Boolean | false | 是否开启日志写入性能监控(默认关闭,必须显式设置为 true),开启后会记录写入耗时超过 100ms 的日志 | | rotate | Number | 100 | 日志轮转大小(MB)。超过此大小会触发日志轮转 | | interval | Number | 3600 | 日志轮转检查间隔(秒),最小 60 秒,最大 604800 秒(7 天) | | compress | String | 'none' | 日志压缩方式,可选值:none, gzip | | maxFiles | Number | 15 | 最大保留的日志文件数量,超过此数量会删除最旧的日志文件 | | bufferSize | Number | 65536 | 缓冲区大小(字节,64KB),最小 1024,最大 10MB | | flushInterval | Number | 1000 | 缓冲区刷新间隔(毫秒),最小 100,最大 60000 | | forceSyncLevels | Array | ['fatal'] | 哪些日志级别应该始终同步写入。可配置为 ['error', 'fatal'] 以确保 ERROR 和 FATAL 日志立即写入磁盘(适用于调试和崩溃场景)。 | | forcePrintConditions | Array | [] | 强制打印条件函数数组,符合条件的日志无论级别如何都会打印,适用于业务排查