@gomarbleai/logging-js
v1.0.15
Published
Standardized structured logging library for microservices
Readme
@gomarbleai/logging-js
Standardized structured logging library for microservices that works seamlessly with Next.js, Express.js, and Fastify.
Features
- Universal Compatibility: Built-in support for Next.js, Express.js, and Fastify frameworks
- Structured Logging: JSON-formatted logs with consistent schema
- Request Tracing: Automatic trace ID extraction and propagation
- Performance Monitoring: Built-in request duration tracking
- Error Handling: Comprehensive error logging with stack traces
- Streaming Support: Special handling for SSE and long-lived connections
- Zero Configuration: Works out of the box with sensible defaults
Installation
npm install @gomarbleai/logging-jsQuick Start
Next.js API Routes
import { withLogging } from '@gomarbleai/logging-js';
async function handler(req: NextApiRequest, res: NextApiResponse) {
// Your API logic here
res.status(200).json({ message: 'Success' });
}
export default withLogging(handler);Express.js Routes
import express from 'express';
import { withLogging, createLogger } from '@gomarbleai/logging-js';
const app = express();
// Apply logging middleware (auto-detects Express)
app.use(withLogging);
app.get('/api/data', (req, res) => {
const logger = createLogger(req);
logger.info('Processing request');
res.json({ data: 'success' });
});Fastify Routes
import Fastify from 'fastify';
import { registerFastifyLogging, createLogger } from '@gomarbleai/logging-js';
const server = Fastify({ logger: true });
const start = async () => {
try {
// Register logging hooks (covers all routes automatically)
registerFastifyLogging(server);
// Register your routes
server.get('/api/data', async (request, reply) => {
const logger = createLogger(request);
logger.info('Processing request');
return { data: 'success' };
});
await server.listen({ port: 3000, host: '0.0.0.0' });
} catch (err) {
server.log.error(err);
process.exit(1);
}
};
start();Alternative Plugin Approach:
// You can also use the plugin approach if preferred
await server.register(withFastifyLogging());Streaming/SSE Endpoints
For Server-Sent Events (SSE) or long-lived streaming connections:
import { withStreamLogging, createLoggingContext } from '@gomarbleai/logging-js';
// Option 1: Use withStreamLogging middleware
app.get('/api/sse', withStreamLogging((req, res) => {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
// Your SSE logic here
const interval = setInterval(() => {
res.write(`data: ${JSON.stringify({ timestamp: Date.now() })}\n\n`);
}, 1000);
req.on('close', () => clearInterval(interval));
}, {
logStart: true, // Log when connection starts
logEnd: true, // Log when connection closes
timeout: 300000 // Optional: Log timeout after 5 minutes
}));
// Option 2: Use manual logging context for fine-grained control
app.get('/api/sse-manual', (req, res) => {
const loggingContext = createLoggingContext(req);
loggingContext.logStart('SSE connection initiated');
try {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
// Your SSE logic here
const interval = setInterval(() => {
res.write(`data: ${JSON.stringify({ timestamp: Date.now() })}\n\n`);
}, 1000);
req.on('close', () => {
clearInterval(interval);
loggingContext.logEnd('SSE connection closed by client');
});
req.on('error', (error) => {
clearInterval(interval);
loggingContext.logError(error, 'SSE connection error');
});
} catch (error) {
loggingContext.logError(error, 'Failed to establish SSE connection');
}
});Usage
Automatic Request Logging
For Next.js & Express.js:
The withLogging function automatically:
- Detects whether you're using Next.js or Express.js
- Logs request start and completion
- Tracks response time
- Extracts and propagates trace IDs
- Handles errors and exceptions
For Fastify:
The registerFastifyLogging() function automatically:
- Registers hooks directly on the Fastify instance
- Logs request completion with method, path, status, and duration
- Extracts trace IDs from headers
- Works with all registered routes
- Alternative: Use
withFastifyLogging()as a plugin
Streaming Request Logging
The withStreamLogging function is designed for long-lived connections:
- Logs connection initiation and closure
- Handles connection events (close, error, finish)
- Supports optional timeout warnings
- Doesn't wait for handler completion (non-blocking)
Manual Logging
import { createLogger, createLoggingContext } from '@gomarbleai/logging-js';
// Basic manual logging
export default withLogging(async (req, res) => {
const logger = createLogger(req);
logger.info('Processing user data');
logger.warn('Rate limit approaching');
logger.error('Database connection failed', {
error: new Error('Connection timeout'),
custom_data: { user_id: 123 }
});
});
// Manual logging with context (for streaming)
app.post('/api/users', (req, res) => {
const context = createLoggingContext(req);
context.logStart('Creating new user');
try {
// Your logic here
context.logEnd('User created successfully');
} catch (error) {
context.logError(error, 'Failed to create user');
}
});
// Fastify manual logging
const start = async () => {
// Register logging hooks
registerFastifyLogging(server);
server.post('/api/users', async (request, reply) => {
const logger = createLogger(request);
logger.info('Creating new user');
try {
// Your logic here
logger.info('User created successfully');
return { success: true };
} catch (error) {
logger.error('Failed to create user', { error });
throw error;
}
});
await server.listen({ port: 3000 });
};Logger Methods
logger.debug(message, metadata?);
logger.info(message, metadata?);
logger.warn(message, metadata?);
logger.error(message, metadata?);
// Context methods
context.logStart(message?);
context.logEnd(message?);
context.logError(error, message?);Configuration
Set environment variables to configure the logger:
SERVICE_NAME=user-service
ENVIRONMENT=production
NODE_ENV=productionStreaming Options
Configure withStreamLogging with these options:
interface StreamLoggingOptions {
logStart?: boolean; // Log connection start (default: true)
logEnd?: boolean; // Log connection end (default: true)
timeout?: number; // Timeout in ms for warning (optional)
}Log Format
All logs follow this structured JSON format:
{
"timestamp": "2024-01-01T12:00:00.000Z",
"level": "INFO",
"message": "request processed",
"service_name": "user-service",
"environment": "production",
"trace_id": "internal-abc123def456",
"http": {
"method": "POST",
"path": "/api/users",
"status_code": 200
},
"duration_ms": 150,
"custom_data": {
"user_id": 123
}
}Framework Support
The library provides different middleware for each framework:
- Next.js: Use
withLogging- automatically detects Next.js API handlers - Express.js: Use
withLogging- automatically detects Express middleware signature - Fastify: Use
registerFastifyLogging()for direct registration orwithFastifyLogging()as a plugin
Each framework has optimized integration that respects framework conventions!
Fastify Integration Notes
Direct Registration (Recommended):
registerFastifyLogging(server);- Registers hooks directly on the Fastify instance
- Ensures hooks apply to all routes regardless of plugin encapsulation
- Simpler setup for most use cases
Plugin Approach:
await server.register(withFastifyLogging());- Follows Fastify plugin conventions
- May require careful ordering relative to route registration
- Use when you need plugin-specific encapsulation
Best Practices
For Regular APIs
- Next.js/Express: Use
withLoggingfor standard request/response cycles - Fastify: Use
registerFastifyLogging(server)for direct hook registration, orwithFastifyLogging()plugin - Use
createLoggerfor manual logging within handlers
For Streaming/SSE
- Use
withStreamLoggingfor SSE endpoints with automatic lifecycle logging - Use
createLoggingContextfor fine-grained control over streaming logs - Set appropriate timeout values for long-running connections
- Always handle connection close events to prevent resource leaks
General
- Include meaningful custom_data for business context
- Use descriptive messages that explain what happened
- Pass Error objects for automatic stack trace formatting
License
MIT
