Logging Middleware
Logging Middleware is a powerful middleware that automatically logs all repository operations including execution time, arguments, results, and error information. It provides detailed insights into your application's data access patterns and helps with debugging and monitoring.
Installation
npm install @unilab/urpc-core
Basic Usage
Default Console Logging
The simplest way to use logging middleware is with the default console logger:
import { Logging } from '@unilab/urpc-core/middleware';
const app = URPC.init({
middlewares: [Logging()],
});
Custom Logger Implementation
You can provide your own logging function for custom log formatting or integration with external logging services:
import { Logging } from '@unilab/urpc-core/middleware';
// Custom logger function
const customLogger = (message: string, context?: any) => {
const timestamp = new Date().toISOString();
console.log(`[${timestamp}] CUSTOM: ${message}`, context);
};
const app = URPC.init({
middlewares: [Logging(customLogger)],
});
Logger Function Signature
The logger function receives two parameters:
type LoggerFunction = (
message: string, // Formatted log message
context?: any // Additional context data
) => void;
Message Format
The middleware generates structured log messages:
- Start:
[{operation}] Starting operation
- Success:
[{operation}] Operation completed in {duration}ms
- Error:
[{operation}] Operation failed after {duration}ms
Context Data
The context object contains:
args
: Operation arguments passed to the repository methodresult
: Operation result (for successful operations)error
: Error object (for failed operations)
Advanced Usage Examples
File-Based Logging
class CustomLogger {
private logs: string[] = [];
log(message: string, context?: any): void {
const timestamp = new Date().toISOString();
const logEntry = `[${timestamp}] ${message}`;
if (context) {
console.log(logEntry, context);
this.logs.push(`${logEntry} ${JSON.stringify(context)}`);
} else {
console.log(logEntry);
this.logs.push(logEntry);
}
}
getLogs(): string[] {
return [...this.logs];
}
clear(): void {
this.logs = [];
}
}
const customLogger = new CustomLogger();
const customLoggingMiddleware = Logging((message, context) =>
customLogger.log(`CUSTOM: ${message}`, context)
);
const app = URPC.init({
middlewares: [customLoggingMiddleware],
});
Integration with External Logging Services
import winston from 'winston';
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' })
]
});
const winstonLoggingMiddleware = Logging((message, context) => {
if (context?.error) {
logger.error(message, context);
} else {
logger.info(message, context);
}
});
const app = URPC.init({
middlewares: [winstonLoggingMiddleware],
});
Conditional Logging
const conditionalLogger = (message: string, context?: any) => {
// Only log slow operations (> 1000ms)
if (message.includes('completed') || message.includes('failed')) {
const durationMatch = message.match(/(\d+)ms/);
const duration = durationMatch ? parseInt(durationMatch[1]) : 0;
if (duration > 1000) {
console.warn(`SLOW OPERATION: ${message}`, context);
}
} else {
console.log(message, context);
}
};
const conditionalLoggingMiddleware = Logging(conditionalLogger);
Performance Considerations
- Logging Overhead: The middleware adds minimal overhead, primarily from timing operations
- Context Serialization: Large result objects in context may impact performance
- Async Loggers: Ensure your custom logger handles async operations properly if needed
- Log Volume: Consider log rotation and cleanup for high-traffic applications
Best Practices
- Use Appropriate Log Levels: Implement log levels in your custom logger
- Sanitize Sensitive Data: Remove passwords, tokens, and PII from logged context
- Configure for Environment: Use different logging strategies for development vs production
- Monitor Log Volume: Implement log rotation and archival strategies
- Structure Your Logs: Use consistent log formats for easier parsing and analysis
- Handle Errors Gracefully: Ensure logging failures don't break your application
Troubleshooting
Common Issues
Logs Not Appearing: Ensure the middleware is registered before repository operations Performance Impact: Consider reducing context data or using async loggers Memory Usage: Implement log rotation for long-running applications
Debug Mode
For development, you can create a debug-specific logger:
const debugLogger = (message: string, context?: any) => {
if (process.env.NODE_ENV === 'development') {
console.debug(`[DEBUG] ${message}`, context);
}
};
const debugLoggingMiddleware = Logging(debugLogger);
Hook Middleware
Hook Middleware is a powerful middleware that allows you to hook into the URPC lifecycle and execute custom logic before and after CRUD operations. This enables you to implement cross-cutting concerns like validation, logging, caching, notifications, and more.
Global Adapters
A collection of adapters for URPC that provide different data storage solutions. Choose the right adapter for your development needs.