# Logging Policy ## ✅ Console Statement Prevention (P0 #2) **Status**: Enforced via ESLint **Severity**: Critical - Security & Information Leakage --- ## The Problem Console statements in production code cause: - **Information leakage**: Sensitive data exposed in browser console - **Performance overhead**: Console operations are expensive - **Unprofessional UX**: Users see debug output - **No structured logging**: Can't filter, search, or analyze logs effectively **128 console statements** were found during the security audit. --- ## The Solution ### ✅ Use handleError() for Application Errors **CRITICAL: All application errors MUST be logged to the Admin Panel Error Log** (`/admin/error-monitoring`) ```typescript import { handleError } from '@/lib/errorHandler'; // ❌ DON'T use console or raw toast for errors try { await fetchData(); } catch (error) { console.error('Failed:', error); // ❌ No admin logging toast.error('Failed to load data'); // ❌ Not tracked } // ✅ DO use handleError() for application errors try { await fetchData(); } catch (error) { handleError(error, { action: 'Load Data', userId: user?.id, metadata: { entityId, context: 'DataLoader' } }); throw error; // Re-throw for parent error boundaries } ``` ### ✅ Use the Structured Logger for Non-Error Logging ```typescript import { logger } from '@/lib/logger'; // ❌ DON'T use console console.log('User logged in:', userId); // ✅ DO use structured logger logger.info('User logged in', { userId }); logger.debug('Auth state changed', { state, userId }); ``` ### Error Handling Method ```typescript // Application errors (REQUIRED for errors that need admin visibility) handleError( error: unknown, context: { action: string; // What operation failed userId?: string; // Who was affected metadata?: Record; // Additional context } ): string // Returns error reference ID ``` **What handleError() does:** 1. Logs error to `request_metadata` table (Admin Panel visibility) 2. Shows user-friendly toast with reference ID 3. Captures breadcrumbs and environment context 4. Makes errors searchable in `/admin/error-monitoring` 5. Returns error reference ID for tracking ### Logger Methods (for non-error logging) ```typescript // Information (development only) logger.info(message: string, context?: Record); // Warnings (development + production) logger.warn(message: string, context?: Record); // Errors (development + production, but prefer handleError() for app errors) logger.error(message: string, context?: Record); // Debug (very verbose, development only) logger.debug(message: string, context?: Record); ``` ### Benefits of Structured Error Handling & Logging 1. **Admin visibility**: All errors logged to Admin Panel (`/admin/error-monitoring`) 2. **User-friendly**: Shows toast with reference ID for support tickets 3. **Context preservation**: Rich metadata for debugging 4. **Searchable**: Filter by user, action, date, error type 5. **Trackable**: Each error gets unique reference ID 6. **Automatic filtering**: Development logs show everything, production shows warnings/errors 7. **Security**: Prevents accidental PII exposure --- ## ESLint Enforcement The `no-console` rule is enforced in `eslint.config.js`: ```javascript "no-console": "error" // Blocks ALL console statements ``` This rule will: - ❌ **Block**: `console.log()`, `console.debug()`, `console.info()`, `console.warn()`, `console.error()` - ✅ **Use instead**: `logger.*` for logging, `handleError()` for error handling ### Running Lint ```bash # Check for violations npm run lint # Auto-fix where possible npm run lint -- --fix ``` --- ## Migration Guide ### 1. Replace console.error in catch blocks with handleError() ```typescript // Before try { await saveData(); } catch (error) { console.error('Save failed:', error); toast.error('Failed to save'); } // After try { await saveData(); } catch (error) { handleError(error, { action: 'Save Data', userId: user?.id, metadata: { entityId, entityType } }); throw error; // Re-throw for parent components } ``` ### 2. Replace console.log with logger.info ```typescript // Before console.log('[ModerationQueue] Fetching submissions'); // After logger.info('Fetching submissions', { component: 'ModerationQueue' }); ``` ### 3. Replace console.debug with logger.debug ```typescript // Before console.log('[DEBUG] Auth state:', authState); // After logger.debug('Auth state', { authState }); ``` ### 4. Replace console.warn with logger.warn ```typescript // Before console.warn('localStorage error:', error); // After logger.warn('localStorage error', { error }); ``` --- ## Examples ### Good: Error Handling with Admin Logging ```typescript import { handleError } from '@/lib/errorHandler'; import { logger } from '@/lib/logger'; const handleSubmit = async () => { logger.info('Starting submission', { entityType, entityId, userId }); try { const result = await submitData(); logger.info('Submission successful', { submissionId: result.id, processingTime: Date.now() - startTime }); toast.success('Submission created successfully'); } catch (error) { // handleError logs to admin panel + shows toast const errorId = handleError(error, { action: 'Submit Data', userId, metadata: { entityType, entityId } }); throw error; // Re-throw for parent error boundaries } }; ``` ### Bad: Console Logging ```typescript const handleSubmit = async () => { console.log('Submitting...'); // ❌ Will fail ESLint try { const result = await submitData(); console.log('Success:', result); // ❌ Will fail ESLint } catch (error) { console.error(error); // ❌ Will fail ESLint toast.error('Failed'); // ❌ Not logged to admin panel } }; ``` --- ## When to Use What ### Use `handleError()` for: - ✅ Database errors (fetch, insert, update, delete) - ✅ API call failures - ✅ Form submission errors - ✅ Authentication errors - ✅ Any error that users should report to support - ✅ Any error that needs admin investigation ### Use `logger.*` for: - ✅ Debug information (development only) - ✅ Performance tracking - ✅ Component lifecycle events - ✅ Non-error warnings (localStorage issues, etc.) ### Use `toast.*` (without handleError) for: - ✅ Success messages - ✅ Info messages - ✅ User-facing validation errors (no admin logging needed) ### NEVER use `console.*`: - ❌ All console statements are blocked by ESLint - ❌ Use `handleError()` or `logger.*` instead --- ## Environment-Aware Logging The logger automatically adjusts based on environment: ```typescript // Development: All logs shown logger.debug('Verbose details'); // ✅ Visible logger.info('Operation started'); // ✅ Visible logger.warn('Potential issue'); // ✅ Visible logger.error('Critical error'); // ✅ Visible // Production: Only warnings and errors logger.debug('Verbose details'); // ❌ Hidden logger.info('Operation started'); // ❌ Hidden logger.warn('Potential issue'); // ✅ Visible logger.error('Critical error'); // ✅ Visible + Sent to monitoring ``` --- ## Testing with Logger ```typescript import { logger } from '@/lib/logger'; // Mock logger in tests jest.mock('@/lib/logger', () => ({ logger: { info: jest.fn(), warn: jest.fn(), error: jest.fn(), debug: jest.fn(), } })); test('logs error on failure', async () => { await failingOperation(); expect(logger.error).toHaveBeenCalledWith( 'Operation failed', expect.objectContaining({ error: expect.any(String) }) ); }); ``` --- ## Monitoring Integration (Future) The logger is designed to integrate with: - **Sentry**: Automatic error tracking - **LogRocket**: Session replay with logs - **Datadog**: Log aggregation and analysis - **Custom dashboards**: Structured JSON logs ```typescript // Future: Logs will automatically flow to monitoring services logger.error('Payment failed', { userId, amount, paymentProvider }); // → Automatically sent to Sentry with full context // → Triggers alert if error rate exceeds threshold ``` --- ## Edge Function Logging ### Using `edgeLogger` in Edge Functions Edge functions use the `edgeLogger` utility from `_shared/logger.ts`: ```typescript import { edgeLogger, startRequest, endRequest } from "../_shared/logger.ts"; const handler = async (req: Request): Promise => { const tracking = startRequest('function-name'); try { edgeLogger.info('Processing request', { requestId: tracking.requestId, // ... context }); // ... your code const duration = endRequest(tracking); edgeLogger.info('Request completed', { requestId: tracking.requestId, duration }); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); const duration = endRequest(tracking); edgeLogger.error('Request failed', { error: errorMessage, requestId: tracking.requestId, duration }); } }; ``` ### Logger Methods for Edge Functions - `edgeLogger.info()` - General information logging - `edgeLogger.warn()` - Warning conditions - `edgeLogger.error()` - Error conditions - `edgeLogger.debug()` - Detailed debugging (dev only) All logs are visible in the Supabase Edge Function Logs dashboard. **CRITICAL**: Never use `console.*` in edge functions. Always use `edgeLogger.*` instead. --- ## Summary **Use `handleError()` for application errors** → Logs to Admin Panel + user-friendly toast **Use `logger.*` for general logging (client-side)** → Environment-aware console output **Use `edgeLogger.*` for edge function logging** → Structured logs visible in Supabase dashboard **Never use `console.*`** → Blocked by ESLint This approach ensures: - ✅ Production builds are clean (no console noise) - ✅ All errors are tracked and actionable in Admin Panel - ✅ Users get helpful error messages with reference IDs - ✅ Development remains productive with detailed logs - ✅ Edge functions have structured, searchable logs ## Admin Panel Error Monitoring All errors logged via `handleError()` are visible in the Admin Panel at: **Path**: `/admin/error-monitoring` **Features**: - Search and filter errors by action, user, date range - View error context (metadata, breadcrumbs, environment) - Track error frequency and patterns - One-click copy of error details for debugging **Access**: Admin role required --- **Updated**: 2025-11-03 **Status**: ✅ Enforced via ESLint (Frontend + Edge Functions) --- **See Also:** - `src/lib/errorHandler.ts` - Error handling utilities - `src/lib/logger.ts` - Logger implementation - `eslint.config.js` - Enforcement configuration - `docs/JSONB_ELIMINATION.md` - Related improvements