PrettyHandler
The PrettyHandler formats log output with proper indentation and structure, making nested objects and complex data much more readable. It works as a wrapper around other handlers and can be combined with ColorHandler for beautiful, colorized pretty output.
Features
- 🎨 Beautiful Formatting: Deep indentation for nested objects
- 🔧 Handler Wrapper: Works with any underlying handler (TextHandler, JSONHandler, ColorHandler)
- 📊 Smart Arrays: Optional compact mode for primitive arrays
- 🎯 Depth Control: Configurable maximum depth to prevent excessive nesting
- 🌈 Composable: Combine with ColorHandler for colorized pretty output
- ⚡ Multi-handler Support: Use in MultiHandler for different outputs
Basic Usage
With TextHandler
import { Logger, PrettyHandler, TextHandler, Any } from '@omdxp/jslog';
const logger = new Logger(
new PrettyHandler({
handler: new TextHandler()
})
);
logger.info('User data', Any('user', {
id: 123,
name: 'Alice',
profile: {
bio: 'Developer',
settings: {
theme: 'dark',
notifications: true
}
}
}));
With JSONHandler
import { Logger, PrettyHandler, JSONHandler, Any } from '@omdxp/jslog';
const logger = new Logger(
new PrettyHandler({
handler: new JSONHandler()
})
);
logger.info('API Response', Any('data', {
status: 200,
body: {
users: [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
]
}
}));
Combining with ColorHandler
For the best development experience, combine PrettyHandler with ColorHandler:
import { Logger, PrettyHandler, ColorHandler, Any } from '@omdxp/jslog';
const logger = new Logger(
new PrettyHandler({
handler: new ColorHandler(),
indent: 4
})
);
logger.info('Beautiful colorized output', Any('config', {
server: {
host: 'localhost',
port: 3000,
ssl: {
enabled: true,
cert: '/path/to/cert.pem'
}
},
database: {
host: 'db.example.com',
port: 5432
}
}));
Configuration Options
indent
Number of spaces for each indentation level (default: 2).
const logger = new Logger(
new PrettyHandler({
handler: new TextHandler(),
indent: 4 // Use 4 spaces instead of 2
})
);
maxDepth
Maximum depth for nested objects (default: 10). Objects deeper than this will show [Max depth reached].
const logger = new Logger(
new PrettyHandler({
handler: new TextHandler(),
maxDepth: 5
})
);
logger.info('Deep nesting', Any('data', {
l1: { l2: { l3: { l4: { l5: { l6: 'too deep' } } } } }
}));
// l6 will show as [Max depth reached]
compactArrays
Display primitive arrays in compact mode (default: false).
const logger = new Logger(
new PrettyHandler({
handler: new ColorHandler(),
compactArrays: true
})
);
logger.info('Tags', Any('tags', ['typescript', 'logging', 'nodejs']));
// Output: tags=[typescript, logging, nodejs]
logger.info('Numbers', Any('numbers', [1, 2, 3, 4, 5]));
// Output: numbers=[1, 2, 3, 4, 5]
// Complex arrays are still prettified
logger.info('Users', Any('users', [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
]));
// Each user object is formatted with indentation
Advanced Examples
MultiHandler: Pretty Console + Compact File
Log pretty output to console while keeping compact JSON for file processing:
import {
Logger,
MultiHandler,
PrettyHandler,
ColorHandler,
JSONHandler
} from '@omdxp/jslog';
import * as fs from 'fs';
const logger = new Logger(
new MultiHandler([
// Pretty colorized console output
new PrettyHandler({
handler: new ColorHandler(),
indent: 2
}),
// Compact JSON for file/processing
new JSONHandler({
writer: fs.createWriteStream('./app.log')
})
])
);
logger.info('Request processed', Any('request', {
method: 'POST',
path: '/api/users',
body: { name: 'Alice', email: 'alice@example.com' }
}));
Error Logging with Pretty Format
try {
throw new Error('Database connection failed');
} catch (err) {
logger.error('Operation failed', Err(err), Any('context', {
operation: 'query',
database: 'users_db',
attempts: 3,
lastAttempt: new Date()
}));
}
// Output will show:
// - Error message, name, and stack (prettified)
// - Context object with proper indentation
Groups with PrettyHandler
PrettyHandler properly tracks and displays group prefixes:
const appLogger = logger.withGroup('app');
appLogger.info('Application event', { event: 'startup' });
const dbLogger = appLogger.withGroup('database');
dbLogger.info('Database query', Any('query', {
sql: 'SELECT * FROM users WHERE active = true',
duration: 45,
params: []
}));
Output:
2025-11-05T18:56:11.489Z INFO Application event
app.event="startup"
2025-11-05T18:56:11.489Z INFO Database query
app.database.query:
{
duration: 45,
params: [],
sql: "SELECT * FROM users WHERE active = true"
}
Notice how groups are properly prefixed to attribute keys (app.event, app.database.query), making it easy to see the attribute hierarchy.
Development vs Production
Use PrettyHandler in development and compact handlers in production:
const isDev = process.env.NODE_ENV === 'development';
const logger = new Logger(
isDev
? new PrettyHandler({
handler: new ColorHandler(),
indent: 2
})
: new JSONHandler()
);
Child Loggers with Attributes
const childLogger = logger.with(
String('service', 'api'),
String('version', '1.0.0')
);
childLogger.info('Request processed', Any('request', {
id: 'req_123',
method: 'GET',
path: '/users/123',
response: {
status: 200,
body: {
id: 123,
name: 'Alice',
roles: ['admin', 'user']
}
}
}));
// All logs will include service and version attributes
// with proper formatting
Performance Considerations
- Development Only:
PrettyHandleradds formatting overhead. Use it in development but consider compact handlers for production. - Depth Limit: Set
maxDepthappropriately to avoid excessive processing of deeply nested structures. - MultiHandler: When using
MultiHandler, putPrettyHandlerfirst for console output and compact handlers for file/network logging.
How It Works
PrettyHandler is a wrapper handler that:
- Intercepts log records before they reach the underlying handler
- Prettifies all attribute values (recursively formatting objects and arrays)
- Passes the modified record to the wrapped handler
- Does NOT handle streams or output itself - that's the wrapped handler's job
This design makes it composable with any other handler:
// Works with TextHandler
new PrettyHandler({ handler: new TextHandler() })
// Works with JSONHandler
new PrettyHandler({ handler: new JSONHandler() })
// Works with ColorHandler
new PrettyHandler({ handler: new ColorHandler() })
// Works with FileHandler (via advanced handlers)
new PrettyHandler({ handler: new FileHandler({ filepath: './app.log' }) })
// Works in chains
new PrettyHandler({
handler: new BufferedHandler({
handler: new FileHandler({ filepath: './app.log' })
})
})
API Reference
Constructor
constructor(options: PrettyHandlerOptions)
Options
interface PrettyHandlerOptions {
handler: Handler; // Required: The underlying handler
indent?: number; // Optional: Spaces per indent (default: 2)
maxDepth?: number; // Optional: Max nesting depth (default: 10)
compactArrays?: boolean; // Optional: Compact primitive arrays (default: false)
}
Methods
enabled(level: Level): boolean- Delegates to wrapped handlerneedsSource(): boolean- Delegates to wrapped handlerhandle(record: Record): void- Prettifies and delegates to wrapped handlerwithAttrs(attrs: Attr[]): Handler- Returns new PrettyHandler with attributeswithGroup(name: string): Handler- Returns new PrettyHandler with groupclose(): Promise<void>- Closes wrapped handler if it supports closing
See Also
- ColorHandler - Add colors to your logs
- MultiHandler - Send logs to multiple destinations
- TextHandler - Text output format
- JSONHandler - JSON output format