bandeng-logger
v1.3.11
Published
Logger from bandeng developer team.
Maintainers
Readme
Bandeng Logger
English
A powerful logging library from Bandeng developer team.
Installation
npm install bandeng-loggerUsage
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
msgfield
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:
- Structured Logging: Object expansion provides clearer field structure for log analysis and querying
- Backward Compatibility: Arrays and other types still use
msgkey for compatibility - 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 filteringContext 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 serializedAutomatic 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
uncaughtExceptionevents - 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)
- Logger automatically registers a handler for
Automatic ERROR Logging for
unhandledRejection:- Logger automatically registers a handler for
unhandledRejectionevents - 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)
- Logger automatically registers a handler for
Automatic FATAL Logging for
process.exit:- Logger automatically registers a handler for
process.exitevents - 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
- Logger automatically registers a handler for
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:
Timer-Based Periodic Check: Logger uses a timer-based mechanism (not real-time file size monitoring). A periodic check is scheduled using
setIntervalthat runs everyintervalseconds (default: 3600 seconds / 1 hour, configurable viaintervaloption). The check also runs immediately when the logger is initialized.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
rotateoption). If the file size is below the threshold, no splitting occurs even though the check runs.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
finallyblock, 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
- Uses a lock file (
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
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
Old File Cleanup:
- After splitting, checks total number of log files
- Deletes oldest files if count exceeds
maxFileslimit (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 operationsConfiguration:
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
rotateoption 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
intervalvalue (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 - 12345Format 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 loggedDatabase 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 fieldNested Field Path Support:
Both whitelist and blacklist processors support nested field paths using dot notation:
'user.id'- matchesctx.user.id'request.headers.authorization'- matchesctx.request.headers.authorization'data.items[0].name'- matchesctx.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 stringtimestamp: Log timestamp (Date.now() format)
Best Practices:
- Keep conditions simple - Complex conditions can impact performance
- Use specific patterns - Avoid overly broad conditions that print too much
- Time-limit conditions - Use timestamps to automatically disable debug logging
- Monitor impact - Force printing can generate significant log volume
- 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 errorerror(message, ...args)- Log errorwarn(message, ...args)- Log warninginfo(message, ...args)- Log infodebug(message, ...args)- Log debugtrace(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 tagsLogger.getCtxProcessor(type, options)- Get predefined ctx processing functions for traceRequestPerformance
Ctx Processor Types
whitelist- Only include specified fieldsblacklist- Exclude specified fieldsrename- Rename fields using mapping objecttransform- Complex transformation with include/exclude/renamedepthLimit- Limit object depth to prevent deep nestingcombine- Combine multiple processors
Configuration Methods
updateOptions(newOptions)- Update configuration at runtime with hot reloadinggetOptions()- Get current configuration settings
Utility Methods
logHttpRequest(request, options)- Log HTTP request information (console output only)getStatistics()- Get real-time logger statistics and metricsresetStatistics()- Reset all statistics countersflushBuffers()- 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 fieldsblacklist- Exclude specified fieldsrename- Rename fields using mapping objecttransform- Complex transformation with include/exclude/renamedepthLimit- Limit object depth to prevent deep nestingcombine- Combine multiple processors
Important Notes
Default Behaviors
- Log Directory: Defaults to
./logs(automatically created) - Log Level: Defaults to
'warn'level - Log Format: Defaults to
'json'format - Timezone: Auto-detects server timezone (use
utcFormatto override) - Performance Monitoring: Disabled by default (set
traceLogWrite: trueto enable) - Log Rotation: 100MB size limit, 1-hour check interval
- File Retention: Maximum 15 log files kept
- Buffer Settings: 64KB buffer, 1-second flush interval
- Error Separation:
'error'and'fatal'levels separated by default
Operational Notes
- PM2 Support: Automatically adds process identifiers in PM2 environment
- Console Output: Warn level uses
console.infoto avoid PM2 color issues - File Validation: Log filenames must end with
.logextension - Rotation Units:
rotateparameter is in MB (e.g., 100 = 100MB) - Interval Limits: Check interval must be 60 seconds to 7 days
- Buffer System: Zero-blocking I/O with synchronous API semantics
- High-Precision Timestamps: Millisecond precision prevents filename conflicts
Advanced Features
- Enhanced Error Handling: Automatic circular reference detection and prevention
- Concurrent Safety: Thread-safe operations with queue management
- Automatic File Management: Periodic cleanup and old file removal
- Process Lifecycle: Comprehensive signal handling and graceful shutdown
- Real-time Statistics: Built-in metrics and monitoring capabilities
- Smart Buffer Management: Dynamic thresholds and intelligent flushing
- Context Sanitization: Automatic content filtering and security protection
- Runtime Configuration: Hot reloading without service restart
- Request Performance Tracking: Advanced monitoring with context handling
- HTTP Request Logging: Framework-aware logging with automatic parameter extraction
- Smart IP Extraction: Intelligent parsing supporting multiple proxy headers
Parameter Rules
- Parameter Validation: First parameter must be string when using multiple arguments
- Parameter Limits: Maximum 2 parameters supported, extras are ignored
- Resource Management: Automatic cleanup prevents memory and file descriptor leaks
- Security Features: Path traversal protection and input sanitization
- Retry Mechanism: Intelligent retry with exponential backoff
- Memory Monitoring: Real-time tracking and leak prevention
- Unified Error Handling: Consistent error processing across all operations
- HTTP Request Logging: Framework-aware logging with automatic parameter extraction
- 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 headerx-client-ip: Apache real IP headerx-forwarded-for: Standard proxy header (takes first IP)cf-connecting-ip: Cloudflare real IP headerx-cluster-client-ip: Cluster client IP headerx-forwarded: RFC 7239 standard headerforwarded-for: Alternative forwarded headerforwarded: RFC 7239 complete header
Fallback Sources:
- Request object IP property (
request.ip) - Connection remote address (
request.connection.remoteAddress) - 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 logginglogProcessStart(info)- Process startup logginglogPivotalInfo(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 functionerror. 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 offs.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
logHttpRequestmethod.Problem: When
responseTimeoption was not provided or wasnull/undefined, the log output would incorrectly displaynullmsorundefinedmsinstead 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
responseTimeisnull,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}设计意图
这种设计允许:
- 结构化日志:对象展开提供更清晰的字段结构,便于日志分析和查询
- 向后兼容:数组和其他类型仍然使用
msg键保持兼容性 - 类型安全:防止意外的属性覆盖,保持日志结构的清晰性
配置参数
| 参数 | 类型 | 默认值 | 说明 |
| -------------------- | -------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| 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 | [] | 强制打印条件函数数组,符合条件的日志无论级别如何都会打印,适用于业务排查
