# JavaScript Logging Best Practices

**Date:** 2025-11-17  
**Purpose:** Guidelines for JavaScript logging in the Ordio codebase

## Overview

All console log statements have been removed from production code. This document provides guidelines for future development and when structured logging should be used.

## Core Principle

**Never use `console.log()`, `console.error()`, or any console methods in production code.**

## Structured Logger

### Location

`v2/js/logger.js`

### Usage

```javascript
// Include logger (add to page head or load before use)
<script src="/v2/js/logger.js"></script>;

// Use structured logger
if (typeof window !== "undefined" && window.ordioLogger) {
  window.ordioLogger.debug("Debug message", {
    context: "additional data",
    endpoint: "page-name",
  });
}
```

### Log Levels

```javascript
// DEBUG - Development-only debugging
window.ordioLogger.debug("Message", { context });

// INFO - General information
window.ordioLogger.info("Message", { context });

// WARN - Warnings
window.ordioLogger.warn("Message", { context });

// ERROR - Error conditions
window.ordioLogger.error("Message", { context });

// CRITICAL - Critical errors
window.ordioLogger.critical("Message", { context });
```

### Features

- **Structured JSON output:** Easy to parse and analyze
- **Correlation IDs:** Link client-side and server-side logs
- **Environment detection:** Automatically disabled in production
- **Context support:** Additional metadata in structured format
- **Timestamp formatting:** ISO 8601 format

## Safe Console.log Removal

When removing `console.log()` statements, be careful not to leave orphaned code:

### ❌ BAD: Incomplete Removal

```javascript
// Before removal:
console.log('Function called at:', new Date().toISOString(), 'Function ID:', functionId);

// After incomplete removal (WRONG):
called at:', new Date().toISOString(), 'Function ID:', functionId);
```

### ✅ GOOD: Complete Removal

```javascript
// Before removal:
console.log('Function called at:', new Date().toISOString(), 'Function ID:', functionId);

// After complete removal (CORRECT):
// (entire line removed, no orphaned code)
```

### Common Patterns to Watch For

When removing console.log statements, check for these orphaned patterns:

- `called at:', new Date().toISOString());`
- `.toISOString());`
- `');`
- `');`
- `with click ID:', clickId);`
- `.stack);`

### Alpine.js Expression Cleanup

When removing console.log from Alpine.js expressions (`@click`, `x-model`, etc.), ensure the entire statement is removed:

```javascript
// ❌ BAD: Orphaned code in Alpine expression
@click="const clickId = Math.random().toString(36).substr(2, 9); .toISOString(), 'Click ID:', clickId); exportCSV();"

// ✅ GOOD: Clean Alpine expression
@click="const clickId = Math.random().toString(36).substr(2, 9); exportCSV();"
```

### Validation Script

Use grep to find orphaned console.log patterns:

```bash
grep -r "called at:\|\.toISOString()\|\');\|with click ID:" v2/pages/
```

## When to Use Structured Logger

### ✅ Use Structured Logger For:

1. **Development Debugging**

   ```javascript
   if (window.ordioLogger) {
     window.ordioLogger.debug("Calculation step", {
       input: value,
       result: calculated,
     });
   }
   ```

2. **Error Tracking**

   ```javascript
   try {
     // Code that might fail
   } catch (error) {
     if (window.ordioLogger) {
       window.ordioLogger.error("Operation failed", {
         error: error.message,
         stack: error.stack,
         context: "operation-name",
       });
     }
   }
   ```

3. **Performance Monitoring** (Future)
   ```javascript
   // Future: Send to remote logging endpoint
   window.ordioLogger.info("API call completed", {
     duration: elapsed,
     endpoint: "/api/endpoint",
   });
   ```

### ❌ Never Use Console For:

1. **Production Code**

   ```javascript
   // ❌ BAD
   console.log("User action:", action);

   // ✅ GOOD (if logging needed)
   if (window.ordioLogger) {
     window.ordioLogger.debug("User action", { action });
   }
   ```

2. **Error Handling**

   ```javascript
   // ❌ BAD
   console.error("Error:", error);

   // ✅ GOOD
   if (window.ordioLogger) {
     window.ordioLogger.error("Operation failed", { error: error.message });
   }
   // Or: Silent failure with user-friendly message
   ```

3. **User Feedback**

   ```javascript
   // ❌ BAD
   console.log("Form submitted");

   // ✅ GOOD
   // Show user-friendly message in UI, not console
   showSuccessMessage("Form submitted successfully");
   ```

## When NOT to Log

### Silent Failures

For non-critical operations, prefer silent failure with user-friendly error messages:

```javascript
// ❌ BAD
try {
  saveToLocalStorage(data);
} catch (error) {
  console.error("Failed to save:", error);
}

// ✅ GOOD
try {
  saveToLocalStorage(data);
} catch (error) {
  // Silent failure - localStorage might be disabled
  // User doesn't need to know, functionality degrades gracefully
}
```

### User Actions

Don't log user actions - they're not errors:

```javascript
// ❌ BAD
button.addEventListener("click", () => {
  console.log("Button clicked");
  // Handle click
});

// ✅ GOOD
button.addEventListener("click", () => {
  // Handle click directly
  // No logging needed for normal user interactions
});
```

## Context and Correlation IDs

### Include Context

Always include relevant context in log messages:

```javascript
window.ordioLogger.debug("API call", {
  endpoint: "/v2/api/endpoint",
  method: "POST",
  payload: sanitizedPayload, // Never log sensitive data
  correlation_id: getCorrelationId(),
});
```

### Correlation IDs

Link client-side and server-side logs:

```javascript
// Get correlation ID from meta tag (set by PHP)
const correlationId = document.querySelector(
  'meta[name="ordio-correlation-id"]'
)?.content;

// Use in logs
window.ordioLogger.info("Request sent", {
  correlation_id: correlationId,
  endpoint: "/v2/api/endpoint",
});
```

## Performance Considerations

### Lazy Evaluation

Only create log entries when logger is available and enabled:

```javascript
// ✅ GOOD - Check before logging
if (window.ordioLogger && window.ordioLogger.isConsoleEnabled()) {
  window.ordioLogger.debug("Expensive operation", {
    result: expensiveCalculation(), // Only called if logging enabled
  });
}
```

### Production Behavior

In production, the logger is disabled by default:

- No console output
- No performance overhead
- No log file writes
- Clean browser console

## Security Considerations

### Never Log Sensitive Data

```javascript
// ❌ BAD
window.ordioLogger.debug("User login", {
  email: userEmail,
  password: userPassword, // NEVER log passwords!
});

// ✅ GOOD
window.ordioLogger.debug("User login", {
  user_id: userId, // Use ID, not email
  // Never include passwords, tokens, or sensitive data
});
```

### Sanitize Data

Always sanitize data before logging:

```javascript
window.ordioLogger.debug("Form data", {
  field1: sanitizeString(formData.field1),
  field2: sanitizeString(formData.field2),
  // Remove any sensitive information
});
```

## Examples

### Calculator Debugging

```javascript
// Development debugging
if (window.ordioLogger) {
  window.ordioLogger.debug("Calculation performed", {
    input: {
      value1: input1,
      value2: input2,
    },
    result: calculatedResult,
    method: "addition",
  });
}
```

### API Error Handling

```javascript
try {
  const response = await fetch("/v2/api/endpoint", options);
  if (!response.ok) {
    throw new Error(`HTTP ${response.status}`);
  }
} catch (error) {
  // Log error for debugging
  if (window.ordioLogger) {
    window.ordioLogger.error("API call failed", {
      endpoint: "/v2/api/endpoint",
      error: error.message,
      status: error.status,
    });
  }

  // Show user-friendly error
  showErrorMessage("Unable to complete request. Please try again.");
}
```

### Form Validation

```javascript
function validateForm(formData) {
  const errors = [];

  if (!formData.email) {
    errors.push("Email required");
  }

  // Log validation errors (development only)
  if (errors.length > 0 && window.ordioLogger) {
    window.ordioLogger.debug("Form validation failed", {
      errors: errors,
      form_data: sanitizeFormData(formData),
    });
  }

  return errors;
}
```

## Migration from Console

### Before (Console)

```javascript
console.log("User action:", action);
console.error("Error occurred:", error);
console.warn("Warning:", warning);
```

### After (Structured Logger)

```javascript
if (window.ordioLogger) {
  window.ordioLogger.debug("User action", { action });
  window.ordioLogger.error("Error occurred", { error: error.message });
  window.ordioLogger.warn("Warning", { warning });
}
```

## Checklist

Before committing code:

- [ ] No `console.log()`, `console.error()`, `console.warn()`, etc.
- [ ] If logging needed, use structured logger
- [ ] Logger checks for availability before use
- [ ] No sensitive data in logs
- [ ] Context included in log messages
- [ ] Correlation IDs used when available
- [ ] Production code doesn't log user actions
- [ ] Errors handled gracefully with user-friendly messages

## Summary

1. **Never use console methods** in production code
2. **Use structured logger** for development debugging
3. **Include context** in all log messages
4. **Never log sensitive data**
5. **Prefer silent failures** for non-critical operations
6. **Show user-friendly messages** instead of console logs
7. **Check logger availability** before use
8. **Use correlation IDs** to link client/server logs

---

**Last updated:** 2025-11-17  
**Status:** Active guidelines for all JavaScript development
