Log Levels

This article explains how log levels work in Triton and how to configure them using custom metadata.

Log levels provide a powerful mechanism to control the verbosity of logging output across your Salesforce org. Triton implements a hierarchical log level system that allows you to filter logs based on their severity, ensuring that only relevant information is captured and stored.

Understanding Log Levels

Log levels in Triton follow a standard hierarchy from least verbose to most verbose:

  • ERROR - Critical errors that require immediate attention

  • WARNING - Issues that may need attention but aren't critical

  • INFO - General information about application flow

  • DEBUG - Detailed debugging information

  • FINE - Fine-grained debugging information

  • FINER - Very detailed debugging information

  • FINEST - Most detailed debugging information

The fundamental principle is that if you set a log level, only logs with that level or higher (more critical) will be persisted. For example, if you set the log level to INFO, only ERROR, WARNING, and INFO logs will be saved, while DEBUG, FINE, FINER, and FINEST logs will be filtered out.

Custom Metadata Configuration

Triton uses the Log_Level__mdt custom metadata type to control log levels. This metadata type contains four fields:

  • Category - The log category (e.g., Apex, Flow, LWC, Integration)

  • Type - The log type (e.g., Backend, Frontend, DMLResult)

  • Area - The functional area (e.g., Accounts, Opportunities, LeadConversion)

  • Level - The minimum log level to capture (ERROR, WARNING, INFO, DEBUG, FINE, FINER, FINEST)

Org-Wide Log Level

To set a default log level for your entire org, create a metadata record with all three classification fields (Category, Type, Area) left blank. This serves as a catch-all configuration that applies when no more specific rules match.

Example:

Category: (blank)
Type: (blank)
Area: (blank)
Level: INFO

This configuration would ensure that only ERROR, WARNING, and INFO logs are captured across all categories, types, and areas unless overridden by more specific rules.

Refined Log Level Control

You can create more specific log level rules by populating one or more of the classification fields. The system uses a hierarchical matching approach:

  1. Exact Match - Category, Type, and Area all match

  2. Partial Matches - Various combinations of Category, Type, and Area

  3. Fallback - Org-wide default (all fields blank)

Example Configurations:

# All Apex logs at DEBUG level
Category: Apex
Type: (blank)
Area: (blank)
Level: DEBUG

# All Flow logs at INFO level
Category: Flow
Type: (blank)
Area: (blank)
Level: INFO

# Account-related Apex logs at FINE level
Category: Apex
Type: (blank)
Area: Accounts
Level: FINE

# Integration errors always captured
Category: Integration
Type: (blank)
Area: (blank)
Level: ERROR

Implementation in TritonBuilder

The TritonBuilder class provides the level() method to set log levels on individual log entries:

public TritonBuilder level(TritonTypes.Level l)

This method accepts a TritonTypes.Level enum value and sets it on the log record. The system then compares this level against the configured metadata rules to determine whether the log should be persisted.

Example Usage:

Triton.instance.addLog(
    Triton.makeBuilder()
        .category(TritonTypes.Category.Apex)
        .type(TritonTypes.Type.Backend)
        .area(TritonTypes.Area.Accounts)
        .summary('Account processing started')
        .details('Processing account: 001xx000003DGb2AAG')
        .level(TritonTypes.Level.DEBUG)
);

Log Level Filtering Logic

When a log is created, Triton performs the following steps to determine if it should be persisted:

  1. Build Matching Keys - Creates various combinations of Category, Type, and Area

  2. Check Metadata Rules - Looks for matching rules in the Log_Level__mdt metadata

  3. Compare Levels - Compares the log's level against the configured minimum level

  4. Filter Decision - Only persists logs that meet or exceed the minimum level

The system checks rules in order of specificity, from most specific (all three fields populated) to least specific (org-wide default).

Practical Examples

Environment-Specific Configuration

The logging code remains the same across all environments. What changes is the metadata configuration that controls which logs are actually persisted:

Development Environment Metadata:

Category: Apex
Type: (blank)
Area: (blank)
Level: DEBUG

Production Environment Metadata:

Category: Apex
Type: (blank)
Area: (blank)
Level: INFO

Same Logging Code:

Triton.instance.addLog(
    Triton.makeBuilder()
        .category(TritonTypes.Category.Apex)
        .type(TritonTypes.Type.Backend)
        .area(TritonTypes.Area.Accounts)
        .summary('Account validation started')
        .details('Validating account data: ' + accountData)
        .level(TritonTypes.Level.DEBUG)  // Same level in both environments
);

In development, this DEBUG log would be captured. In production, it would be filtered out based on the INFO-level configuration.

Error Handling

Errors should always be logged at the ERROR level:

try {
    // Business logic
    processAccount(account);
} catch (Exception e) {
    // Always log errors
    Triton.instance.addError(TritonTypes.Area.Accounts, e);
}

Log Levels are Ubiquitos

The log level concept applies consistently across all Triton logging capabilities:

Apex Logging

Triton.instance.addEvent(
    TritonTypes.Level.DEBUG,  // Set log level
    TritonTypes.Type.Backend,
    TritonTypes.Area.Accounts,
    'Account processing',
    'Processing account data'
);

LWC Logging

this.tritonLogger.log(
    this.tritonLogger.debug(TYPE.BACKEND, AREA.ACCOUNTS)
        .summary('Account data loaded')
        .details(JSON.stringify(accountData))
        .level(LEVEL.DEBUG)  // Set log level
);

Flow Logging

When using the Triton Flow action, you can set the log level parameter to control verbosity:

Level: DEBUG
Summary: Account validation completed
Details: Account {!Account.Id} validated successfully

Best Practices

1. Start Conservative

Begin with INFO level in production and adjust based on your monitoring needs. You can always increase verbosity for specific areas when troubleshooting.

2. Use Specific Rules

Create targeted log level rules for different functional areas rather than relying solely on org-wide defaults.

3. Monitor Log Volume

Keep an eye on log volume and adjust levels accordingly. Too much logging can impact performance and storage costs.

4. Error Logging

Always log errors at the ERROR level - these should never be filtered out as they represent actual problems that need attention.

5. Development vs Production

Use different log level configurations for development and production environments. Development can use DEBUG or FINE levels, while production should typically use INFO or WARNING levels.

Real-World Scenarios

Scenario 1: Account Processing System

// Metadata Configuration
// Category: Apex, Type: (blank), Area: Accounts, Level: INFO

// In your code
Triton.instance.addLog(
    Triton.makeBuilder()
        .category(TritonTypes.Category.Apex)
        .area(TritonTypes.Area.Accounts)
        .summary('Account validation started')
        .level(TritonTypes.Level.INFO)  // Will be logged
);

Triton.instance.addLog(
    Triton.makeBuilder()
        .category(TritonTypes.Category.Apex)
        .area(TritonTypes.Area.Accounts)
        .summary('Detailed validation step')
        .level(TritonTypes.Level.DEBUG)  // Will be filtered out
);

Scenario 2: Integration Monitoring

// Metadata Configuration
// Category: Integration, Type: (blank), Area: (blank), Level: ERROR

// In your integration code
Triton.instance.addLog(
    Triton.makeBuilder()
        .category(TritonTypes.Category.Integration)
        .summary('API call successful')
        .level(TritonTypes.Level.INFO)  // Will be filtered out
);

// Only errors will be logged
Triton.instance.addIntegrationError(
    TritonTypes.Area.ExternalAPI,
    apiException,
    httpRequest,
    httpResponse
);

Scenario 3: Flow Debugging

// Metadata Configuration
// Category: Flow, Type: (blank), Area: (blank), Level: DEBUG

// In Flow, use the Triton action with:
// Level: DEBUG
// Summary: Flow decision point reached
// Details: Decision criteria met: {!decisionResult}

Choosing Appropriate Log Levels

Understanding when to use each log level is crucial for effective logging. Here's guidance on which types of information belong at each level:

ERROR Level

Use for critical failures that require immediate attention:

  • Unhandled exceptions and system errors

  • Integration failures that break business processes

  • Data corruption or loss scenarios

  • Security violations or authentication failures

  • System resource exhaustion (CPU, memory, governor limits)

try {
    processAccount(account);
} catch (Exception e) {
    Triton.instance.addError(TritonTypes.Area.Accounts, e);
}

WARNING Level

Use for issues that may need attention but aren't critical:

  • Deprecated feature usage

  • Performance degradation indicators

  • Business rule violations that don't break the process

  • Retry scenarios and temporary failures

  • Approaching governor limits

// Check if we're approaching governor limits
if (System.Limits.getQueries() > System.Limits.getLimitQueries() * 0.8) {
    Triton.instance.addWarning(
        TritonTypes.Type.Backend,
        TritonTypes.Area.Accounts,
        'Approaching SOQL query limit',
        'Used: ' + System.Limits.getQueries() + 
        ', Limit: ' + System.Limits.getLimitQueries() + 
        ', Remaining: ' + (System.Limits.getLimitQueries() - System.Limits.getQueries())
    );
}

INFO Level

Use for important business events and milestones:

  • Record creation, updates, and deletions

  • Process completion and major workflow steps

  • User actions and business transactions

  • Integration success and data synchronization

  • Scheduled job execution and completion

Triton.instance.addEvent(
    TritonTypes.Type.Backend,
    TritonTypes.Area.Accounts,
    'Account created successfully',
    'Account ID: ' + newAccount.Id + ', Owner: ' + newAccount.OwnerId
);

DEBUG Level

Use for detailed debugging information:

  • Method entry and exit points

  • Variable values and state changes

  • Decision points in business logic

  • Query results and data transformations

  • Performance timing information

Triton.instance.addDebug(
    TritonTypes.Type.Backend,
    TritonTypes.Area.Accounts,
    'Account validation started',
    'Validating account: ' + account.Id + ', Industry: ' + account.Industry
);

FINE Level

Use for fine-grained debugging and code flow tracking:

  • Loop iterations and collection processing

  • Conditional branch execution

  • Detailed parameter values

  • Minor state transitions

  • Helper method execution

Triton.instance.addEvent(
    TritonTypes.Level.FINE,
    TritonTypes.Type.Backend,
    TritonTypes.Area.Accounts,
    'Processing account field',
    'Field: Industry, Value: ' + account.Industry + ', Validation: passed'
);

FINER Level

Use for very detailed debugging when troubleshooting complex issues:

  • Individual record processing in bulk operations

  • Detailed stack trace analysis

  • Memory usage and performance metrics

  • Network call details and response parsing

  • Complex algorithm step-by-step execution

Triton.instance.addEvent(
    TritonTypes.Level.FINER,
    TritonTypes.Type.Backend,
    TritonTypes.Area.Accounts,
    'Bulk account processing iteration',
    'Processing record ' + (i + 1) + ' of ' + accounts.size() + 
    ', Account: ' + account.Id + ', Status: ' + processingStatus
);

FINEST Level

Use for the most detailed debugging information:

  • Individual character processing in string operations

  • Bit-level operations and data structure details

  • Memory allocation and garbage collection events

  • Network packet-level information

  • Detailed timing for micro-optimizations

Triton.instance.addEvent(
    TritonTypes.Level.FINEST,
    TritonTypes.Type.Backend,
    TritonTypes.Area.Accounts,
    'String processing detail',
    'Processing character ' + (j + 1) + ' of ' + fieldValue.length() + 
    ', Character: "' + fieldValue.charAt(j) + '", ASCII: ' + (int)fieldValue.charAt(j)
);

Log Level Guidelines

General Principles

  • ERROR: Something is broken and needs immediate attention

  • WARNING: Something might be wrong, but the system can continue

  • INFO: Important business events that stakeholders should know about

  • DEBUG: Detailed information useful for troubleshooting

  • FINE: Fine-grained debugging for complex issues

  • FINER: Very detailed debugging for deep troubleshooting

  • FINEST: Extremely detailed debugging for performance optimization

Performance Considerations

  • Higher log levels (FINE, FINER, FINEST) can impact performance

  • String concatenation and object serialization in logs should be minimized

  • Consider using conditional logging for expensive operations

  • Monitor log volume and adjust levels based on system performance

Environment-Specific Recommendations

  • Development: DEBUG or FINE level for comprehensive debugging

  • Staging: INFO level to simulate production behavior

  • Production: INFO or WARNING level to focus on business events

  • Troubleshooting: Temporarily increase to DEBUG or FINE as needed

By understanding and properly configuring log levels, you can maintain comprehensive visibility into your application's behavior while keeping log volumes manageable and focused on the information that matters most for your specific use case.

Last updated