HTTP Instrumentation
SyntropyLog's HTTP instrumentation provides automatic request/response logging, context propagation, and correlation across HTTP calls.
🎯 Overview
HTTP instrumentation enables:
- Automatic logging - Request/response details logged automatically
- Context propagation - Correlation IDs and context flow through headers
- Framework agnostic - Works with any HTTP client via adapters
- Performance monitoring - Request duration and status tracking
🚀 Basic Usage
import { syntropyLog } from 'syntropylog';
import { AxiosAdapter } from '@syntropylog/adapters';
import axios from 'axios';
// Initialize with HTTP configuration
await syntropyLog.init({
http: {
instances: [
{
instanceName: 'api',
adapter: new AxiosAdapter(axios.create({
baseURL: 'https://api.example.com'
})),
},
],
},
});
// Use the instrumented client
const httpClient = syntropyLog.getHttp('api');
const response = await httpClient.request({
method: 'GET',
url: '/users',
});
🏗️ Singleton Pattern
HTTP clients use singleton pattern for efficient resource management:
// First call - creates and returns new instance
const client1 = syntropyLog.getHttp('api');
// Second call - returns the SAME instance (singleton)
const client2 = syntropyLog.getHttp('api');
// client1 === client2 ✅
// Same connection pool and configuration
🔗 Context Propagation
Context automatically propagates through HTTP headers:
await syntropyLog.init({
http: {
instances: [
{
instanceName: 'api',
adapter: new AxiosAdapter(axios.create()),
propagate: ['correlationId', 'userId', 'tenantId'],
},
],
},
});
// Set context data
const contextManager = syntropyLog.getContextManager();
contextManager.set('userId', 123);
contextManager.set('tenantId', 'tenant-1');
// Context is automatically added to headers
const httpClient = syntropyLog.getHttp('api');
await httpClient.request({
method: 'GET',
url: '/api/users',
// Headers automatically include:
// X-Correlation-ID: abc-123-def-456
// X-User-ID: 123
// X-Tenant-ID: tenant-1
});
📊 Automatic Logging
HTTP operations are automatically logged with context:
await syntropyLog.init({
http: {
instances: [
{
instanceName: 'api',
adapter: new AxiosAdapter(axios.create()),
logging: {
onRequest: 'info',
onSuccess: 'debug',
onError: 'error',
logRequestHeaders: false,
logRequestBody: true,
logResponseHeaders: false,
logResponseBody: false,
},
},
],
},
});
// All HTTP operations are automatically logged
const httpClient = syntropyLog.getHttp('api');
// This will log: "HTTP Request: GET /api/users"
await httpClient.get('/api/users');
// This will log: "HTTP Response: 200 OK" (at debug level)
// This will log: "HTTP Error: 500 Internal Server Error" (at error level)
🎨 Multiple HTTP Clients
Configure multiple HTTP clients for different services:
await syntropyLog.init({
http: {
instances: [
{
instanceName: 'userApi',
adapter: new AxiosAdapter(axios.create({
baseURL: 'https://api.users.com'
})),
propagate: ['correlationId', 'userId'],
logging: {
onSuccess: 'debug',
onError: 'error',
},
},
{
instanceName: 'paymentApi',
adapter: new AxiosAdapter(axios.create({
baseURL: 'https://api.payments.com'
})),
propagate: ['correlationId', 'paymentId'],
logging: {
onSuccess: 'info', // More verbose for payments
onError: 'warn',
logResponseBody: true, // Log payment responses
},
},
],
default: 'userApi', // Default instance
},
});
// Use different clients
const userClient = syntropyLog.getHttp('userApi');
const paymentClient = syntropyLog.getHttp('paymentApi');
await userClient.get('/users/123');
await paymentClient.post('/payments', paymentData);
🔧 Adapter Pattern
SyntropyLog uses adapters to support any HTTP client:
Axios Adapter
import { AxiosAdapter } from '@syntropylog/adapters';
import axios from 'axios';
const axiosInstance = axios.create({
baseURL: 'https://api.example.com',
timeout: 5000,
});
const adapter = new AxiosAdapter(axiosInstance);
Fetch Adapter
import { FetchAdapter } from '@syntropylog/adapters';
const adapter = new FetchAdapter();
Custom Adapter
import { IHttpAdapter } from 'syntropylog';
class CustomHttpAdapter implements IHttpAdapter {
async request(config: any) {
// Your custom HTTP client implementation
return response;
}
}
const adapter = new CustomHttpAdapter();
🎯 Logging Configuration
Fine-tune what gets logged for each HTTP operation:
await syntropyLog.init({
http: {
instances: [
{
instanceName: 'api',
adapter: new AxiosAdapter(axios.create()),
logging: {
onRequest: 'info', // Log when request starts
onSuccess: 'debug', // Log successful responses
onError: 'error', // Log errors
logRequestHeaders: false, // Don't log request headers
logRequestBody: true, // Log request body
logResponseHeaders: false, // Don't log response headers
logResponseBody: false, // Don't log response body
logDuration: true, // Log request duration
},
},
],
},
});
🔒 Security Features
Header Redaction
await syntropyLog.init({
http: {
instances: [
{
instanceName: 'api',
adapter: new AxiosAdapter(axios.create()),
logging: {
redactHeaders: ['authorization', 'cookie', 'x-api-key'],
logRequestHeaders: true,
},
},
],
},
});
// Sensitive headers are automatically redacted in logs
await httpClient.request({
headers: {
'Authorization': 'Bearer secret-token', // Will show as "***"
'Content-Type': 'application/json', // Will show normally
},
});
Body Masking
await syntropyLog.init({
masking: {
fields: ['password', 'token', 'creditCard'],
},
http: {
instances: [
{
instanceName: 'api',
adapter: new AxiosAdapter(axios.create()),
logging: {
logRequestBody: true,
},
},
],
},
});
// Sensitive data in request body is automatically masked
await httpClient.post('/users', {
email: 'user@example.com',
password: 'secret123', // Will show as "***"
});
⚡ Performance Monitoring
Track HTTP performance automatically:
await syntropyLog.init({
http: {
instances: [
{
instanceName: 'api',
adapter: new AxiosAdapter(axios.create()),
logging: {
logDuration: true,
logStatusCodes: true,
},
},
],
},
});
// Performance metrics are automatically logged
const startTime = Date.now();
await httpClient.get('/api/users');
// Logs: "HTTP Response: 200 OK (45ms)"
🎯 Error Handling
HTTP errors are automatically logged with context:
try {
await httpClient.get('/api/users');
} catch (error) {
// Error is automatically logged with:
// - Request details (method, URL, headers)
// - Response details (status, body)
// - Duration
// - Full context (correlation ID, etc.)
// You can also log additional context
logger.error({ err: error }, 'API call failed', {
operation: 'fetch_users',
retryCount: 3,
});
}
🔧 Configuration Options
await syntropyLog.init({
http: {
instances: [
{
instanceName: 'api',
adapter: new AxiosAdapter(axios.create()),
isDefault: true,
propagate: ['correlationId', 'userId', 'tenantId'],
logging: {
onRequest: 'info',
onSuccess: 'debug',
onError: 'error',
logRequestHeaders: false,
logRequestBody: true,
logResponseHeaders: false,
logResponseBody: false,
logDuration: true,
redactHeaders: ['authorization'],
},
timeout: 5000,
retries: 3,
},
],
default: 'api',
},
});
🎯 Best Practices
- Use meaningful instance names - Choose descriptive names for different APIs
- Configure appropriate logging levels - Don't log everything at the same level
- Redact sensitive headers - Always redact authorization and API keys
- Use context propagation - Enable correlation for distributed tracing
- Monitor performance - Enable duration logging for performance tracking
- Handle errors gracefully - Use try-catch blocks for error handling
- Use adapters - Leverage the adapter pattern for framework agnosticism
🔍 Debugging HTTP Calls
// Enable verbose logging for debugging
await syntropyLog.init({
http: {
instances: [
{
instanceName: 'api',
adapter: new AxiosAdapter(axios.create()),
logging: {
onRequest: 'debug',
onSuccess: 'debug',
onError: 'debug',
logRequestHeaders: true,
logRequestBody: true,
logResponseHeaders: true,
logResponseBody: true,
},
},
],
},
});
// All HTTP operations will be logged in detail
⚡ Performance Considerations
- Minimal overhead - HTTP instrumentation adds less than 1ms per request
- Connection pooling - Adapters reuse connections when possible
- Async operations - All HTTP calls are non-blocking
- Memory efficient - Singleton pattern prevents connection leaks