# Legacy Code Logging Rollout

## The Legacy Code Challenge

Legacy code changes should be handled with extreme care, and this guide acknowledges the inherent risks and challenges involved. Unlike greenfield development, legacy systems often suffer from a lack of knowledge and documentation about their functionality. The original developers may be unreachable, tribal knowledge has been lost, and internal teams are poorly equipped to deal with the potential fallout should changes go awry.

When working with legacy code, the primary goal is to add observability without disrupting existing functionality. This requires a careful assessment of the current state, understanding of the team's comfort level with the codebase, and a risk-based approach to implementation.

## Understanding Your Legacy Codebase

Before embarking on any logging implementation, assess your team's comfort level with different parts of the codebase:

### High Comfort Level

* **Recently added code** (within the last 6-12 months)
* **Original author is available** and can provide guidance
* **Good documentation** exists for the functionality
* **Team has experience** with similar patterns in the codebase
* **Comprehensive test coverage** exists

### Medium Comfort Level

* **Code is 1-3 years old** but follows familiar patterns
* **Some documentation** exists, though incomplete
* **Team has worked with** similar functionality before
* **Partial test coverage** exists
* **Original author is reachable** but not actively involved

### Low Comfort Level

* **Code is 3+ years old** with no recent modifications
* **No documentation** or outdated documentation
* **Original author is unreachable** or no longer with the company
* **No tribal knowledge** within the existing team
* **Minimal or no test coverage**
* **Complex business logic** that's difficult to understand
* **Critical business processes** with high impact if broken

## Risk-Based Implementation Strategy

### Exception Logging Patterns

The most critical aspect of legacy code logging is exception handling. Different patterns require different approaches based on risk assessment:

#### Pattern A: Non-existent Error Handling (No try/catch)

**Current State**: Code has no exception handling, errors bubble up naturally.

**Risk Level**: **Low Risk**

**Recommended Approach**:

* **Don't modify the code initially**
* Let automated exception capture via Pharos handle error logging
* Monitor the automated logs to understand error patterns
* Only add explicit logging if specific error scenarios need custom handling

**Example**:

```apex
// ❌ Don't modify this initially
public class LegacyAccountProcessor {
    public static void processAccount(Account acc) {
        // No try/catch - let errors bubble up
        update acc;
        processRelatedRecords(acc.Id);
    }
}

// ✅ Let Pharos capture exceptions automatically
// No code changes needed - Pharos will log unhandled exceptions
```

#### Pattern B: Some Error Handling but No Logging (or System.debug)

**Current State**: Code has try/catch blocks but uses System.debug or no logging.

**Risk Level**: **Medium to High Risk**

**Recommended Approach**:

* **Phase 1 (Low Risk)**: Replace System.debug with Triton logging
* **Phase 2 (Higher Risk)**: Enhance error handling with more detailed logging
* **Use feature flags** to control logging behavior

**Example**:

```apex
// ❌ Current legacy code
public class LegacyIntegrationService {
    public static void callExternalAPI(String endpoint) {
        try {
            HttpRequest req = new HttpRequest();
            req.setEndpoint(endpoint);
            HttpResponse response = new Http().send(req);
            
            if (response.getStatusCode() != 200) {
                throw new CalloutException('API call failed: ' + response.getStatusCode());
            }
        } catch (Exception e) {
            System.debug('Integration error: ' + e.getMessage()); // ❌ Replace this
            throw e;
        }
    }
}

// ✅ Phase 1: Replace System.debug (Low Risk)
public class LegacyIntegrationService {
    public static void callExternalAPI(String endpoint) {
        try {
            HttpRequest req = new HttpRequest();
            req.setEndpoint(endpoint);
            HttpResponse response = new Http().send(req);
            
            if (response.getStatusCode() != 200) {
                throw new CalloutException('API call failed: ' + response.getStatusCode());
            }
        } catch (Exception e) {
            // ✅ Simple replacement - low risk
            if (LoggingSettings__c.getInstance().EnableTritonLogging__c) {
                Triton.instance.log(
                    Triton.makeBuilder()
                        .category(TritonTypes.Category.Integration)
                        .type(TritonTypes.Type.Backend)
                        .area(TritonTypes.Area.ExternalAPI)
                        .exception(e)
                        .summary('External API call failed')
                        .details('endpoint=' + endpoint)
                );
            }
            throw e;
        }
    }
}

// ✅ Phase 2: Enhanced logging (Higher Risk)
public class LegacyIntegrationService {
    public static void callExternalAPI(String endpoint) {
        Long startTime = System.now().getTime();
        
        try {
            HttpRequest req = new HttpRequest();
            req.setEndpoint(endpoint);
            HttpResponse response = new Http().send(req);
            
            if (response.getStatusCode() == 200) {
                // ✅ Log success with context
                if (LoggingSettings__c.getInstance().EnableTritonLogging__c) {
                    Triton.instance.log(
                        Triton.makeBuilder()
                            .category(TritonTypes.Category.Integration)
                            .type(TritonTypes.Type.Backend)
                            .area(TritonTypes.Area.ExternalAPI)
                            .summary('External API call successful')
                            .details('endpoint=' + endpoint + ', statusCode=' + response.getStatusCode())
                            .integrationPayload(req, response)
                            .duration(System.now().getTime() - startTime)
                    );
                }
            } else {
                throw new CalloutException('API call failed: ' + response.getStatusCode());
            }
        } catch (Exception e) {
            // ✅ Enhanced error logging
            if (LoggingSettings__c.getInstance().EnableTritonLogging__c) {
                Triton.instance.log(
                    Triton.makeBuilder()
                        .category(TritonTypes.Category.Integration)
                        .type(TritonTypes.Type.Backend)
                        .area(TritonTypes.Area.ExternalAPI)
                        .exception(e)
                        .summary('External API call failed')
                        .details('endpoint=' + endpoint)
                        .integrationPayload(req, null)
                        .duration(System.now().getTime() - startTime)
                );
            }
            throw e;
        }
    }
}
```

#### Pattern C: Error Handling with Custom Logging Framework

**Current State**: Code uses a custom logging framework (e.g., custom Log class, third-party logging).

**Risk Level**: **Low to High Risk** (depending on implementation)

**Recommended Approach**:

* **Phase 1 (Low Risk)**: Modify existing logging framework to pass data to Triton
* **Phase 2 (Medium Risk)**: Replace logging calls if insufficient data is being passed
* **Phase 3 (High Risk)**: Complete replacement with Triton

**Example**:

```apex
// ❌ Current custom logging framework
public class CustomLogger {
    public static void logError(String message, Exception e) {
        // Custom logging implementation
        Log__c log = new Log__c(
            Message__c = message,
            Error__c = e.getMessage(),
            Timestamp__c = System.now()
        );
        insert log;
    }
}

// ✅ Phase 1: Modify to use Triton (Low Risk)
public class CustomLogger {
    public static void logError(String message, Exception e) {
        // Keep existing logging for backward compatibility
        Log__c log = new Log__c(
            Message__c = message,
            Error__c = e.getMessage(),
            Timestamp__c = System.now()
        );
        insert log;
        
        // ✅ Add Triton logging if enabled
        if (LoggingSettings__c.getInstance().EnableTritonLogging__c) {
            Triton.instance.log(
                Triton.makeBuilder()
                    .category(TritonTypes.Category.Apex)
                    .type(TritonTypes.Type.Backend)
                    .area(TritonTypes.Area.General)
                    .exception(e)
                    .summary(message)
            );
        }
    }
}

// ✅ Phase 2: Enhanced data passing (Medium Risk)
public class CustomLogger {
    public static void logError(String message, Exception e, String context, Id relatedObjectId) {
        // Keep existing logging for backward compatibility
        Log__c log = new Log__c(
            Message__c = message,
            Error__c = e.getMessage(),
            Timestamp__c = System.now(),
            Context__c = context,
            RelatedObjectId__c = relatedObjectId
        );
        insert log;
        
        // ✅ Enhanced Triton logging with more context
        if (LoggingSettings__c.getInstance().EnableTritonLogging__c) {
            Triton.instance.log(
                Triton.makeBuilder()
                    .category(TritonTypes.Category.Apex)
                    .type(TritonTypes.Type.Backend)
                    .area(TritonTypes.Area.General)
                    .exception(e)
                    .summary(message)
                    .details('context=' + context)
                    .relatedObject(relatedObjectId)
            );
        }
    }
}
```

## Implementation Strategy by Comfort Level

### High Comfort Level - Aggressive Approach

**Timeline**: 2-4 weeks **Risk Tolerance**: High **Approach**: Direct replacement with comprehensive logging

**Strategy**:

1. **Week 1**: Set up Triton infrastructure and templates
2. **Week 2**: Replace System.debug statements with Triton logging
3. **Week 3**: Add comprehensive exception handling and context
4. **Week 4**: Implement transaction correlation and advanced patterns

### Medium Comfort Level - Balanced Approach

**Timeline**: 4-8 weeks **Risk Tolerance**: Medium **Approach**: Gradual replacement with feature flags

**Strategy**:

1. **Weeks 1-2**: Set up infrastructure and create logging templates
2. **Weeks 3-4**: Implement feature flags and basic logging replacement
3. **Weeks 5-6**: Add exception handling with dual logging (old + new)
4. **Weeks 7-8**: Transition to Triton-only logging

### Low Comfort Level - Conservative Approach

**Timeline**: 8-16 weeks **Risk Tolerance**: Low **Approach**: Minimal changes with extensive testing

**Strategy**:

1. **Weeks 1-4**: Set up infrastructure and create comprehensive test suite
2. **Weeks 5-8**: Implement feature flags and basic exception logging
3. **Weeks 9-12**: Add logging to non-critical paths only
4. **Weeks 13-16**: Gradually expand to critical paths with extensive monitoring

## Risk Mitigation Strategies

### Feature Flags and Dual Logging

```apex
// Custom Setting for controlling logging behavior
public class LoggingSettings__c {
    public Boolean EnableTritonLogging__c;
    public Boolean EnableLegacyLogging__c;
    public Boolean EnableDualLogging__c;
    public String LogLevel__c; // DEBUG, INFO, WARNING, ERROR
}

// Safe logging wrapper
public class SafeLogger {
    public static void logError(String message, Exception e, String context) {
        LoggingSettings__c settings = LoggingSettings__c.getInstance();
        
        // Legacy logging (if enabled)
        if (settings.EnableLegacyLogging__c || settings.EnableDualLogging__c) {
            // Existing logging logic
            CustomLogger.logError(message, e);
        }
        
        // Triton logging (if enabled)
        if (settings.EnableTritonLogging__c || settings.EnableDualLogging__c) {
            try {
                Triton.instance.log(
                    Triton.makeBuilder()
                        .category(TritonTypes.Category.Apex)
                        .type(TritonTypes.Type.Backend)
                        .area(TritonTypes.Area.General)
                        .exception(e)
                        .summary(message)
                        .details('context=' + context)
                );
            } catch (Exception loggingError) {
                // Don't let logging errors break the main flow
                System.debug('Logging error: ' + loggingError.getMessage());
            }
        }
    }
}
```

### Comprehensive Testing

```apex
// Test class for legacy code changes
@IsTest
public class LegacyCodeLoggingTest {
    @TestSetup
    static void setup() {
        // Create test data
        LoggingSettings__c settings = new LoggingSettings__c(
            EnableTritonLogging__c = true,
            EnableLegacyLogging__c = false,
            EnableDualLogging__c = false
        );
        insert settings;
    }
    
    @IsTest
    static void testLegacyIntegrationWithLogging() {
        // Test that logging doesn't break existing functionality
        Test.startTest();
        
        // Test normal operation
        LegacyIntegrationService.callExternalAPI('https://test.endpoint.com');
        
        // Test error scenarios
        try {
            LegacyIntegrationService.callExternalAPI('https://invalid.endpoint.com');
        } catch (Exception e) {
            // Expected error
        }
        
        Test.stopTest();
        
        // Verify logs were created
        List<pharos__Log__c> logs = [SELECT Id FROM pharos__Log__c WHERE CreatedDate = TODAY];
        System.assert(logs.size() > 0, 'Logs should be created');
    }
}
```

## Success Metrics and Monitoring

### Implementation Metrics

* **Code Coverage**: Maintain or improve existing test coverage
* **Error Rates**: Monitor for any increase in errors after logging changes
* **Performance Impact**: Measure execution time before and after changes
* **Log Quality**: Track percentage of logs with proper context and taxonomy

### Business Metrics

* **MTTR**: Mean time to resolution for issues
* **Support Ticket Volume**: Reduction in tickets due to better debugging
* **System Reliability**: No degradation in system stability
* **Developer Productivity**: Faster debugging and issue resolution

### Rollback Plan

**Immediate Rollback**:

```apex
// Emergency rollback method
public class LoggingRollback {
    public static void disableTritonLogging() {
        LoggingSettings__c settings = LoggingSettings__c.getInstance();
        settings.EnableTritonLogging__c = false;
        settings.EnableLegacyLogging__c = true;
        update settings;
    }
}
```

## Best Practices for Legacy Migration

### Do's

* ✅ **Start with non-critical paths** to build confidence
* ✅ **Use feature flags** to control logging behavior
* ✅ **Implement dual logging** during transition periods
* ✅ **Test extensively** before making changes to critical code
* ✅ **Monitor closely** after each change
* ✅ **Document all changes** for future reference
* ✅ **Have a rollback plan** ready for emergencies

### Don'ts

* ❌ **Don't modify critical business logic** without extensive testing
* ❌ **Don't remove existing logging** until Triton is proven stable
* ❌ **Don't make changes during business hours** without proper testing
* ❌ **Don't ignore performance impact** of logging changes
* ❌ **Don't skip monitoring** after implementation
* ❌ **Don't assume all code is safe** to modify

By following this risk-based approach, organizations can successfully implement Triton logging in legacy systems while minimizing the risk of disrupting critical business processes. The key is to understand your comfort level with the codebase and choose an implementation strategy that matches your risk tolerance.
