Super fast, all natural JSON logger with exceptional performance for structured logging applications.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Browser-compatible logging with console output and transmit functionality for client-side applications. Pino provides a browser-specific build that maintains API compatibility while adapting to browser constraints.
Use Pino in browser environments with console output and optional remote logging.
/**
* Create a browser-compatible logger instance
* @param options - Browser-specific logger options
* @returns Logger instance optimized for browser use
*/
function pino(options?: BrowserLoggerOptions): Logger;
interface BrowserLoggerOptions extends LoggerOptions {
/** Browser-specific configuration */
browser?: BrowserOptions;
}Usage Examples:
// Basic browser logger
const logger = pino();
logger.info('Hello from browser'); // Outputs to console
// Browser logger with custom options
const logger = pino({
name: 'my-web-app',
level: 'debug',
browser: {
asObject: true,
transmit: {
level: 'error',
send: (level, logEvent) => {
// Send errors to monitoring service
fetch('/api/logs', {
method: 'POST',
body: JSON.stringify(logEvent)
});
}
}
}
});Configure browser-specific behavior and output formatting.
interface BrowserOptions {
/** Create log objects instead of calling console methods directly */
asObject?: boolean;
/** Keep message formatting for deferred console rendering */
asObjectBindingsOnly?: boolean;
/** Custom write functions for different log levels */
write?: WriteFn | { [level: string]: WriteFn };
/** Enable serializers in browser (disabled by default) */
serialize?: boolean | string[];
/** Disable browser logging entirely */
disabled?: boolean;
/** Browser-specific formatters */
formatters?: {
level?: (label: string, number: number) => object;
log?: (object: Record<string, unknown>) => Record<string, unknown>;
};
/** Remote log transmission configuration */
transmit?: {
level?: string;
send: (level: string, logEvent: LogEvent) => void;
};
}
type WriteFn = (obj: object) => void;Output structured log objects instead of formatted strings.
interface BrowserOptions {
/** Create pino-like log objects instead of console calls */
asObject?: boolean;
}Usage Examples:
// Default console output
const logger = pino();
logger.info('Hello world'); // → console.info('Hello world')
// Object mode
const logger = pino({
browser: {
asObject: true
}
});
logger.info('Hello world');
// → console.info({msg: 'Hello world', level: 30, time: 1531171074631})
// With additional data
logger.info({ userId: 123 }, 'User action');
// → console.info({msg: 'User action', level: 30, time: 1531171074631, userId: 123})Preserve message formatting for better browser devtools rendering.
interface BrowserOptions {
/** Keep messages unformatted for better browser devtools display */
asObjectBindingsOnly?: boolean;
}Usage Examples:
const logger = pino({
browser: {
asObjectBindingsOnly: true
}
});
logger.info('hello %s', 'world');
// → console.info({level: 30, time: 1531171074631}, 'hello %s', 'world')
// Browser devtools will format 'hello world' with proper stylingOverride default console methods with custom write functions.
interface BrowserOptions {
/** Custom write functions */
write?: WriteFn | { [level: string]: WriteFn };
}Usage Examples:
// Single write function for all levels
const logger = pino({
browser: {
write: (obj) => {
// Custom logging implementation
const logEntry = {
timestamp: new Date().toISOString(),
level: obj.level,
message: obj.msg,
data: obj
};
// Send to custom logging service
window.customLogger.log(logEntry);
}
}
});
// Level-specific write functions
const logger = pino({
browser: {
write: {
info: (obj) => {
console.log('INFO:', obj);
},
error: (obj) => {
console.error('ERROR:', obj);
// Also send errors to error tracking
window.errorTracker.captureError(obj);
},
debug: (obj) => {
// Only log debug in development
if (process.env.NODE_ENV === 'development') {
console.debug('DEBUG:', obj);
}
}
}
}
});Control which serializers are active in browser environments.
interface BrowserOptions {
/** Enable serializers (disabled by default in browser) */
serialize?: boolean | string[];
}Usage Examples:
// Enable all serializers
const logger = pino({
serializers: {
error: (err) => ({
name: err.name,
message: err.message,
stack: err.stack
})
},
browser: {
serialize: true
}
});
// Enable specific serializers
const logger = pino({
serializers: {
req: reqSerializer,
res: resSerializer,
err: errSerializer
},
browser: {
serialize: ['err'] // Only error serializer active
}
});
// Explicitly disable standard error serializer
const logger = pino({
browser: {
serialize: ['!stdSerializers.err', 'custom']
}
});Send browser logs to remote endpoints for centralized logging.
interface BrowserOptions {
/** Remote transmission configuration */
transmit?: {
level?: string;
send: (level: string, logEvent: LogEvent) => void;
};
}
interface LogEvent {
/** Timestamp when log method was called */
ts: number;
/** Array of arguments passed to log method */
messages: any[];
/** Child logger bindings hierarchy */
bindings: Bindings[];
/** Log level information */
level: {
label: string;
value: number;
};
}Usage Examples:
// Basic remote logging
const logger = pino({
browser: {
transmit: {
level: 'error',
send: (level, logEvent) => {
fetch('/api/logs', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
level,
timestamp: logEvent.ts,
messages: logEvent.messages,
bindings: logEvent.bindings
})
}).catch(console.error);
}
}
}
});
// Advanced transmission with batching
const logger = pino({
browser: {
transmit: {
level: 'warn',
send: (() => {
const logBuffer = [];
let sendTimer;
return (level, logEvent) => {
logBuffer.push({ level, logEvent, timestamp: Date.now() });
// Batch send every 5 seconds or on critical errors
if (level === 'fatal' || level === 'error') {
sendLogs();
} else {
clearTimeout(sendTimer);
sendTimer = setTimeout(sendLogs, 5000);
}
};
function sendLogs() {
if (logBuffer.length === 0) return;
fetch('/api/logs/batch', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(logBuffer.splice(0))
}).catch(console.error);
}
})()
}
}
});Integrate with browser error tracking services.
Usage Examples:
// Sentry integration
const logger = pino({
browser: {
transmit: {
level: 'error',
send: (level, logEvent) => {
if (typeof Sentry !== 'undefined') {
Sentry.captureMessage(logEvent.messages[0], level);
// Add context from bindings
logEvent.bindings.forEach(binding => {
Sentry.setContext('logger', binding);
});
}
}
}
}
});
// Google Analytics event tracking
const logger = pino({
browser: {
transmit: {
level: 'info',
send: (level, logEvent) => {
if (typeof gtag !== 'undefined' && level === 'info') {
// Track important events
if (logEvent.messages[0].includes('user_action')) {
gtag('event', 'user_action', {
event_category: 'engagement',
event_label: logEvent.messages[0]
});
}
}
}
}
}
});Store logs locally for offline scenarios.
Usage Examples:
const logger = pino({
browser: {
write: {
error: (obj) => {
// Always show errors in console
console.error(obj);
// Store errors locally
try {
const errors = JSON.parse(localStorage.getItem('app_errors') || '[]');
errors.push({
...obj,
timestamp: Date.now(),
url: window.location.href,
userAgent: navigator.userAgent
});
// Keep only last 50 errors
if (errors.length > 50) {
errors.splice(0, errors.length - 50);
}
localStorage.setItem('app_errors', JSON.stringify(errors));
} catch (e) {
console.warn('Failed to store error in localStorage:', e);
}
}
}
}
});
// Function to retrieve stored errors
function getStoredErrors() {
try {
return JSON.parse(localStorage.getItem('app_errors') || '[]');
} catch (e) {
return [];
}
}
// Function to send stored errors when online
function syncStoredErrors() {
const errors = getStoredErrors();
if (errors.length > 0) {
fetch('/api/logs/sync', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(errors)
}).then(() => {
localStorage.removeItem('app_errors');
}).catch(console.error);
}
}Configure different behaviors for development and production builds.
Usage Examples:
function createBrowserLogger() {
const isDevelopment = process.env.NODE_ENV === 'development';
return pino({
level: isDevelopment ? 'debug' : 'warn',
browser: {
asObject: isDevelopment, // Objects in dev, formatted in prod
disabled: false,
transmit: isDevelopment ? undefined : {
level: 'error',
send: (level, logEvent) => {
// Only transmit in production
fetch('/api/logs', {
method: 'POST',
body: JSON.stringify(logEvent)
});
}
},
write: isDevelopment ? undefined : {
// Custom production logging
error: (obj) => {
console.error(obj);
// Track errors in production
window.analytics?.track('error', obj);
}
}
}
});
}
const logger = createBrowserLogger();Custom formatting for log levels and objects in browser environments.
interface BrowserOptions {
/** Browser-specific formatting functions */
formatters?: {
/** Changes the shape of the log level in browser output */
level?: (label: string, number: number) => object;
/** Changes the shape of the log object in browser output */
log?: (object: Record<string, unknown>) => Record<string, unknown>;
};
}Usage Examples:
// Custom level formatting
const logger = pino({
browser: {
formatters: {
level: (label, number) => {
return {
severity: label.toUpperCase(),
levelNum: number,
timestamp: Date.now()
};
},
log: (object) => {
// Add browser-specific context
return {
...object,
userAgent: navigator.userAgent,
url: window.location.href,
viewport: {
width: window.innerWidth,
height: window.innerHeight
}
};
}
}
}
});
logger.info({ action: 'page_load' }, 'Page loaded');
// Output includes custom formatting with browser contextMinimize browser bundle size when using Pino.
Usage Examples:
// Import only what you need
import pino from 'pino/browser';
// Or use a custom build
const logger = pino({
browser: {
// Disable features not needed in browser
serialize: false,
disabled: process.env.NODE_ENV === 'test'
}
});
// Tree-shake unused features in webpack
module.exports = {
resolve: {
alias: {
'pino': 'pino/browser'
}
}
};Install with Tessl CLI
npx tessl i tessl/npm-pino