Skip to main content

Logging Middleware

Structured logging for message processing with multiple output formats.

Installation​

npm install @saga-bus/middleware-logging

Basic Usage​

import { createLoggingMiddleware } from '@saga-bus/middleware-logging';

const bus = createBus({
transport,
store,
sagas: [{ definition: orderSaga }],
middleware: [
createLoggingMiddleware({
level: 'info',
}),
],
});

Configuration​

OptionTypeDefaultDescription
levelstring'info'Log level (debug, info, warn, error)
loggerLoggerconsoleCustom logger instance
formatstring'json'Output format (json, pretty)
includePayloadbooleanfalseInclude message payload
redactPathsstring[][]Paths to redact from logs
onLogfunction-Custom log handler

Full Configuration Example​

import { createLoggingMiddleware } from '@saga-bus/middleware-logging';
import pino from 'pino';

const logger = pino({
level: 'info',
transport: {
target: 'pino-pretty',
},
});

const loggingMiddleware = createLoggingMiddleware({
level: 'info',
logger,
format: 'json',
includePayload: true,
redactPaths: ['password', 'creditCard', 'ssn'],
});

Log Output​

Message Received​

{
"level": "info",
"time": "2024-01-15T10:30:00.000Z",
"event": "message.received",
"sagaName": "OrderSaga",
"messageType": "OrderSubmitted",
"correlationId": "order-123",
"messageId": "msg-456"
}

Message Processed​

{
"level": "info",
"time": "2024-01-15T10:30:00.100Z",
"event": "message.processed",
"sagaName": "OrderSaga",
"messageType": "OrderSubmitted",
"correlationId": "order-123",
"duration": 100,
"success": true
}

Message Failed​

{
"level": "error",
"time": "2024-01-15T10:30:00.200Z",
"event": "message.failed",
"sagaName": "OrderSaga",
"messageType": "OrderSubmitted",
"correlationId": "order-123",
"error": "PaymentDeclined",
"stack": "..."
}

Custom Logger Integration​

Pino​

import pino from 'pino';

const logger = pino({
level: process.env.LOG_LEVEL || 'info',
});

const middleware = createLoggingMiddleware({
logger: {
debug: (msg, data) => logger.debug(data, msg),
info: (msg, data) => logger.info(data, msg),
warn: (msg, data) => logger.warn(data, msg),
error: (msg, data) => logger.error(data, msg),
},
});

Winston​

import winston from 'winston';

const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [new winston.transports.Console()],
});

const middleware = createLoggingMiddleware({
logger: {
debug: (msg, data) => logger.debug(msg, data),
info: (msg, data) => logger.info(msg, data),
warn: (msg, data) => logger.warn(msg, data),
error: (msg, data) => logger.error(msg, data),
},
});

Sensitive Data Redaction​

Automatically redact sensitive fields:

const middleware = createLoggingMiddleware({
includePayload: true,
redactPaths: [
'password',
'creditCard.number',
'creditCard.cvv',
'user.ssn',
'headers.authorization',
],
});

// Input
{
"orderId": "123",
"creditCard": {
"number": "4111111111111111",
"cvv": "123"
}
}

// Output (logged)
{
"orderId": "123",
"creditCard": {
"number": "[REDACTED]",
"cvv": "[REDACTED]"
}
}

Conditional Logging​

Log only certain message types:

const middleware = createLoggingMiddleware({
shouldLog: (context) => {
// Skip health check messages
if (context.messageType === 'HealthCheck') {
return false;
}
return true;
},
});

Best Practices​

Use Structured Logging​

// Good - structured data
logger.info('Order processed', {
orderId: '123',
amount: 99.99,
duration: 150,
});

// Avoid - string interpolation
logger.info(`Order ${orderId} processed for $${amount}`);

Set Appropriate Log Levels​

// Production
createLoggingMiddleware({ level: 'info' });

// Development
createLoggingMiddleware({ level: 'debug' });

Avoid Logging Sensitive Data​

createLoggingMiddleware({
includePayload: false, // Default, safest option
// Or use redaction
redactPaths: ['password', 'token', 'creditCard'],
});

See Also​