@empe/logger v2.1.0
@empe/logger
A flexible and configurable logging utility for Node.js applications based on Winston, providing structured logging with environment-specific formatting, log rotation, and sensitive data redaction.
Overview
This package provides a standardized logging solution for the Empe ecosystem, making it easy to implement consistent logging across different services and applications. It's built on top of Winston, one of the most popular logging libraries for Node.js.
Features
- Environment-aware formatting: Different log formats for development and production environments
- Log rotation: Automatic daily log file rotation with compression
- Sensitive data redaction: Automatic redaction of sensitive information like passwords and tokens
- Multiple transports: Console output and file logging
- Exception handling: Dedicated exception logging
- Configurable log levels: Support for standard Winston log levels
- Structured metadata: Support for structured metadata in log entries
Installation
npm install @empe/logger
# or
yarn add @empe/logger
Usage
Basic Usage
import { createLoggerInstance, LogLevelEnum } from '@empe/logger';
// Create a logger for your application
const logger = createLoggerInstance(
'MyApp', // Application name
'development', // Node environment
LogLevelEnum.DEBUG // Log level
);
// Use the logger
logger.info('Application started');
logger.debug('Debug information', { userId: 123, action: 'login' });
logger.error('An error occurred', { error: new Error('Something went wrong') });
Integration with Environment Variables
Typically, you'll want to configure the logger based on environment variables:
import { createLoggerInstance, LogLevelEnum } from '@empe/logger';
const nodeEnv = (process.env.NODE_ENV || 'development') as 'development' | 'production' | 'test';
const logLevel = (process.env.LOG_LEVEL || LogLevelEnum.INFO) as LogLevelEnum;
const logDir = process.env.LOG_DIR || 'logs';
const logger = createLoggerInstance(appName, nodeEnv, logLevel, logDir);
Using with Base App
If you're using the @empe/base-app
package, you can use the simplified logger creation function:
import { createLogger } from '@empe/base-app/tools';
// This will automatically use environment variables for configuration
const logger = createLogger('MyService');
API Reference
createLoggerInstance
The main function to create a new logger instance.
function createLoggerInstance(
appName: string,
nodeEnv: 'development' | 'production' | 'test',
logLevel: LogLevel,
logsDirname?: string,
maxSize?: string,
maxFiles?: string
): Logger
Parameters
appName
: The name of your application (will be included in log entries)nodeEnv
: The Node.js environment ('development', 'production', or 'test')logLevel
: The minimum log level to recordlogsDirname
: (Optional) Directory to store log files (default: 'logs')maxSize
: (Optional) Maximum size of each log file before rotation (default: '10m')maxFiles
: (Optional) Maximum number of days to keep log files (default: '60d')
Returns
A configured Winston logger instance.
LogLevelEnum
An enum of valid log levels:
enum LogLevelEnum {
ERROR = 'error',
WARN = 'warn',
INFO = 'info',
HTTP = 'http',
VERBOSE = 'verbose',
DEBUG = 'debug',
SILLY = 'silly',
}
Log Formatting
Development Environment
In development, logs are colorized and formatted for readability:
[2023-05-15 10:15:30.123 AM] info [MyApp]: User logged in {"userId":123,"role":"admin"}
Production Environment
In production, logs are more compact and include sanitized metadata:
[2023-05-15 10:15:30.123 AM] info [MyApp] User logged in {"userId":123,"role":"admin","token":"[REDACTED]"}
Log File Management
Logs are stored in the specified directory with the following structure:
- Daily log files:
app-YYYY-MM-DD.log
- Exception logs:
exceptions.log
Old log files are automatically compressed and eventually deleted based on the maxFiles
setting.
Security Features
The logger automatically redacts sensitive information in metadata fields with names like:
password
token
secret
key
This helps prevent accidental logging of sensitive data.
Best Practices
Use appropriate log levels:
error
: For errors that affect functionalitywarn
: For concerning but non-critical issuesinfo
: For important operational eventsdebug
: For detailed troubleshooting informationverbose
/silly
: For very detailed debugging
Include structured metadata:
// Good logger.info('User authenticated', { userId: 123, method: 'oauth' }); // Not as useful logger.info(`User 123 authenticated via oauth`);
Configure log levels by environment:
- Development:
debug
orverbose
- Testing:
info
- Production:
info
orwarn
- Development:
Integration with Empe Ecosystem
The @empe/logger
package is designed to work seamlessly with other packages in the Empe ecosystem:
Integration with Base App
The @empe/base-app
package provides a simplified interface to create loggers with environment-based configuration:
// In @empe/base-app/tools/logger.ts
import { createLoggerInstance } from '@empe/logger';
import { getLogLevel, getNodeEnv, getLogsDir } from './env-manager.js';
export const createLogger = (name: string) =>
createLoggerInstance(name, getNodeEnv(), getLogLevel(), getLogsDir());
Usage in Services
All Empe services use the logger in a consistent way:
// In apps/verifier-service/src/logger.ts
import { createLogger } from '@empe/base-app/tools';
export const logger = createLogger('VerifierService');
// Then in other files
import { logger } from './logger.js';
logger.info('Service starting up');
Error Middleware Integration
The logger integrates with the error handling middleware in @empe/base-app
:
// In @empe/base-app/middlewares/error-middleware.ts
export const errorMiddleware = (logger: Logger): ErrorRequestHandler => {
return (err: Error | BaseAppError, req: Request, res: Response, __: NextFunction) => {
// Log errors with appropriate level and context
if (err instanceof BaseAppError) {
logger.warn('OAuth error occurred', { /* error details */ });
} else {
logger.error('An unknown error occurred', { /* error details */ });
}
// Send error response
// ...
};
};
Environment Configuration
The logger can be configured through environment variables:
# The verbosity level for application logging
# Valid options: error, warn, info, http, verbose, debug, silly
LOG_LEVEL=debug
# The directory where application logs are stored
LOG_DIR=logs
# The current environment (affects log formatting)
NODE_ENV=development
Extending the Logger
Since the logger is built on Winston, you can extend it with custom formatters, transports, or other Winston features.
Adding Custom Transports
import { createLoggerInstance, LogLevelEnum } from '@empe/logger';
import { transports } from 'winston';
// Create the base logger
const logger = createLoggerInstance('MyApp', 'development', LogLevelEnum.DEBUG);
// Add a custom transport
logger.add(new transports.Http({
host: 'logging-service.example.com',
port: 8080,
path: '/logs',
ssl: true
}));
Creating a Custom Formatter
import { createLoggerInstance, LogLevelEnum } from '@empe/logger';
import { format } from 'winston';
// Create a custom formatter
const customFormat = format.combine(
format.timestamp(),
format.json(),
format.printf(info => {
return `${info.timestamp} [${info.service}] ${info.level}: ${info.message}`;
})
);
// Create the logger
const logger = createLoggerInstance('MyApp', 'development', LogLevelEnum.DEBUG);
// Create a new console transport with custom format
const consoleTransport = new transports.Console({
format: customFormat
});
// Remove default console transport and add the custom one
logger.clear(); // Remove all transports
logger.add(consoleTransport); // Add the custom console transport
// If you need file transport as well, add it back
logger.add(new transports.DailyRotateFile({
filename: 'app-%DATE%.log',
dirname: 'logs',
format: customFormat
}));
Integration with Third-Party Services
You can integrate the logger with services like Sentry, Loggly, or Elasticsearch:
import { createLoggerInstance, LogLevelEnum } from '@empe/logger';
import winston from 'winston';
import winstonSentry from 'winston-sentry';
const logger = createLoggerInstance('MyApp', 'production', LogLevelEnum.INFO);
// Add Sentry transport
logger.add(new winstonSentry({
dsn: 'your-sentry-dsn',
level: 'error',
tags: { service: 'my-service' }
}));
License
MIT