Custom prettifiers provide extensibility for formatting specific log properties with custom logic. They can be used to transform timestamps, levels, or any arbitrary property in the log object.
Custom prettifier functions follow a standard signature.
/**
* Custom prettifier function for specific log properties
* @param inputData - The value of the property being prettified
* @param key - The property name (useful when levelKey or messageKey is customized)
* @param log - The complete log object for context
* @param extras - Additional context including colors and level labels
* @returns Prettified string representation of the property
*/
type Prettifier = (
inputData: string | object,
key: string,
log: object,
extras: PrettifierExtras
) => string;
interface PrettifierExtras {
/**
* Colorette instance with color functions
* Colors are enabled based on colorize option
*/
colors: Colorette;
/**
* Derived level label string (for level prettifier only)
*/
label: string;
/**
* Derived level label with colors applied (for level prettifier only)
*/
labelColorized: string;
}Prettifiers are configured via the customPrettifiers option.
/**
* Hash of property names to prettifier functions
* Can prettify standard properties or arbitrary log properties
* Standard properties: time, level, hostname, pid, name, caller
*/
customPrettifiers?: Record<string, Prettifier> & {
level?: Prettifier;
};Usage Example:
const pinoPretty = require('pino-pretty');
const stream = pinoPretty({
customPrettifiers: {
time: (timestamp) => new Date(timestamp).toISOString(),
level: (logLevel, key, log, { labelColorized }) => {
return `[${labelColorized}]`;
},
hostname: (hostname) => `HOST:${hostname}`,
requestId: (id, key, log, { colors }) => {
return colors.cyan(`[${id}]`);
}
}
});Custom formatting for the timestamp field.
/**
* Prettifier for timestamp field
* @param timestamp - Timestamp value from log (usually number or string)
* @param key - The timestamp key name (usually 'time')
* @param log - Complete log object
* @param extras - Colors and other context
* @returns Formatted timestamp string
*/
time?: (timestamp: any, key: string, log: object, extras: PrettifierExtras) => string;Usage Examples:
// ISO format
customPrettifiers: {
time: (timestamp) => new Date(timestamp).toISOString()
}
// Output: 2023-12-09T15:30:45.123Z
// Custom format with emoji
customPrettifiers: {
time: (timestamp) => {
const date = new Date(timestamp);
return `π° ${date.toLocaleTimeString()}`;
}
}
// Output: π° 3:30:45 PM
// Relative time
customPrettifiers: {
time: (timestamp) => {
const now = Date.now();
const diff = now - timestamp;
return `${Math.floor(diff / 1000)}s ago`;
}
}
// Output: 5s ago
// Using colors
customPrettifiers: {
time: (timestamp, key, log, { colors }) => {
const date = new Date(timestamp).toISOString();
return colors.gray(date);
}
}Custom formatting for the log level with special extras.
/**
* Prettifier for level field
* @param logLevel - Level value (number or string)
* @param key - The level key name (usually 'level')
* @param log - Complete log object
* @param extras - Colors, label, and labelColorized
* @returns Formatted level string
*/
level?: (
logLevel: number | string,
key: string,
log: object,
extras: PrettifierExtras & { label: string; labelColorized: string }
) => string;Usage Examples:
// Wrap label in brackets
customPrettifiers: {
level: (logLevel, key, log, { labelColorized }) => {
return `[${labelColorized}]`;
}
}
// Output: [INFO] or [ERROR]
// Use numeric level
customPrettifiers: {
level: (logLevel) => {
return `LEVEL:${logLevel}`;
}
}
// Output: LEVEL:30
// Custom format with label and number
customPrettifiers: {
level: (logLevel, key, log, { label, colors }) => {
return colors.bold(`${label}(${logLevel})`);
}
}
// Output: INFO(30)
// Emoji indicators
customPrettifiers: {
level: (logLevel, key, log, { label }) => {
const emoji = {
TRACE: 'π',
DEBUG: 'π',
INFO: 'βΉοΈ',
WARN: 'β οΈ',
ERROR: 'β',
FATAL: 'π'
}[label] || 'π';
return `${emoji} ${label}`;
}
}
// Output: βΉοΈ INFOCustom formatting for hostname field.
/**
* Prettifier for hostname field
*/
hostname?: (hostname: string, key: string, log: object, extras: PrettifierExtras) => string;Usage Examples:
// Uppercase hostname
customPrettifiers: {
hostname: (hostname) => hostname.toUpperCase()
}
// Short hostname (remove domain)
customPrettifiers: {
hostname: (hostname) => hostname.split('.')[0]
}
// Decorated hostname
customPrettifiers: {
hostname: (hostname, key, log, { colors }) => {
return colors.dim(`@${hostname}`);
}
}Custom formatting for process ID field.
/**
* Prettifier for pid field
*/
pid?: (pid: number, key: string, log: object, extras: PrettifierExtras) => string;Usage Examples:
// Padded PID
customPrettifiers: {
pid: (pid) => String(pid).padStart(6, '0')
}
// Output: 001234
// PID with label
customPrettifiers: {
pid: (pid, key, log, { colors }) => {
return colors.gray(`[PID:${pid}]`);
}
}Custom formatting for logger name field.
/**
* Prettifier for name field
*/
name?: (name: string, key: string, log: object, extras: PrettifierExtras) => string;Usage Examples:
// Colored name
customPrettifiers: {
name: (name, key, log, { colors }) => {
return colors.blue(name);
}
}
// Uppercase name with brackets
customPrettifiers: {
name: (name) => `[${name.toUpperCase()}]`
}Custom formatting for caller field.
/**
* Prettifier for caller field
*/
caller?: (caller: string, key: string, log: object, extras: PrettifierExtras) => string;Usage Examples:
// Highlighted caller
customPrettifiers: {
caller: (caller, key, log, { colors }) => {
return colors.greenBright(caller);
}
}
// Short caller (filename only)
customPrettifiers: {
caller: (caller) => {
return caller.split('/').pop();
}
}Prettify any property in your log objects.
/**
* Prettifiers for custom properties
* Property name is the key, prettifier is the value
*/
customPrettifiers?: {
[propertyName: string]: Prettifier;
};Usage Examples:
const pinoPretty = require('pino-pretty');
const stream = pinoPretty({
customPrettifiers: {
// Format request ID
requestId: (id, key, log, { colors }) => {
return colors.cyan(`[REQ:${id}]`);
},
// Format user object
user: (user, key, log, { colors }) => {
if (typeof user === 'object') {
return `${colors.bold(user.name)} (ID:${user.id})`;
}
return String(user);
},
// Format duration
duration: (ms) => {
if (ms < 1000) return `${ms}ms`;
return `${(ms / 1000).toFixed(2)}s`;
},
// Format URL
url: (url, key, log, { colors }) => {
return colors.underline(url);
},
// Format database query
query: (query, key, log, { colors }) => {
// Pretty print SQL
return '\n' + colors.dim(query.replace(/\s+/g, ' ').trim());
},
// Format status code
statusCode: (code, key, log, { colors }) => {
if (code >= 500) return colors.red(code);
if (code >= 400) return colors.yellow(code);
if (code >= 300) return colors.cyan(code);
return colors.green(code);
}
}
});The extras.colors object provides Colorette functions.
/**
* Colorette instance provided in extras
* Colors are enabled based on colorize option
*/
interface Colorette {
// Text colors
black(str: string): string;
red(str: string): string;
green(str: string): string;
yellow(str: string): string;
blue(str: string): string;
magenta(str: string): string;
cyan(str: string): string;
white(str: string): string;
gray(str: string): string;
// Background colors
bgBlack(str: string): string;
bgRed(str: string): string;
bgGreen(str: string): string;
bgYellow(str: string): string;
bgBlue(str: string): string;
bgMagenta(str: string): string;
bgCyan(str: string): string;
bgWhite(str: string): string;
// Modifiers
bold(str: string): string;
dim(str: string): string;
italic(str: string): string;
underline(str: string): string;
inverse(str: string): string;
hidden(str: string): string;
strikethrough(str: string): string;
reset(str: string): string;
}Usage Examples:
customPrettifiers: {
userId: (id, key, log, { colors }) => {
// Combine multiple color functions
return colors.bold(colors.cyan(`USER:${id}`));
},
status: (status, key, log, { colors }) => {
// Conditional coloring
if (status === 'error') {
return colors.bgRed(colors.white(status.toUpperCase()));
}
return colors.green(status);
},
important: (value, key, log, { colors }) => {
// Multiple modifiers
return colors.underline(colors.bold(colors.red(value)));
}
}Comprehensive example with multiple prettifiers.
const pinoPretty = require('pino-pretty');
const stream = pinoPretty({
colorize: true,
customPrettifiers: {
// Standard properties
time: (timestamp, key, log, { colors }) => {
const date = new Date(timestamp);
return colors.gray(date.toISOString());
},
level: (logLevel, key, log, { label, colors }) => {
const emoji = {
TRACE: 'π', DEBUG: 'π', INFO: 'βΉοΈ',
WARN: 'β οΈ', ERROR: 'β', FATAL: 'π'
}[label] || 'π';
return `${emoji} ${colors.bold(label)}`;
},
hostname: (hostname, key, log, { colors }) => {
return colors.dim(`@${hostname.split('.')[0]}`);
},
pid: (pid, key, log, { colors }) => {
return colors.gray(`[${pid}]`);
},
// Custom properties
requestId: (id, key, log, { colors }) => {
return colors.cyan(`[${id}]`);
},
userId: (id, key, log, { colors }) => {
return colors.bold(`USER:${id}`);
},
duration: (ms, key, log, { colors }) => {
const formatted = ms < 1000 ? `${ms}ms` : `${(ms / 1000).toFixed(2)}s`;
const color = ms > 1000 ? colors.red : ms > 500 ? colors.yellow : colors.green;
return color(formatted);
},
statusCode: (code, key, log, { colors }) => {
if (code >= 500) return colors.bgRed(colors.white(` ${code} `));
if (code >= 400) return colors.yellow(code);
if (code >= 300) return colors.cyan(code);
return colors.green(code);
},
method: (method, key, log, { colors }) => {
const colorMap = {
GET: colors.blue,
POST: colors.green,
PUT: colors.yellow,
DELETE: colors.red,
PATCH: colors.magenta
};
const colorize = colorMap[method] || colors.white;
return colorize(method);
}
}
});Keep prettifiers fast and synchronous.
/**
* Best practices:
* - Keep prettifiers synchronous (no async/await)
* - Avoid expensive operations
* - Cache computed values when possible
* - Return strings, not objects
*/Examples:
// Good: Fast and synchronous
customPrettifiers: {
userId: (id) => `USER:${id}`
}
// Bad: Async operation (will cause issues)
customPrettifiers: {
userId: async (id) => {
const user = await fetchUser(id); // DON'T DO THIS
return user.name;
}
}
// Good: Use existing log data
customPrettifiers: {
userId: (id, key, log) => {
// Use other properties from log if available
return log.userName ? `${log.userName} (${id})` : `USER:${id}`;
}
}Handle missing or invalid data gracefully.
/**
* Prettifiers should handle edge cases:
* - Undefined or null values
* - Unexpected types
* - Missing properties
*/Examples:
customPrettifiers: {
user: (user, key, log, { colors }) => {
// Handle null/undefined
if (!user) return colors.gray('(anonymous)');
// Handle different types
if (typeof user === 'string') return user;
if (typeof user === 'number') return `USER:${user}`;
// Handle objects
if (typeof user === 'object') {
return user.name || user.id || colors.gray('(unknown)');
}
return String(user);
},
duration: (ms) => {
// Handle invalid numbers
if (typeof ms !== 'number' || isNaN(ms)) return '-';
if (ms < 1000) return `${ms}ms`;
return `${(ms / 1000).toFixed(2)}s`;
}
}