The fetch-gate library includes comprehensive logging capabilities using Pino, a fast and low-overhead logging library for Node.js.
- Basic Usage
- Logger Configuration
- Log Levels
- Event Types
- Production Setup
- Development Setup
- Custom Serializers
- Security Considerations
The simplest way to enable logging is to use the default logger:
import { FetchProxy } from "fetch-gate"
const proxy = new FetchProxy({
// Default logger is automatically configured
})The default logger uses:
- Level:
infoin production,debugin development - Format: JSON in production, pretty-printed in development
- Output: stdout
You can provide your own Pino logger instance:
import { FetchProxy } from "fetch-gate"
import pino from "pino"
const logger = pino({
level: "warn",
transport: {
target: "pino/file",
options: { destination: "./proxy.log" },
},
})
const proxy = new FetchProxy({
logger: logger,
})interface ProxyOptions {
logger?: Logger // Pino logger instance
// ... other options
}interface ProxyRequestOptions extends RequestInit {
logger?: Logger // Override proxy-level logger for specific requests
// ... other options
}The library uses the following log levels according to Pino standards:
| Level | Numeric | Usage |
|---|---|---|
trace |
10 | Very detailed debugging information |
debug |
20 | Debugging information |
info |
30 | General information about operations |
warn |
40 | Warning conditions |
error |
50 | Error conditions |
fatal |
60 | Critical errors that cause termination |
const logger = pino({ level: "info" })The library logs various types of events:
// Request start (info level)
{
"event": "request_start",
"requestId": "req-123",
"method": "GET",
"url": "https://api.example.com/data",
"timestamp": "2024-01-01T12:00:00.000Z"
}
// Request success (info level)
{
"event": "request_success",
"requestId": "req-123",
"status": 200,
"duration": 250,
"cacheHit": false
}
// Request error (error level)
{
"event": "request_error",
"requestId": "req-123",
"error": "Network timeout",
"duration": 5000
}// Protocol validation (warn level)
{
"event": "security_protocol_validation",
"requestId": "req-123",
"protocol": "file:",
"message": "Unsupported protocol detected"
}
// Header injection attempt (warn level)
{
"event": "security_header_validation",
"requestId": "req-123",
"headerName": "X-Custom",
"issue": "CRLF injection attempt"
}// Circuit breaker state change (warn level)
{
"event": "circuit_breaker_state_change",
"requestId": "req-123",
"previousState": "closed",
"newState": "open",
"errorRate": 0.6,
"errorCount": 6,
"totalCount": 10
}// Performance metrics (debug level)
{
"event": "performance_metrics",
"requestId": "req-123",
"timing": {
"total": 250,
"dns": 10,
"tcp": 20,
"request": 50,
"response": 170
}
}// Cache operations (debug level)
{
"event": "cache_operation",
"requestId": "req-123",
"operation": "hit",
"key": "GET:https://api.example.com/data",
"age": 1500
}For production environments, configure structured logging with appropriate levels:
import pino from "pino"
const productionLogger = pino({
level: "info",
timestamp: pino.stdTimeFunctions.isoTime,
formatters: {
level: (label) => ({ level: label }),
log: (object) => ({
...object,
service: "fetch-gate",
environment: "production",
}),
},
// Redact sensitive information
redact: ["password", "token", "authorization", "cookie"],
// File output for log aggregation
transport: {
target: "pino/file",
options: {
destination: "./logs/proxy.log",
mkdir: true,
},
},
})For production log rotation, use pino-roll:
npm install pino-rollconst logger = pino({
level: "info",
transport: {
target: "pino-roll",
options: {
file: "./logs/proxy.log",
frequency: "daily",
size: "10m",
},
},
})For development, use pretty-printed logs with detailed information:
const developmentLogger = pino({
level: "debug",
transport: {
target: "pino-pretty",
options: {
colorize: true,
translateTime: "SYS:yyyy-mm-dd HH:MM:ss",
ignore: "pid,hostname",
messageFormat: "{msg} [{requestId}]",
},
},
})Customize how objects are logged:
const logger = pino({
serializers: {
req: (req) => ({
method: req.method,
url: req.url,
headers: sanitizeHeaders(req.headers),
}),
res: (res) => ({
status: res.status,
statusText: res.statusText,
headers: Object.fromEntries(res.headers.entries()),
}),
err: pino.stdSerializers.err,
},
})
function sanitizeHeaders(headers) {
const sanitized = { ...headers }
// Remove sensitive headers
delete sanitized.authorization
delete sanitized.cookie
return sanitized
}Always redact sensitive information in logs:
const logger = pino({
redact: {
paths: [
"password",
"token",
"authorization",
"cookie",
"req.headers.authorization",
"req.headers.cookie",
],
censor: "[REDACTED]",
},
})Use appropriate log levels to avoid logging sensitive debugging information:
// Production: Only log important events
const prodLogger = pino({ level: "warn" })
// Development: Log everything for debugging
const devLogger = pino({ level: "trace" })Use structured logging for security events to enable easy monitoring:
// Good: Structured security event
logger.warn({
event: "security_validation_failed",
requestId: "req-123",
validationType: "header_injection",
attemptedValue: "malicious\r\nheader",
})
// Avoid: Unstructured security logs
logger.warn("Header validation failed for request req-123")Integrate with APM tools by adding custom hooks:
const apmLogger = pino({
hooks: {
logMethod(inputArgs, method, level) {
if (level >= 50) {
// Error level
// Send to APM/monitoring system
apm.captureError(new Error(inputArgs[0]))
}
return method.apply(this, inputArgs)
},
},
})Extract metrics from logs for monitoring dashboards:
const metricsLogger = pino({
formatters: {
log: (object) => ({
...object,
// Add correlation IDs for tracing
traceId: getTraceId(),
// Add environment context
environment: process.env.NODE_ENV,
version: process.env.APP_VERSION,
}),
},
})See the examples directory for complete configuration examples including:
- Basic setup
- Production configuration
- Development configuration
- Structured logging
- Custom serializers
- Monitoring integration
- Logs not appearing: Check log level configuration
- Performance impact: Use appropriate log levels for production
- Sensitive data in logs: Configure redaction properly
- Log rotation: Set up proper log rotation for production
Enable debug mode to see all logging events:
const debugProxy = new FetchProxy({
logger: pino({ level: "trace" }),
})This will log all events including detailed request/response information and internal operations.