CtrlK
BlogDocsLog inGet started
Tessl Logo

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

The logging API of the Log4j project providing a comprehensive and flexible logging framework for Java applications.

Pending
Overview
Eval results
Files

spi.mddocs/

Service Provider Interface

Extension points for custom logger implementations, context factories, and integration with different logging backends. Enables Log4j API to work with various implementations.

Capabilities

LoggerContext Interface

Anchor point for logging implementations that manages loggers and their lifecycle.

/**
 * Anchor point for logging implementations; manages loggers
 */
public interface LoggerContext {
    /** Get logger by name */
    ExtendedLogger getLogger(String name);
    
    /** Get logger with custom message factory */
    ExtendedLogger getLogger(String name, MessageFactory messageFactory);
    
    /** Get logger by class */
    ExtendedLogger getLogger(Class<?> cls);
    
    /** Check if logger exists */
    boolean hasLogger(String name);
    
    /** Check if logger exists with specific message factory */
    boolean hasLogger(String name, MessageFactory messageFactory);
    
    /** Check if logger exists by class */
    boolean hasLogger(Class<?> cls);
    
    /** Get external context object */
    Object getExternalContext();
    
    /** Get stored object by key */
    Object getObject(String key);
    
    /** Store object with key */
    Object putObject(String key, Object value);
    
    /** Remove stored object */
    Object removeObject(String key);
    
    /** Empty array constant */
    LoggerContext[] EMPTY_ARRAY = new LoggerContext[0];
}

Usage Examples:

public void demonstrateLoggerContext() {
    // Get current logger context
    LoggerContext context = LogManager.getContext();
    
    // Get loggers from context
    ExtendedLogger logger1 = context.getLogger("com.example.MyClass");
    ExtendedLogger logger2 = context.getLogger(MyClass.class);
    
    // Check logger existence
    boolean exists = context.hasLogger("com.example.MyClass");
    
    // Store and retrieve context-specific objects
    context.putObject("config", new MyConfiguration());
    MyConfiguration config = (MyConfiguration) context.getObject("config");
    
    // External context (implementation-specific)
    Object externalCtx = context.getExternalContext();
}

// Custom logger context implementation
public class CustomLoggerContext implements LoggerContext {
    private final Map<String, ExtendedLogger> loggers = new ConcurrentHashMap<>();
    private final Map<String, Object> objects = new ConcurrentHashMap<>();
    private final Object externalContext;
    
    public CustomLoggerContext(Object externalContext) {
        this.externalContext = externalContext;
    }
    
    @Override
    public ExtendedLogger getLogger(String name) {
        return loggers.computeIfAbsent(name, this::createLogger);
    }
    
    @Override
    public ExtendedLogger getLogger(String name, MessageFactory messageFactory) {
        String key = name + "#" + messageFactory.getClass().getName();
        return loggers.computeIfAbsent(key, k -> createLogger(name, messageFactory));
    }
    
    @Override
    public boolean hasLogger(String name) {
        return loggers.containsKey(name);
    }
    
    @Override
    public Object getExternalContext() {
        return externalContext;
    }
    
    @Override
    public Object getObject(String key) {
        return objects.get(key);
    }
    
    @Override
    public Object putObject(String key, Object value) {
        return objects.put(key, value);
    }
    
    @Override
    public Object removeObject(String key) {
        return objects.remove(key);
    }
    
    private ExtendedLogger createLogger(String name) {
        return new CustomExtendedLogger(name);
    }
    
    private ExtendedLogger createLogger(String name, MessageFactory messageFactory) {
        return new CustomExtendedLogger(name, messageFactory);
    }
}

LoggerContextFactory Interface

Factory for creating and managing LoggerContext instances across different classloaders and configurations.

/**
 * Factory for creating LoggerContext instances
 */
public interface LoggerContextFactory {
    /** 
     * Get context with full control over selection criteria
     * @param fqcn Fully qualified class name of the caller
     * @param loader ClassLoader to associate with context
     * @param externalContext External context object
     * @param currentContext Whether to return current context
     */
    LoggerContext getContext(String fqcn, ClassLoader loader, 
                           Object externalContext, boolean currentContext);
    
    /** 
     * Get context with configuration location and name
     * @param fqcn Fully qualified class name of the caller
     * @param loader ClassLoader to associate with context
     * @param externalContext External context object
     * @param currentContext Whether to return current context
     * @param configLocation Configuration file location
     * @param name Context name
     */
    LoggerContext getContext(String fqcn, ClassLoader loader, 
                           Object externalContext, boolean currentContext,
                           URI configLocation, String name);
    
    /** Remove a context */
    void removeContext(LoggerContext context);
    
    /** Check if context exists */
    boolean hasContext(String fqcn, ClassLoader loader, boolean currentContext);
    
    /** 
     * Shutdown contexts
     * @param fqcn Fully qualified class name
     * @param loader ClassLoader
     * @param currentContext Whether to shutdown current context
     * @param allContexts Whether to shutdown all contexts
     */
    void shutdown(String fqcn, ClassLoader loader, 
                  boolean currentContext, boolean allContexts);
    
    /** Check if factory is dependent on ClassLoader */
    boolean isClassLoaderDependent();
}

Usage Examples:

// Custom logger context factory
public class CustomLoggerContextFactory implements LoggerContextFactory {
    private final Map<String, LoggerContext> contexts = new ConcurrentHashMap<>();
    
    @Override
    public LoggerContext getContext(String fqcn, ClassLoader loader, 
                                  Object externalContext, boolean currentContext) {
        String key = createContextKey(loader, externalContext);
        return contexts.computeIfAbsent(key, k -> createContext(externalContext));
    }
    
    @Override
    public LoggerContext getContext(String fqcn, ClassLoader loader, 
                                  Object externalContext, boolean currentContext,
                                  URI configLocation, String name) {
        String key = createContextKey(loader, externalContext, configLocation, name);
        return contexts.computeIfAbsent(key, k -> createContext(externalContext, configLocation, name));
    }
    
    @Override
    public void removeContext(LoggerContext context) {
        contexts.values().remove(context);
    }
    
    @Override
    public boolean hasContext(String fqcn, ClassLoader loader, boolean currentContext) {
        String key = createContextKey(loader, null);
        return contexts.containsKey(key);
    }
    
    @Override
    public void shutdown(String fqcn, ClassLoader loader, 
                        boolean currentContext, boolean allContexts) {
        if (allContexts) {
            contexts.clear();
        } else {
            String key = createContextKey(loader, null);
            contexts.remove(key);
        }
    }
    
    @Override
    public boolean isClassLoaderDependent() {
        return true; // This factory creates different contexts per ClassLoader
    }
    
    private String createContextKey(ClassLoader loader, Object externalContext) {
        return loader.toString() + "#" + (externalContext != null ? externalContext.toString() : "null");
    }
    
    private String createContextKey(ClassLoader loader, Object externalContext, 
                                  URI configLocation, String name) {
        return createContextKey(loader, externalContext) + "#" + configLocation + "#" + name;
    }
    
    private LoggerContext createContext(Object externalContext) {
        return new CustomLoggerContext(externalContext);
    }
    
    private LoggerContext createContext(Object externalContext, URI configLocation, String name) {
        return new CustomLoggerContext(externalContext, configLocation, name);
    }
}

// Usage in application
public class ContextFactoryUsage {
    
    public void demonstrateContextFactory() {
        LoggerContextFactory factory = new CustomLoggerContextFactory();
        
        // Get context for current classloader
        LoggerContext context1 = factory.getContext(
            this.getClass().getName(),
            Thread.currentThread().getContextClassLoader(),
            null,
            true
        );
        
        // Get context with specific configuration
        URI configUri = URI.create("classpath:log4j2-test.xml");
        LoggerContext context2 = factory.getContext(
            this.getClass().getName(),
            getClass().getClassLoader(),
            "test-app",
            false,
            configUri,
            "test-context"
        );
        
        // Check context existence
        boolean exists = factory.hasContext(
            this.getClass().getName(),
            getClass().getClassLoader(),
            true
        );
        
        // Shutdown specific context
        factory.removeContext(context1);
        
        // Shutdown all contexts
        factory.shutdown(null, null, false, true);
    }
}

ExtendedLogger Interface

Extended logger interface providing additional methods for logger implementations.

/**
 * Extended logger interface for implementations
 */
public interface ExtendedLogger extends Logger {
    /** 
     * Log message if the specified level is enabled
     * @param fqcn Fully qualified class name of the caller
     * @param level Log level
     * @param marker Marker
     * @param message Message
     * @param throwable Throwable
     */
    void logIfEnabled(String fqcn, Level level, Marker marker, 
                     String message, Throwable throwable);
    
    /** Log with message supplier if level enabled */
    void logIfEnabled(String fqcn, Level level, Marker marker, 
                     Supplier<?> messageSupplier, Throwable throwable);
    
    /** Log with message object if level enabled */
    void logIfEnabled(String fqcn, Level level, Marker marker, 
                     Object message, Throwable throwable);
    
    /** Log with Message object if level enabled */
    void logIfEnabled(String fqcn, Level level, Marker marker, 
                     Message message, Throwable throwable);
    
    /** Log parameterized message if level enabled */
    void logIfEnabled(String fqcn, Level level, Marker marker, 
                     String message, Object... params);
    
    /** Log parameterized message with specific parameter count if level enabled */
    void logIfEnabled(String fqcn, Level level, Marker marker, 
                     String message, Object p0);
    void logIfEnabled(String fqcn, Level level, Marker marker, 
                     String message, Object p0, Object p1);
    // ... additional overloads for performance
    
    /** Always log regardless of level (for internal use) */
    void logMessage(String fqcn, Level level, Marker marker, 
                   Message message, Throwable throwable);
}

Usage Examples:

// Custom extended logger implementation
public class CustomExtendedLogger extends AbstractLogger implements ExtendedLogger {
    private final String name;
    private final Level level;
    
    public CustomExtendedLogger(String name) {
        this.name = name;
        this.level = Level.INFO; // Default level
    }
    
    @Override
    public void logIfEnabled(String fqcn, Level level, Marker marker, 
                           String message, Throwable throwable) {
        if (isEnabled(level, marker)) {
            logMessage(fqcn, level, marker, 
                      getMessageFactory().newMessage(message), throwable);
        }
    }
    
    @Override
    public void logIfEnabled(String fqcn, Level level, Marker marker, 
                           String message, Object... params) {
        if (isEnabled(level, marker)) {
            logMessage(fqcn, level, marker, 
                      getMessageFactory().newMessage(message, params), null);
        }
    }
    
    @Override
    public void logMessage(String fqcn, Level level, Marker marker, 
                          Message message, Throwable throwable) {
        // Actual logging implementation
        StringBuilder sb = new StringBuilder();
        sb.append("[").append(level).append("] ");
        sb.append(name).append(" - ");
        if (marker != null) {
            sb.append(marker.getName()).append(" ");
        }
        sb.append(message.getFormattedMessage());
        
        System.out.println(sb.toString());
        
        if (throwable != null) {
            throwable.printStackTrace(System.out);
        }
    }
    
    @Override
    public boolean isEnabled(Level level, Marker marker) {
        return level.isMoreSpecificThan(this.level);
    }
    
    @Override
    public Level getLevel() {
        return level;
    }
    
    @Override
    public String getName() {
        return name;
    }
}

// Usage of extended logger features
public class ExtendedLoggerUsage {
    private static final String FQCN = ExtendedLoggerUsage.class.getName();
    
    public void demonstrateExtendedLogger() {
        ExtendedLogger logger = (ExtendedLogger) LogManager.getLogger();
        
        // Use extended logger methods directly
        logger.logIfEnabled(FQCN, Level.INFO, null, "Direct extended logging", (Throwable) null);
        
        // Parameterized logging with FQCN
        logger.logIfEnabled(FQCN, Level.DEBUG, null, "User {} performed action {}", "alice", "login");
        
        // With marker and throwable
        Marker securityMarker = MarkerManager.getMarker("SECURITY");
        Exception ex = new RuntimeException("test");
        logger.logIfEnabled(FQCN, Level.ERROR, securityMarker, "Security violation", ex);
        
        // Force logging regardless of level (use with caution)
        Message forceMsg = new SimpleMessage("Forced log message");
        logger.logMessage(FQCN, Level.TRACE, null, forceMsg, null);
    }
}

AbstractLogger Base Class

Abstract base class providing common logger functionality that implementations can extend.

/**
 * Abstract base class for Logger implementations
 */
public abstract class AbstractLogger implements ExtendedLogger, Serializable {
    /** Default message factory */
    public static final MessageFactory DEFAULT_MESSAGE_FACTORY = ParameterizedMessageFactory.INSTANCE;
    
    /** Default flow message factory */
    public static final FlowMessageFactory DEFAULT_FLOW_MESSAGE_FACTORY = DefaultFlowMessageFactory.INSTANCE;
    
    /** Get message factory for this logger */
    @Override
    public MessageFactory getMessageFactory() {
        return DEFAULT_MESSAGE_FACTORY;
    }
    
    /** Get flow message factory for this logger */
    @Override
    public FlowMessageFactory getFlowMessageFactory() {
        return DEFAULT_FLOW_MESSAGE_FACTORY;
    }
    
    // Abstract methods that implementations must provide
    @Override
    public abstract Level getLevel();
    
    @Override
    public abstract boolean isEnabled(Level level, Marker marker, String message, Throwable throwable);
    
    @Override
    public abstract boolean isEnabled(Level level, Marker marker, String message);
    
    @Override
    public abstract boolean isEnabled(Level level, Marker marker, String message, Object... params);
    
    @Override
    public abstract boolean isEnabled(Level level, Marker marker, Object message, Throwable throwable);
    
    @Override
    public abstract boolean isEnabled(Level level, Marker marker, Message message, Throwable throwable);
    
    @Override
    public abstract void logMessage(String fqcn, Level level, Marker marker, 
                                   Message message, Throwable throwable);
}

Usage Examples:

// Implementing a custom logger by extending AbstractLogger
public class FileLogger extends AbstractLogger {
    private final String name;
    private final Level level;
    private final PrintWriter writer;
    
    public FileLogger(String name, Level level, String filename) throws IOException {
        this.name = name;
        this.level = level;
        this.writer = new PrintWriter(new FileWriter(filename, true));
    }
    
    @Override
    public String getName() {
        return name;
    }
    
    @Override
    public Level getLevel() {
        return level;
    }
    
    @Override
    public boolean isEnabled(Level level, Marker marker, String message, Throwable throwable) {
        return level.isMoreSpecificThan(this.level);
    }
    
    @Override
    public boolean isEnabled(Level level, Marker marker, String message) {
        return level.isMoreSpecificThan(this.level);
    }
    
    @Override
    public boolean isEnabled(Level level, Marker marker, String message, Object... params) {
        return level.isMoreSpecificThan(this.level);
    }
    
    @Override
    public boolean isEnabled(Level level, Marker marker, Object message, Throwable throwable) {
        return level.isMoreSpecificThan(this.level);
    }
    
    @Override
    public boolean isEnabled(Level level, Marker marker, Message message, Throwable throwable) {
        return level.isMoreSpecificThan(this.level);
    }
    
    @Override
    public void logMessage(String fqcn, Level level, Marker marker, 
                          Message message, Throwable throwable) {
        synchronized (writer) {
            writer.printf("[%s] %s %s - %s%n", 
                         new Date(), level, name, message.getFormattedMessage());
            
            if (throwable != null) {
                throwable.printStackTrace(writer);
            }
            
            writer.flush();
        }
    }
    
    public void close() {
        writer.close();
    }
}

// Usage of custom logger
public class CustomLoggerUsage {
    
    public void demonstrateCustomLogger() throws IOException {
        // Create custom file logger
        FileLogger fileLogger = new FileLogger("com.example.FileLogger", Level.DEBUG, "app.log");
        
        // Use it like any other logger
        fileLogger.info("Application started");
        fileLogger.debug("Debug information: {}", "debug data");
        fileLogger.error("An error occurred", new RuntimeException("test error"));
        
        // Clean up
        fileLogger.close();
    }
}

ThreadContext SPI Interfaces

Service provider interfaces for custom ThreadContext implementations.

/**
 * Interface for ThreadContext map implementations
 */
public interface ThreadContextMap {
    /** Clear the context */
    void clear();
    
    /** Check if key exists */
    boolean containsKey(String key);
    
    /** Get value by key */
    String get(String key);
    
    /** Get copy of context as Map */
    Map<String, String> getCopy();
    
    /** Get immutable view of context */
    Map<String, String> getImmutableMapOrNull();
    
    /** Check if context is empty */
    boolean isEmpty();
    
    /** Put key-value pair */
    void put(String key, String value);
    
    /** Remove key */
    void remove(String key);
}

/**
 * Interface for ThreadContext stack implementations
 */
public interface ThreadContextStack extends ThreadContext.ContextStack {
    /** Clear the stack */
    void clear();
    
    /** Check if stack contains value */
    boolean contains(Object o);
    
    /** Copy the stack */
    ThreadContextStack copy();
    
    /** Check if stack equals another */
    boolean equals(Object obj);
    
    /** Get stack depth */
    int getDepth();
    
    /** Get hash code */
    int hashCode();
    
    /** Check if stack is empty */
    boolean isEmpty();
    
    /** Get iterator */
    Iterator<String> iterator();
    
    /** Peek at top element */
    String peek();
    
    /** Pop top element */
    String pop();
    
    /** Push element */
    void push(String message);
    
    /** Get stack size */
    int size();
    
    /** Trim to specified depth */
    void trim(int depth);
}

Usage Examples:

// Custom ThreadContext map implementation
public class DatabaseThreadContextMap implements ThreadContextMap {
    private final ThreadLocal<Map<String, String>> localMap = 
        ThreadLocal.withInitial(HashMap::new);
    
    @Override
    public void clear() {
        localMap.get().clear();
        // Could also persist to database here
    }
    
    @Override
    public boolean containsKey(String key) {
        return localMap.get().containsKey(key);
    }
    
    @Override
    public String get(String key) {
        return localMap.get().get(key);
    }
    
    @Override
    public Map<String, String> getCopy() {
        return new HashMap<>(localMap.get());
    }
    
    @Override
    public Map<String, String> getImmutableMapOrNull() {
        Map<String, String> map = localMap.get();
        return map.isEmpty() ? null : Collections.unmodifiableMap(map);
    }
    
    @Override
    public boolean isEmpty() {
        return localMap.get().isEmpty();
    }
    
    @Override
    public void put(String key, String value) {
        localMap.get().put(key, value);
        // Could also persist to database here
        persistToDatabase(key, value);
    }
    
    @Override
    public void remove(String key) {
        localMap.get().remove(key);
        // Could also remove from database here
        removeFromDatabase(key);
    }
    
    private void persistToDatabase(String key, String value) {
        // Database persistence logic
    }
    
    private void removeFromDatabase(String key) {
        // Database removal logic
    }
}

// Provider class for SPI registration
public class CustomProvider extends Provider {
    
    public CustomProvider() {
        super(10, "2.25.1"); // Priority and version
        
        // Register custom implementations
        put("LoggerContextFactory", "com.example.CustomLoggerContextFactory");
        put("ThreadContextMap", "com.example.DatabaseThreadContextMap");
    }
    
    @Override
    public String getVersionStr() {
        return "2.25.1";
    }
}

Install with Tessl CLI

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

docs

core-logging.md

index.md

markers.md

message-system.md

performance-features.md

spi.md

status-system.md

thread-context.md

tile.json