1.0.128 • Published 9 months ago
@bookum/logging-client v1.0.128
@bookum/logging-client
Internal logging client for Bookum services with support for structured logging, admin impersonation tracking, and automatic batching.
Features
- 🚀 TypeScript Support - Full type definitions and IntelliSense
- 📊 Structured Logging - Rich metadata and context tracking
- 👑 Admin Impersonation - Track admin actions on behalf of users
- 🔄 Automatic Batching - High-performance log aggregation
- 🛡️ Error Handling - Graceful failure with configurable error handlers
- 🔌 Express Middleware - Automatic API request logging
- 🏭 Factory Functions - Pre-configured loggers for Bookum services
- 📡 NATS Integration - Seamless integration with existing NATS event systems
Installation
npm install @bookum/logging-clientQuick Start
Basic Usage
import { createServiceLogger, LogLevel, LogType } from '@bookum/logging-client';
const logger = createServiceLogger({
serviceName: 'my-service',
environment: 'production',
});
// Log a user action
await logger.log({
logType: LogType.USER_EVENT,
logLevel: LogLevel.INFO,
userId: 'user-123',
action: 'profile_updated',
metadata: { field: 'email' },
});
// Log an API request
await logger.logApiRequest({
userId: 'user-123',
method: 'POST',
path: '/api/users/profile',
responseStatus: 200,
duration: 150,
});
// Log an error
await logger.logError({
userId: 'user-123',
action: 'payment_processing',
error: {
type: 'ValidationError',
message: 'Invalid credit card',
code: 'INVALID_CARD',
},
});NATS Integration
If you have an existing NATS event system, you can easily integrate logging:
1. Add Log Event to Your Event System
// Add to your subjects enum:
export enum Subjects {
// ... your existing subjects
Log = 'log',
}2. Use the Log Publisher
import { LogEventPublisher } from '@bookum/logging-client';
import { natsWrapper } from '../nats-wrapper'; // Your existing NATS wrapper
const logPublisher = new LogEventPublisher(
natsWrapper.client,
'bookum-api',
'production'
);
// Use as fallback or primary transport
const logger = createServiceLogger({
serviceName: 'bookum-api',
onError: async (error, logData) => {
// Publish to NATS on HTTP failure
await logPublisher.publishSingleLog(logData);
},
});3. Set Up Consumer in Your Logging Service
// In your dedicated logging service
const subscription = nc.subscribe(Subjects.Log);
for await (const msg of subscription) {
const logEvent = JSON.parse(msg.data);
await processLogs(logEvent);
msg.ack?.();
}See src/integration-example.md for detailed integration examples.
Express Middleware
import express from 'express';
import { createServiceLogger, createAutoLogger } from '@bookum/logging-client';
const app = express();
const logger = createServiceLogger({ serviceName: 'api-service' });
// Auto-log all API requests
app.use(
createAutoLogger({
client: logger,
includeRequestBody: true,
excludePaths: ['/health', '/metrics'],
})
);
app.listen(3000);Admin Impersonation Logging
// Log when admin acts on behalf of a user
await logger.logAdminImpersonation({
adminId: 'admin-456',
adminEmail: 'admin@bookum.com',
userId: 'user-123',
userEmail: 'user@example.com',
action: 'update_booking',
impersonationSessionId: 'session-789',
metadata: { bookingId: 'booking-123' },
});API Reference
InternalLoggingClient
Constructor
new InternalLoggingClient(config: LoggingClientConfig)Methods
log(logData: Partial<LogEntryData>): Promise<void>
Main logging method for structured log entries.
logApiRequest(data: {...}): Promise<void>
Convenience method for logging API requests.
logAdminImpersonation(data: {...}): Promise<void>
Log admin impersonation events.
logError(data: {...}): Promise<void>
Log error events with context.
flush(): Promise<void>
Force flush all pending logs.
shutdown(): Promise<void>
Graceful shutdown with log flushing.
Log Types
enum LogType {
API_REQUEST = 'api_request',
USER_EVENT = 'user_event',
ADMIN_IMPERSONATION = 'admin_impersonation',
PAYMENT_PROCESSING = 'payment_processing',
EMAIL_EVENT = 'email_event',
WEBHOOK = 'webhook',
SYSTEM_EVENT = 'system_event',
ERROR = 'error',
AUTHENTICATION = 'authentication',
BOOKING_EVENT = 'booking_event',
}Configuration
interface LoggingClientConfig {
baseUrl: string;
serviceName: string;
environment?: string;
enableBatching?: boolean;
batchSize?: number;
batchTimeout?: number;
enableAsync?: boolean;
maxQueueSize?: number;
onError?: (error: Error, logData: LogEntryData) => void;
}Factory Functions
Pre-configured Service Loggers
import { BookumLoggers } from '@bookum/logging-client';
const apiLogger = BookumLoggers.createApiLogger();
const authLogger = BookumLoggers.createAuthLogger();
const paymentLogger = BookumLoggers.createPaymentLogger();Environment-specific Loggers
import { createEnvironmentLogger } from '@bookum/logging-client';
// Development logger (immediate, verbose)
const devLogger = createEnvironmentLogger.development('my-service');
// Production logger (batched, optimized)
const prodLogger = createEnvironmentLogger.production('my-service');
// Test logger (silent errors)
const testLogger = createEnvironmentLogger.test('my-service');Express Middleware
Auto Logger
app.use(
createAutoLogger({
client: logger,
includeRequestBody: false, // Include request body in logs
includeResponseBody: false, // Include response body in logs
excludePaths: ['/health'], // Paths to skip logging
extractUserId: (req) => req.user?.id,
extractAdminContext: (req) => ({
adminId: req.headers['x-admin-id'],
adminEmail: req.headers['x-admin-email'],
impersonationSessionId: req.headers['x-impersonation-session'],
}),
})
);Event Logger
import { createEventLogger } from '@bookum/logging-client';
const eventLogger = createEventLogger(logger);
app.post('/api/bookings', async (req, res) => {
// Your booking logic here
// Log the booking event
await eventLogger.logUserEvent(req, {
action: 'booking_created',
logType: LogType.BOOKING_EVENT,
metadata: { bookingId: booking.id },
});
res.json(booking);
});Environment Variables
# Set the logging service URL
BOOKUM_LOGGING_URL=https://logging.bookum.com/api/logs
# Set environment (affects default configurations)
NODE_ENV=production
# NATS configuration (if using NATS integration)
NATS_URL=nats://nats.bookum.internal:4222Best Practices
1. Use Appropriate Log Levels
// Use INFO for normal user actions
await logger.log({
logLevel: LogLevel.INFO,
logType: LogType.USER_EVENT,
// ...
});
// Use WARN for admin impersonation
await logger.log({
logLevel: LogLevel.WARN,
logType: LogType.ADMIN_IMPERSONATION,
// ...
});
// Use ERROR for failures
await logger.log({
logLevel: LogLevel.ERROR,
logType: LogType.ERROR,
// ...
});2. Include Correlation IDs
// In your middleware
app.use((req, res, next) => {
req.correlationId = req.headers['x-correlation-id'] || generateId();
next();
});
// Use in logs
await logger.log({
// ...
correlationId: req.correlationId,
});3. Sanitize Sensitive Data
// Don't log sensitive information
await logger.log({
// ...
metadata: {
userId: user.id,
// DON'T: password: user.password
// DON'T: creditCard: payment.cardNumber
action: 'password_changed', // OK
},
});4. Use Structured Metadata
// Good: structured metadata
await logger.log({
// ...
metadata: {
bookingId: 'booking-123',
hotelId: 'hotel-456',
checkIn: '2024-01-01',
guests: 2,
},
});
// Avoid: unstructured strings
// metadata: { info: "booking-123 for hotel-456 with 2 guests" }Error Handling
The client includes robust error handling:
const logger = createServiceLogger({
serviceName: 'my-service',
onError: (error, logData) => {
// Custom error handling
console.error('Logging failed:', error.message);
// Could implement fallback logging here
// e.g., write to local file, send to alternative service
},
});Performance
- Batching: Logs are batched by default for better performance
- Async: Non-blocking logging operations
- Queue Management: Configurable queue size with overflow protection
- Graceful Shutdown: Automatic log flushing on process termination
Development
# Install dependencies
npm install
# Build the project
npm run build
# Clean build artifacts
npm run cleanLicense
ISC