Pino
High-performance structured logging with Pino
Logixlysia can integrate with Pino, a high-performance JSON-first logging library, as an optional logging backend.
Why Pino?
- High Performance - One of the fastest Node.js loggers available
- Structured Logging - JSON-first approach for better log parsing
- Production Ready - Battle-tested in production environments
- Flexible - Extensive configuration options and transport support
Basic Usage
In Elysia Routes
Access Pino through the store in your route handlers:
app.get('/users/:id', ({ store, params }) => {
const { pino } = store
pino.info({
userId: params.id,
action: 'view_profile'
}, 'User profile accessed')
return { user: 'data' }
})Outside Elysia Routes (Standalone)
Use Pino in services, background jobs, or any code outside of HTTP request context:
// logger.ts
import logixlysia from 'logixlysia'
export const logixlysiaIns = logixlysia({
config: {
logFilePath: './logs/app.log',
pino: {
level: 'info',
base: {
service: 'my-api',
version: '1.0.0'
}
}
}
})
// Export Pino instance for standalone use
export const logger = logixlysiaIns.store.pino// services/order.service.ts
import { logger } from '../logger'
export class OrderService {
async processOrder(orderId: string) {
logger.info({ orderId }, 'Processing order')
try {
// ... business logic
logger.info({ orderId }, 'Order processed successfully')
} catch (error) {
logger.error({ orderId, error }, 'Order processing failed')
throw error
}
}
}// index.ts
import { Elysia } from 'elysia'
import { logixlysiaIns } from './logger'
import { OrderService } from './services/order.service'
const orderService = new OrderService()
new Elysia()
.use(logixlysiaIns)
.post('/orders/:id/process', async ({ params }) => {
await orderService.processOrder(params.id)
return { success: true }
})
.listen(3000)Note: When using Pino outside of routes, you won't have access to HTTP context (method, pathname, IP, etc.). For HTTP request logging, use store.logger inside route handlers.
Configuration
Log Level
logixlysia({
config: {
pino: {
level: 'debug' // 'fatal', 'error', 'warn', 'info', 'debug', 'trace'
}
}
})Pretty Printing
logixlysia({
config: {
pino: {
prettyPrint: true
}
}
})Or with custom options:
logixlysia({
config: {
pino: {
prettyPrint: {
colorize: true,
translateTime: 'HH:MM:ss Z',
ignore: 'pid,hostname'
}
}
}
})Redacting Sensitive Data
logixlysia({
config: {
pino: {
redact: ['password', 'token', 'apiKey']
}
}
})Or with paths:
logixlysia({
config: {
pino: {
redact: {
paths: ['user.password', 'req.headers.authorization'],
remove: true
}
}
}
})Base Fields
logixlysia({
config: {
pino: {
base: {
service: 'my-api',
version: '1.0.0',
environment: process.env.NODE_ENV
}
}
}
})Pino Transports
Pino supports its own transport system for advanced logging destinations. You can configure Pino transports using the transport option:
logixlysia({
config: {
pino: {
transport: {
target: 'pino/file',
options: {
destination: './logs/pino-example.log'
}
}
}
}
})Important: Pino transports are separate from Logixlysia's transport system:
- Pino transports (
pino.transport) - Only affect logs written throughstore.pino.info(),store.pino.error(), etc. - Logixlysia transports (
config.transports) - Only affect Logixlysia's internal HTTP request logging
For example:
logixlysia({
config: {
// Pino transport - only for store.pino.* logs
pino: {
transport: {
target: 'pino/file',
options: {
destination: './logs/pino-example.log'
}
}
},
// Logixlysia transports - only for HTTP request logs
transports: [customTransport]
}
})
app.get('/example', ({ store }) => {
// This log goes to pino/file transport
store.pino.info({ feature: 'pino' }, 'pino log example')
// HTTP request logs go to Logixlysia transports (if configured)
// or to console/file based on logixlysia config
})This separation allows you to:
- Use Pino transports for structured application logs (
store.pino.*) - Use Logixlysia transports for HTTP request/response logs
- Configure different destinations for different log types
Advanced Usage
Structured Logging
app.get('/users/:id', ({ store, params }) => {
const { pino } = store
pino.info({
userId: params.id,
action: 'view_profile',
timestamp: Date.now()
}, 'User profile viewed')
return user
})Child Loggers
Create child loggers with context:
app.get('/api/orders/:id', ({ store, params }) => {
const { pino } = store
const orderLogger = pino.child({
orderId: params.id,
module: 'order-service'
})
orderLogger.info('Fetching order details')
orderLogger.debug({ query: 'SELECT * FROM orders WHERE id = ?' })
return order
})Performance Logging
app.post('/api/process', async ({ store, body }) => {
const { pino } = store
const startTime = Date.now()
const result = await processData(body)
pino.info({
operation: 'process_data',
duration: Date.now() - startTime,
itemsProcessed: result.count,
success: true
}, 'Data processing completed')
return result
})Error Logging
app.get('/api/risky', ({ store }) => {
const { pino } = store
try {
performRiskyOperation()
} catch (error) {
pino.error({
err: error,
operation: 'risky_operation'
}, 'Operation failed')
throw error
}
})Environment-based Configuration
const isDev = process.env.NODE_ENV === 'development'
logixlysia({
config: {
pino: {
level: isDev ? 'debug' : 'info',
prettyPrint: isDev,
redact: isDev ? [] : ['password', 'token', 'apiKey'],
base: {
service: 'my-api',
environment: process.env.NODE_ENV
}
}
}
})Best Practices
-
Use Structured Logging - Pass objects instead of string interpolation
// ✅ Good pino.info({ userId: 123, action: 'login' }, 'User logged in') // ❌ Avoid pino.info(`User ${userId} logged in`) -
Create Child Loggers - For scoped logging with context
const requestLogger = pino.child({ requestId: generateId() }) -
Log Performance Metrics - Track important metrics
pino.info({ duration: 150, operation: 'db_query' }, 'Query completed') -
Redact Sensitive Data - Always redact sensitive information
logixlysia({ config: { pino: { redact: ['password', 'token', 'apiKey'] } } }) -
Use Appropriate Log Levels - Follow log level guidelines
fatal- Application is about to crasherror- Error that needs attentionwarn- Warning but application continuesinfo- General information (default)debug- Detailed debugging informationtrace- Very detailed debugging
-
Environment-based Configuration - Configure differently per environment
const isDev = process.env.NODE_ENV === 'development' logixlysia({ config: { pino: { level: isDev ? 'debug' : 'info', prettyPrint: isDev } } }) -
Export Pino for Standalone Use - Use in services, jobs, and utilities
// logger.ts export const logger = logixlysiaIns.store.pino // services/user.service.ts import { logger } from '../logger' logger.info({ userId }, 'User updated')