Files
thrilltrack-explorer/supabase/functions/_shared/logger.ts
2025-10-21 12:05:04 +00:00

110 lines
2.5 KiB
TypeScript

/**
* Structured logging utility for edge functions
* Prevents sensitive data exposure and provides consistent log format
*/
type LogLevel = 'info' | 'warn' | 'error' | 'debug';
interface LogContext {
requestId?: string; // Correlation ID for tracing
userId?: string;
action?: string;
duration?: number; // Request duration in ms
traceId?: string; // Distributed tracing ID
[key: string]: unknown;
}
// Request tracking utilities
export interface RequestTracking {
requestId: string;
start: number;
traceId?: string;
}
export function startRequest(traceId?: string): RequestTracking {
return {
requestId: crypto.randomUUID(),
start: Date.now(),
traceId: traceId || crypto.randomUUID(),
};
}
export function endRequest(tracking: RequestTracking): number {
return Date.now() - tracking.start;
}
// Fields that should never be logged
const SENSITIVE_FIELDS = [
'password',
'token',
'secret',
'api_key',
'apikey',
'authorization',
'email',
'phone',
'ssn',
'credit_card',
'ip_address',
'session_id'
];
/**
* Sanitize context to remove sensitive data
*/
function sanitizeContext(context: LogContext): LogContext {
const sanitized: LogContext = {};
for (const [key, value] of Object.entries(context)) {
const lowerKey = key.toLowerCase();
// Skip sensitive fields
if (SENSITIVE_FIELDS.some(field => lowerKey.includes(field))) {
sanitized[key] = '[REDACTED]';
continue;
}
// Recursively sanitize objects
if (value && typeof value === 'object' && !Array.isArray(value)) {
sanitized[key] = sanitizeContext(value as LogContext);
} else {
sanitized[key] = value;
}
}
return sanitized;
}
/**
* Format log message with context
*/
function formatLog(level: LogLevel, message: string, context?: LogContext): string {
const timestamp = new Date().toISOString();
const sanitizedContext = context ? sanitizeContext(context) : {};
return JSON.stringify({
timestamp,
level,
message,
...sanitizedContext
});
}
export const edgeLogger = {
info: (message: string, context?: LogContext): void => {
console.info(formatLog('info', message, context));
},
warn: (message: string, context?: LogContext): void => {
console.warn(formatLog('warn', message, context));
},
error: (message: string, context?: LogContext): void => {
console.error(formatLog('error', message, context));
},
debug: (message: string, context?: LogContext): void => {
console.debug(formatLog('debug', message, context));
}
};