/** * Structured logging utility for edge functions * Prevents sensitive data exposure and provides consistent log format */ type LogLevel = 'info' | 'warn' | 'error' | 'debug'; interface LogContext { userId?: string; action?: string; [key: string]: unknown; } // 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)); } };