CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-apache-logging-log4j--log4j-jul

The Apache Log4j implementation of java.util.logging providing JUL to Log4j bridge functionality

Pending
Overview
Eval results
Files

level-translation.mddocs/

Level Translation

The level translation system provides bidirectional conversion between Java Util Logging (JUL) levels and Log4j levels, with support for custom levels and intelligent closest-match mapping for non-standard level values.

Overview

Level translation is essential for proper log filtering and routing when bridging JUL to Log4j. The system provides:

  • Standard Mappings: Predefined conversions between common JUL and Log4j levels
  • Custom Levels: Special Log4j levels for JUL-specific levels (FINEST, CONFIG)
  • Dynamic Mapping: Closest-match algorithm for custom or non-standard levels
  • Pluggable Converters: Interface for custom level conversion strategies

Standard Level Mappings

JUL to Log4j

JUL LevelLog4j LevelNotes
ALLALLBoth represent unlimited logging
FINESTFINESTCustom Log4j level (TRACE + 100)
FINERTRACEFine-grained debugging
FINEDEBUGStandard debugging
CONFIGCONFIGCustom Log4j level (INFO + 50)
INFOINFOInformational messages
WARNINGWARNWarning conditions
SEVEREERRORError conditions
OFFOFFNo logging

Log4j to JUL

Log4j LevelJUL LevelNotes
ALLALLBoth represent unlimited logging
FINESTFINESTCustom Log4j level maps back
TRACEFINERFine-grained debugging
DEBUGFINEStandard debugging
CONFIGCONFIGCustom Log4j level maps back
INFOINFOInformational messages
WARNWARNINGWarning conditions
ERRORSEVEREError conditions
FATALSEVERECritical errors map to SEVERE
OFFOFFNo logging

Usage

Basic Level Conversion

import org.apache.logging.log4j.jul.LevelTranslator;
import org.apache.logging.log4j.Level;

// Convert JUL level to Log4j level
java.util.logging.Level julLevel = java.util.logging.Level.INFO;
Level log4jLevel = LevelTranslator.toLevel(julLevel);

// Convert Log4j level to JUL level  
Level log4jError = Level.ERROR;
java.util.logging.Level julSevere = LevelTranslator.toJavaLevel(log4jError);

// Handle null values (JUL allows null levels)
Level result = LevelTranslator.toLevel(null); // returns null

Custom Level Handling

The translator automatically handles custom levels by finding the closest standard level:

// Custom JUL level between FINE and INFO
java.util.logging.Level customLevel = new java.util.logging.Level("CUSTOM", 750) {};

// Automatically maps to closest Log4j level (DEBUG in this case)
Level mapped = LevelTranslator.toLevel(customLevel);

API Reference

LevelTranslator Class

public final class LevelTranslator {
    /**
     * Custom Log4j level corresponding to JUL FINEST.
     * Maps to TRACE + 100 for more specific than standard TRACE.
     */
    public static final Level FINEST = Level.forName("FINEST", Level.TRACE.intLevel() + 100);
    
    /**
     * Custom Log4j level corresponding to JUL CONFIG.
     * Maps to INFO + 50 for level between INFO and DEBUG.
     */
    public static final Level CONFIG = Level.forName("CONFIG", Level.INFO.intLevel() + 50);
    
    /**
     * Converts a JUL logging Level to a Log4j logging Level.
     * Uses pluggable LevelConverter for actual conversion.
     * 
     * @param level JUL Level to convert, may be null per JUL specification
     * @return converted Log4j Level or null if input was null
     */
    public static Level toLevel(java.util.logging.Level level);
    
    /**
     * Converts a Log4j logging Level to a JUL logging Level.
     * Uses pluggable LevelConverter for actual conversion.
     * 
     * @param level Log4j Level to convert, must not be null
     * @return converted JUL Level
     */
    public static java.util.logging.Level toJavaLevel(Level level);
}

LevelConverter Interface

public interface LevelConverter {
    /**
     * Converts a JUL logging Level to a Log4j logging Level.
     * Implementation should handle null values and custom levels.
     * 
     * @param javaLevel JUL Level to convert, may be null per JUL specification
     * @return converted Log4j Level or null if conversion not possible
     */
    Level toLevel(java.util.logging.Level javaLevel);
    
    /**
     * Converts a Log4j logging Level to a JUL logging Level.
     * Implementation should handle all standard and custom Log4j levels.
     * 
     * @param level Log4j Level to convert, should not be null
     * @return converted JUL Level or null if conversion not possible
     */
    java.util.logging.Level toJavaLevel(Level level);
}

DefaultLevelConverter Class

public class DefaultLevelConverter implements LevelConverter {
    /**
     * Creates converter with standard level mappings and custom level support.
     * Initializes bidirectional mapping tables and sorted level list for nearest matching.
     */
    public DefaultLevelConverter();
    
    /**
     * Converts JUL level to Log4j level with custom level support.
     * For unknown levels, finds the nearest mapped level by numeric value.
     * 
     * @param javaLevel JUL Level to convert
     * @return corresponding Log4j Level or nearest match for custom levels
     */
    public Level toLevel(java.util.logging.Level javaLevel);
    
    /**
     * Converts Log4j level to JUL level using direct mapping.
     * 
     * @param level Log4j Level to convert
     * @return corresponding JUL Level or null if not mapped
     */
    public java.util.logging.Level toJavaLevel(Level level);
}

Custom Level Converter

You can provide a custom level converter implementation:

public class CustomLevelConverter implements LevelConverter {
    @Override
    public Level toLevel(java.util.logging.Level javaLevel) {
        if (javaLevel == null) return null;
        
        // Custom conversion logic
        if (javaLevel.getName().equals("AUDIT")) {
            return Level.forName("AUDIT", 450); // Between INFO and WARN
        }
        
        // Fall back to default behavior
        return new DefaultLevelConverter().toLevel(javaLevel);
    }
    
    @Override  
    public java.util.logging.Level toJavaLevel(Level level) {
        // Custom reverse conversion
        if ("AUDIT".equals(level.name())) {
            return java.util.logging.Level.parse("AUDIT");
        }
        
        return new DefaultLevelConverter().toJavaLevel(level);
    }
}

// Configure custom converter
System.setProperty("log4j.jul.levelConverter", "com.example.CustomLevelConverter");

Custom Level Support

Nearest Level Algorithm

For unknown JUL levels, the DefaultLevelConverter finds the nearest mapped level:

  1. Calculate Distance: Compute numeric distance between custom level and all known levels
  2. Find Minimum: Select the known level with smallest distance
  3. Cache Result: Store mapping for future lookups
  4. Return Mapping: Return the Log4j level corresponding to nearest JUL level
// Example: Custom level with value 650 (between FINE=500 and CONFIG=700)
java.util.logging.Level custom = new java.util.logging.Level("CUSTOM", 650) {};

// Nearest is CONFIG (700), so maps to LevelTranslator.CONFIG
Level result = LevelTranslator.toLevel(custom);

Performance Optimization

  • Caching: Custom level mappings are cached after first lookup
  • Sorted Search: Binary search through sorted level list
  • Static Initialization: Standard mappings pre-populated at class loading

Configuration

Level Converter Selection

The level converter is selected during static initialization:

  1. Custom Converter: If log4j.jul.levelConverter property is set
  2. Default Converter: Falls back to DefaultLevelConverter
// Set custom converter class
System.setProperty("log4j.jul.levelConverter", "com.example.MyLevelConverter");

Requirements for Custom Converters

Custom LevelConverter implementations must:

  • Have a public no-argument constructor
  • Handle null input values gracefully
  • Be thread-safe for concurrent access
  • Provide reasonable mappings for standard levels

Integration with Bridge Components

LogManager Integration

  • Automatic Translation: All JUL logging calls automatically use level translation
  • Bi-directional: Supports both JUL→Log4j and Log4j→JUL conversions
  • Transparent: No code changes required in application

Bridge Handler Integration

  • Event Processing: Translates levels for each published LogRecord
  • Level Propagation: Uses reverse translation for propagating Log4j levels to JUL
  • Performance: Efficient translation with minimal overhead

Error Handling

The level translation system handles various error conditions:

// Null handling (per JUL specification)
Level result = LevelTranslator.toLevel(null); // returns null

// Custom converter loading failures
try {
    CustomConverter converter = LoaderUtil.newCheckedInstanceOf(className, LevelConverter.class);
} catch (Exception e) {
    LOGGER.error("Could not create custom LevelConverter [{}].", className, e);
    // Falls back to DefaultLevelConverter
}

// Graceful degradation for unknown levels
Level fallback = nearestLevel(unknownLevel); // finds closest match

Thread Safety

All level translation components are fully thread-safe:

  • Static Fields: FINEST and CONFIG levels are immutable
  • Concurrent Maps: DefaultLevelConverter uses ConcurrentHashMap for caching
  • Immutable Mappings: Standard level mappings are immutable after initialization
  • Atomic Operations: Level lookup and caching operations are atomic

Install with Tessl CLI

npx tessl i tessl/maven-org-apache-logging-log4j--log4j-jul

docs

bridge-handler.md

index.md

level-translation.md

logger-adapters.md

logmanager-integration.md

tile.json