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

logger-adapters.mddocs/

Logger Adapters

The logger adapter system provides a pluggable architecture for bridging JUL Logger instances to different Log4j implementations. It automatically selects the most appropriate adapter based on available Log4j components and supports custom adapter implementations.

Overview

Logger adapters bridge the gap between JUL's Logger interface and Log4j's logging infrastructure. The system provides:

  • Automatic Selection: Chooses optimal adapter based on available Log4j components
  • Custom Override: Supports custom adapter implementations via configuration
  • Context Management: Handles LoggerContext lifecycle and isolation
  • Performance Optimization: Minimizes overhead through efficient logger creation

Adapter Hierarchy

AbstractLoggerAdapter (abstract base)
├── ApiLoggerAdapter (log4j-api only)
└── CoreLoggerAdapter (log4j-core available)

Adapter Selection Process

The LogManager selects adapters in the following priority order:

  1. Custom Adapter: If log4j.jul.LoggerAdapter property is set
  2. CoreLoggerAdapter: If log4j-core is available on classpath
  3. ApiLoggerAdapter: Fallback when only log4j-api is available
// Selection logic
String customAdapterClass = PropertiesUtil.getProperties()
    .getStringProperty(Constants.LOGGER_ADAPTOR_PROPERTY);

if (customAdapterClass != null) {
    // Try to load custom adapter
    adapter = LoaderUtil.newCheckedInstanceOf(customAdapterClass, AbstractLoggerAdapter.class);
} else {
    // Default to ApiLoggerAdapter (CoreLoggerAdapter detection is automatic)
    adapter = new ApiLoggerAdapter();
}

Usage

Automatic Selection

Most applications use automatic adapter selection:

// Set LogManager - adapter selection is automatic
System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager");

// Standard JUL usage - adapter works transparently
java.util.logging.Logger logger = java.util.logging.Logger.getLogger("com.example");
logger.info("Message logged through selected adapter");

Custom Adapter Configuration

// Configure custom adapter via system property
System.setProperty("log4j.jul.LoggerAdapter", "com.example.CustomLoggerAdapter");

// Or via log4j2.properties
// log4j.jul.LoggerAdapter=com.example.CustomLoggerAdapter

API Reference

AbstractLoggerAdapter

public abstract class AbstractLoggerAdapter extends org.apache.logging.log4j.spi.AbstractLoggerAdapter<Logger> {
    /**
     * Gets the appropriate LoggerContext for the current execution context.
     * Considers classloader dependency and caller class for context isolation.
     * 
     * @return LoggerContext for creating loggers
     */
    protected LoggerContext getContext();
    
    /**
     * Creates a new Logger instance for the given name and context.
     * Implementation varies based on available Log4j components.
     * 
     * @param name the logger name
     * @param context the LoggerContext 
     * @return new Logger instance
     */
    protected abstract Logger newLogger(String name, LoggerContext context);
}

ApiLoggerAdapter

public class ApiLoggerAdapter extends AbstractLoggerAdapter {
    /**
     * Creates ApiLogger instances using only log4j-api components.
     * Uses MessageFormatMessageFactory for JUL-style message formatting.
     * 
     * @param name the logger name
     * @param context the LoggerContext
     * @return new ApiLogger instance
     */
    protected Logger newLogger(String name, LoggerContext context);
}

CoreLoggerAdapter

public class CoreLoggerAdapter extends AbstractLoggerAdapter {
    /**
     * Creates enhanced Logger instances when log4j-core is available.
     * Returns CoreLogger for full functionality or ApiLogger as fallback.
     * 
     * @param name the logger name
     * @param context the LoggerContext
     * @return new CoreLogger or ApiLogger instance
     */
    protected Logger newLogger(String name, LoggerContext context);
}

Logger Implementations

ApiLogger

The ApiLogger provides JUL Logger implementation using only log4j-api:

// Created by ApiLoggerAdapter
java.util.logging.Logger logger = java.util.logging.Logger.getLogger("example");

// Full JUL API support with some limitations
logger.info("Standard logging works");
logger.log(java.util.logging.Level.WARNING, "Parameterized message: {0}", value);

// Limitations due to log4j-api constraints
logger.setLevel(java.util.logging.Level.DEBUG); // Limited support
Logger parent = logger.getParent(); // May not be accurate

ApiLogger Features:

  • Complete JUL Logger interface implementation
  • Delegates to underlying Log4j ExtendedLogger
  • MessageFormatMessageFactory for JUL-style parameter substitution
  • Limited setLevel() and getParent() support due to API constraints

CoreLogger

The CoreLogger provides enhanced functionality when log4j-core is available:

// Created by CoreLoggerAdapter when log4j-core is present
java.util.logging.Logger logger = java.util.logging.Logger.getLogger("example");

// Enhanced functionality with full JUL API support
logger.setLevel(java.util.logging.Level.DEBUG); // Full support
Logger parent = logger.getParent(); // Accurate parent relationships
logger.setFilter(customFilter); // Full filter support

CoreLogger Features:

  • Full JUL Logger interface implementation
  • Complete level management support
  • Accurate parent-child relationships
  • Enhanced performance through log4j-core integration

Context Management

LoggerContext Selection

The adapter system handles LoggerContext selection based on:

  1. ClassLoader Dependency: Uses appropriate context for classloader isolation
  2. Caller Context: Determines caller class for context selection
  3. Factory Configuration: Respects LoggerFactory configuration
// Context selection logic in AbstractLoggerAdapter
protected LoggerContext getContext() {
    return getContext(
        LogManager.getFactory().isClassLoaderDependent() 
            ? StackLocatorUtil.getCallerClass(java.util.logging.LogManager.class)
            : null
    );
}

Context Isolation

Different contexts allow for:

  • Separate Configurations: Each context can have independent log4j2.xml
  • ClassLoader Isolation: Prevents configuration conflicts between applications
  • Resource Management: Proper cleanup when contexts are destroyed

Custom Adapter Implementation

Create custom adapters for specialized requirements:

public class CustomLoggerAdapter extends AbstractLoggerAdapter {
    
    @Override
    protected Logger newLogger(String name, LoggerContext context) {
        // Custom logger creation logic
        ExtendedLogger log4jLogger = context.getLogger(name, customMessageFactory);
        
        // Return custom logger implementation
        return new CustomJulLogger(log4jLogger);
    }
    
    // Custom logger implementation
    private static class CustomJulLogger extends java.util.logging.Logger {
        private final ExtendedLogger delegate;
        
        CustomJulLogger(ExtendedLogger delegate) {
            super(delegate.getName(), null);
            this.delegate = delegate;
        }
        
        @Override
        public void info(String msg) {
            // Custom logging behavior
            delegate.info("[CUSTOM] " + msg);
        }
        
        // Implement other Logger methods...
    }
}

Custom Adapter Requirements

Custom adapters must:

  • Extend AbstractLoggerAdapter
  • Implement newLogger(String, LoggerContext) method
  • Have a public no-argument constructor
  • Be thread-safe for concurrent logger creation
  • Handle context lifecycle properly

Performance Considerations

Adapter Selection Overhead

  • One-time Cost: Adapter selection occurs once during LogManager construction
  • Fast Path: No selection overhead during normal logging operations
  • Caching: Created loggers are cached by the adapter registry

Logger Creation Performance

  • Lazy Creation: Loggers created on-demand when first requested
  • Context Reuse: LoggerContext instances are reused across loggers
  • Message Factory Reuse: Static MessageFactory instances minimize object creation

Memory Management

  • Weak References: Logger registry uses weak references to prevent memory leaks
  • Context Cleanup: Proper cleanup when LoggerContext is shut down
  • Resource Sharing: Shared resources between logger instances

Error Handling

Adapter Loading Failures

try {
    adapter = LoaderUtil.newCheckedInstanceOf(className, AbstractLoggerAdapter.class);
    LOGGER.info("Using custom LoggerAdapter [{}].", className);
} catch (Exception e) {
    LOGGER.error("Specified LoggerAdapter [{}] is incompatible.", className, e);
    // Falls back to default adapter
    adapter = new ApiLoggerAdapter();
}

Logger Creation Failures

  • Graceful Degradation: Falls back to simpler logger implementation
  • Error Logging: Reports issues through StatusLogger
  • NoOp Fallback: Returns NoOpLogger for recursive creation attempts

Context Issues

  • Context Unavailable: Creates logger with default context
  • Configuration Errors: Uses default configuration if context configuration fails
  • Resource Cleanup: Proper cleanup prevents resource leaks

Thread Safety

All adapter components are fully thread-safe:

  • Adapter Selection: One-time initialization during LogManager construction
  • Logger Creation: Thread-safe logger creation and caching
  • Context Access: Safe concurrent access to LoggerContext
  • Registry Operations: Thread-safe operations in underlying registry

Integration Points

With LogManager

  • Automatic Integration: LogManager automatically uses selected adapter
  • Configuration: Respects adapter configuration from system properties
  • Lifecycle: Adapter lifecycle tied to LogManager lifecycle

With Log4j Components

  • API Integration: Works with any log4j-api implementation
  • Core Integration: Enhanced features when log4j-core is available
  • Context Integration: Proper integration with LoggerContext lifecycle

With JUL Framework

  • Standard Interface: Provides standard JUL Logger interface
  • Handler Compatibility: Works with existing JUL handlers when needed
  • Level Compatibility: Integrates with JUL level system through translation

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