The Apache Log4j 1.x Compatibility API providing a bridge to Log4j 2.x implementations
—
The Service Provider Interface (SPI) classes provide extension points for custom functionality including LoggerRepository, ErrorHandler, Filter, and other pluggable components for advanced logging system customization.
public interface LoggerRepository {
// Logger management
Logger getLogger(String name);
Logger getLogger(String name, LoggerFactory factory);
Logger getRootLogger();
Logger exists(String name);
// Repository state
Enumeration getCurrentLoggers();
Enumeration getCurrentCategories();
// Configuration
void shutdown();
void resetConfiguration();
boolean isDisabled(int level);
void setThreshold(Level level);
void setThreshold(String val);
Level getThreshold();
// Error handling
void emitNoAppenderWarning(Category cat);
// Hierarchy management
void setLoggerFactory(LoggerFactory factory);
LoggerFactory getLoggerFactory();
}Parameters:
name - String logger namefactory - LoggerFactory for logger creationlevel - Integer level to check or Level to setval - String threshold valuecat - Category for warningReturns:
Logger instancesEnumeration of loggers/categoriesboolean for disabled checksLevel current thresholdLoggerFactory current factorypublic interface LoggerFactory {
// Create logger instance
Logger makeNewLoggerInstance(String name);
}Parameters:
name - String name for the new loggerReturns:
Logger newly created logger instancepublic interface ErrorHandler {
// Error handling methods
void error(String message);
void error(String message, Exception ex, int errorCode);
void error(String message, Exception ex, int errorCode, LoggingEvent event);
// Appender association
void setAppender(Appender appender);
void setBackupAppender(Appender appender);
void setLogger(Logger logger);
// Activation
void activateOptions();
}Parameters:
message - String error messageex - Exception that occurrederrorCode - Integer error codeevent - LoggingEvent being processedappender - Appender for associationlogger - Logger for associationpublic interface Filter {
// Filter results
int DENY = -1;
int NEUTRAL = 0;
int ACCEPT = 1;
// Decision method
int decide(LoggingEvent event);
// Filter chaining
Filter getNext();
void setNext(Filter next);
}Parameters:
event - LoggingEvent to evaluatenext - Filter next filter in chainReturns:
int decision (DENY, NEUTRAL, or ACCEPT)Filter next filter in chainpublic class DefaultCategoryFactory implements LoggerFactory {
// Constructor
public DefaultCategoryFactory();
// Factory method implementation
@Override
public Logger makeNewLoggerInstance(String name);
}Parameters:
name - String logger nameReturns:
Logger new logger instancepublic class Hierarchy implements LoggerRepository {
// Constructor
public Hierarchy(Logger root);
// Logger operations
@Override
public Logger getLogger(String name);
@Override
public Logger getLogger(String name, LoggerFactory factory);
@Override
public Logger getRootLogger();
@Override
public Logger exists(String name);
// Enumeration
@Override
public Enumeration getCurrentLoggers();
@Override
public Enumeration getCurrentCategories();
// Configuration
@Override
public void shutdown();
@Override
public void resetConfiguration();
@Override
public boolean isDisabled(int level);
@Override
public void setThreshold(Level level);
@Override
public Level getThreshold();
// Factory management
@Override
public void setLoggerFactory(LoggerFactory factory);
@Override
public LoggerFactory getLoggerFactory();
// Hierarchy-specific methods
public void clear();
public void overrideAsNeeded(String override);
}Parameters:
root - Logger root logger for hierarchyname - String logger namefactory - LoggerFactory for logger creationlevel - Level or integer thresholdoverride - String override configurationReturns:
Logger, Enumeration, Level, LoggerFactory as appropriateboolean for threshold checkspublic class OnlyOnceErrorHandler implements ErrorHandler {
// Constants
public static final String WARN_PREFIX = "log4j warning: ";
public static final String ERROR_PREFIX = "log4j error: ";
// Constructor
public OnlyOnceErrorHandler();
// Error handling
@Override
public void error(String message);
@Override
public void error(String message, Exception ex, int errorCode);
@Override
public void error(String message, Exception ex, int errorCode, LoggingEvent event);
// Configuration
@Override
public void setAppender(Appender appender);
@Override
public void setBackupAppender(Appender appender);
@Override
public void setLogger(Logger logger);
@Override
public void activateOptions();
}Parameters:
message - String error messageex - Exception that occurrederrorCode - Integer error codeevent - LoggingEvent being processedappender - Appender for configurationlogger - Logger for configurationpublic class LevelRangeFilter implements Filter {
// Configuration
public void setLevelMin(Level levelMin);
public Level getLevelMin();
public void setLevelMax(Level levelMax);
public Level getLevelMax();
public void setAcceptOnMatch(boolean acceptOnMatch);
public boolean getAcceptOnMatch();
// Filter implementation
@Override
public int decide(LoggingEvent event);
@Override
public Filter getNext();
@Override
public void setNext(Filter next);
// Lifecycle
public void activateOptions();
}Parameters:
levelMin - Level minimum level in rangelevelMax - Level maximum level in rangeacceptOnMatch - Boolean accept or deny on matchevent - LoggingEvent to evaluatenext - Filter next filter in chainReturns:
Level min/max levelsboolean accept on match settingint filter decisionFilter next filterpublic class LevelMatchFilter implements Filter {
// Configuration
public void setLevel(Level level);
public Level getLevel();
public void setAcceptOnMatch(boolean acceptOnMatch);
public boolean getAcceptOnMatch();
// Filter implementation
@Override
public int decide(LoggingEvent event);
@Override
public Filter getNext();
@Override
public void setNext(Filter next);
// Lifecycle
public void activateOptions();
}Parameters:
level - Level to match againstacceptOnMatch - Boolean accept or deny on matchevent - LoggingEvent to evaluatenext - Filter next filter in chainReturns:
Level match levelboolean accept on match settingint filter decisionFilter next filterpublic class StringMatchFilter implements Filter {
// Configuration
public void setStringToMatch(String s);
public String getStringToMatch();
public void setAcceptOnMatch(boolean acceptOnMatch);
public boolean getAcceptOnMatch();
// Filter implementation
@Override
public int decide(LoggingEvent event);
@Override
public Filter getNext();
@Override
public void setNext(Filter next);
// Lifecycle
public void activateOptions();
}Parameters:
s - String to match in log messagesacceptOnMatch - Boolean accept or deny on matchevent - LoggingEvent to evaluatenext - Filter next filter in chainReturns:
String match stringboolean accept on match settingint filter decisionFilter next filterpublic interface OptionHandler {
// Activate configured options
void activateOptions();
}public interface Configurator {
// Configure from URL
void doConfigure(URL url, LoggerRepository repository);
// Configure from InputStream
void doConfigure(InputStream inputStream, LoggerRepository repository);
}Parameters:
url - URL pointing to configurationinputStream - InputStream containing configurationrepository - LoggerRepository to configurepublic class LoggingEvent implements Serializable {
// Event properties
public String getLoggerName();
public Logger getLogger();
public Level getLevel();
public Object getMessage();
public String getRenderedMessage();
public String[] getThrowableStrRep();
public ThrowableInformation getThrowableInformation();
public long getTimeStamp();
public String getThreadName();
public LocationInfo getLocationInformation();
public String getFQNOfLoggerClass();
// MDC access
public Object getMDC(String key);
public void getMDCCopy();
// NDC access
public String getNDC();
// Properties
public Set getPropertyKeySet();
public String getProperty(String key);
}Parameters:
key - String key for MDC or property accessReturns:
public class LocationInfo implements Serializable {
// Location constants
public static final String NA = "?";
// Location information
public String getClassName();
public String getFileName();
public String getLineNumber();
public String getMethodName();
public String fullInfo();
}Returns:
String location information componentspublic class ThrowableInformation implements Serializable {
// Constructor
public ThrowableInformation(Throwable throwable);
public ThrowableInformation(String[] rep);
// Throwable access
public Throwable getThrowable();
public String[] getThrowableStrRep();
}Parameters:
throwable - Throwable exceptionrep - String array representationReturns:
Throwable original exceptionString[] string representationimport org.apache.log4j.spi.LoggerFactory;
import org.apache.log4j.Logger;
public class CustomLoggerFactory implements LoggerFactory {
@Override
public Logger makeNewLoggerInstance(String name) {
// Create custom logger with enhanced functionality
return new CustomLogger(name);
}
// Custom logger implementation
public static class CustomLogger extends Logger {
public CustomLogger(String name) {
super(name);
}
// Add custom logging methods
public void audit(Object message) {
// Custom audit logging
super.info("AUDIT: " + message);
}
public void security(Object message) {
// Custom security logging
super.warn("SECURITY: " + message);
}
}
}import org.apache.log4j.spi.ErrorHandler;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.*;
public class CustomErrorHandler implements ErrorHandler {
private Appender appender;
private Appender backupAppender;
private Logger logger;
@Override
public void error(String message) {
System.err.println("Custom Error Handler: " + message);
}
@Override
public void error(String message, Exception ex, int errorCode) {
System.err.println("Custom Error Handler [" + errorCode + "]: " + message);
if (ex != null) {
ex.printStackTrace();
}
}
@Override
public void error(String message, Exception ex, int errorCode, LoggingEvent event) {
error(message, ex, errorCode);
// Try backup appender if available
if (backupAppender != null && event != null) {
try {
backupAppender.doAppend(event);
} catch (Exception backupEx) {
System.err.println("Backup appender also failed: " + backupEx.getMessage());
}
}
}
@Override
public void setAppender(Appender appender) {
this.appender = appender;
}
@Override
public void setBackupAppender(Appender appender) {
this.backupAppender = appender;
}
@Override
public void setLogger(Logger logger) {
this.logger = logger;
}
@Override
public void activateOptions() {
// Initialize any resources
}
}import org.apache.log4j.spi.Filter;
import org.apache.log4j.spi.LoggingEvent;
public class CustomMessageFilter implements Filter {
private String[] forbiddenWords;
private Filter next;
public CustomMessageFilter(String[] forbiddenWords) {
this.forbiddenWords = forbiddenWords;
}
@Override
public int decide(LoggingEvent event) {
String message = event.getRenderedMessage();
if (message != null) {
for (String forbidden : forbiddenWords) {
if (message.toLowerCase().contains(forbidden.toLowerCase())) {
return Filter.DENY; // Block messages with forbidden words
}
}
}
return Filter.NEUTRAL; // Let other filters decide
}
@Override
public Filter getNext() {
return next;
}
@Override
public void setNext(Filter next) {
this.next = next;
}
// Usage example
public static void setupFilteredLogging() {
// Create filter to block sensitive information
String[] sensitiveWords = {"password", "ssn", "credit card"};
CustomMessageFilter filter = new CustomMessageFilter(sensitiveWords);
// Create appender with filter
ConsoleAppender appender = new ConsoleAppender(
new PatternLayout("%-5p %c - %m%n")
);
appender.addFilter(filter);
// Configure logger
Logger logger = Logger.getLogger("sensitive");
logger.addAppender(appender);
// Test filtering
logger.info("User login successful"); // Will appear
logger.info("User password is secret"); // Will be blocked
logger.info("Processing credit card transaction"); // Will be blocked
}
}import org.apache.log4j.spi.*;
import org.apache.log4j.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class CustomLoggerRepository implements LoggerRepository {
private final Map<String, Logger> loggers = new ConcurrentHashMap<>();
private final Logger rootLogger;
private LoggerFactory loggerFactory = new DefaultCategoryFactory();
private Level threshold = Level.ALL;
public CustomLoggerRepository() {
this.rootLogger = new Logger("root");
this.rootLogger.setLevel(Level.DEBUG);
loggers.put("root", rootLogger);
}
@Override
public Logger getLogger(String name) {
return getLogger(name, loggerFactory);
}
@Override
public Logger getLogger(String name, LoggerFactory factory) {
Logger logger = loggers.get(name);
if (logger == null) {
logger = factory.makeNewLoggerInstance(name);
loggers.put(name, logger);
// Set up parent-child relationships
setupParentChild(logger, name);
}
return logger;
}
@Override
public Logger getRootLogger() {
return rootLogger;
}
@Override
public Logger exists(String name) {
return loggers.get(name);
}
@Override
public Enumeration getCurrentLoggers() {
return Collections.enumeration(
loggers.values().stream()
.filter(logger -> !logger.getName().equals("root"))
.collect(java.util.stream.Collectors.toList())
);
}
@Override
public Enumeration getCurrentCategories() {
return getCurrentLoggers();
}
@Override
public void shutdown() {
// Close all appenders
for (Logger logger : loggers.values()) {
Enumeration appenders = logger.getAllAppenders();
while (appenders.hasMoreElements()) {
Appender appender = (Appender) appenders.nextElement();
appender.close();
}
}
}
@Override
public void resetConfiguration() {
// Remove all appenders and reset levels
for (Logger logger : loggers.values()) {
logger.removeAllAppenders();
logger.setLevel(null);
}
rootLogger.setLevel(Level.DEBUG);
}
@Override
public boolean isDisabled(int level) {
return threshold.toInt() > level;
}
@Override
public void setThreshold(Level level) {
this.threshold = level;
}
@Override
public void setThreshold(String val) {
setThreshold(Level.toLevel(val));
}
@Override
public Level getThreshold() {
return threshold;
}
@Override
public void emitNoAppenderWarning(Category cat) {
System.err.println("No appenders could be found for logger (" +
cat.getName() + ").");
}
@Override
public void setLoggerFactory(LoggerFactory factory) {
this.loggerFactory = factory;
}
@Override
public LoggerFactory getLoggerFactory() {
return loggerFactory;
}
private void setupParentChild(Logger logger, String name) {
// Simplified parent-child setup
int lastDot = name.lastIndexOf('.');
if (lastDot > 0) {
String parentName = name.substring(0, lastDot);
Logger parent = getLogger(parentName);
// Set up parent relationship (simplified)
}
}
}import org.apache.log4j.spi.Filter;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.*;
public class FilterChainExample {
public static void setupAdvancedFiltering() {
// Create multiple filters
LevelMatchFilter infoFilter = new LevelMatchFilter();
infoFilter.setLevel(Level.INFO);
infoFilter.setAcceptOnMatch(true);
LevelRangeFilter errorFilter = new LevelRangeFilter();
errorFilter.setLevelMin(Level.ERROR);
errorFilter.setLevelMax(Level.FATAL);
errorFilter.setAcceptOnMatch(true);
StringMatchFilter sensitiveFilter = new StringMatchFilter();
sensitiveFilter.setStringToMatch("password");
sensitiveFilter.setAcceptOnMatch(false); // Deny
// Chain filters
infoFilter.setNext(errorFilter);
errorFilter.setNext(sensitiveFilter);
// Create appender with filter chain
ConsoleAppender appender = new ConsoleAppender(
new PatternLayout("%-5p %c - %m%n")
);
appender.addFilter(infoFilter);
// Configure logger
Logger logger = Logger.getLogger("filtered");
logger.addAppender(appender);
logger.setLevel(Level.DEBUG);
// Test filter chain
logger.debug("Debug message"); // Filtered out (not INFO or ERROR+)
logger.info("Info message"); // Passes (INFO level)
logger.info("User password changed"); // Blocked (contains "password")
logger.error("Error occurred"); // Passes (ERROR level)
}
}An error handler that provides failover capability by switching to a backup appender when the primary appender fails.
public class FallbackErrorHandler implements ErrorHandler {
// Constructors
public FallbackErrorHandler();
// ErrorHandler interface methods
public void error(String message);
public void error(String message, Exception e, int errorCode);
public void error(String message, Exception e, int errorCode, LoggingEvent event);
public void setAppender(Appender primary);
public void setBackupAppender(Appender backup);
public void setLogger(Logger logger);
// Activation
public void activateOptions();
}Parameters:
message - Error message describing the failuree - Exception that caused the errorerrorCode - Numeric error code from ErrorCode constantsevent - LoggingEvent that failed to be processedprimary - Primary appender that failedbackup - Backup appender to use for failoverlogger - Logger to update during failoverUsage Example:
import org.apache.log4j.*;
import org.apache.log4j.varia.FallbackErrorHandler;
public class FallbackErrorHandlerExample {
public void setupFallback() {
// Create primary appender (might fail)
FileAppender primaryAppender = new FileAppender(
new PatternLayout("%d %-5p %c - %m%n"),
"/tmp/primary.log",
true
);
primaryAppender.setName("primary");
// Create backup appender (console)
ConsoleAppender backupAppender = new ConsoleAppender(
new PatternLayout("FALLBACK: %d %-5p %c - %m%n")
);
backupAppender.setName("backup");
// Create fallback error handler
FallbackErrorHandler errorHandler = new FallbackErrorHandler();
errorHandler.setAppender(primaryAppender);
errorHandler.setBackupAppender(backupAppender);
errorHandler.setLogger(Logger.getLogger("com.myapp"));
errorHandler.activateOptions();
// Set error handler on primary appender
primaryAppender.setErrorHandler(errorHandler);
// Configure logger
Logger logger = Logger.getLogger("com.myapp");
logger.addAppender(primaryAppender);
}
}Base interface for implementing logging event rewrite strategies used with RewriteAppender.
public interface RewritePolicy {
/**
* Rewrite a logging event
* @param source original logging event
* @return rewritten event, original event, or null to suppress
*/
LoggingEvent rewrite(LoggingEvent source);
}A rewrite policy that processes events where the message implements java.util.Map, combining message properties with the event's existing properties.
public class MapRewritePolicy implements RewritePolicy {
// Constructor
public MapRewritePolicy();
// RewritePolicy implementation
public LoggingEvent rewrite(LoggingEvent source);
}Usage Example:
import org.apache.log4j.*;
import org.apache.log4j.rewrite.MapRewritePolicy;
import java.util.HashMap;
import java.util.Map;
public class RewritePolicyExample {
public void setupMapRewrite() {
// Create rewrite policy
MapRewritePolicy rewritePolicy = new MapRewritePolicy();
// Create RewriteAppender (would need to be implemented)
// RewriteAppender rewriteAppender = new RewriteAppender();
// rewriteAppender.setRewritePolicy(rewritePolicy);
// Example of map-based logging
Logger logger = Logger.getLogger("com.myapp");
Map<String, Object> logMap = new HashMap<>();
logMap.put("message", "User action performed");
logMap.put("userId", "12345");
logMap.put("action", "login");
logMap.put("timestamp", System.currentTimeMillis());
// Log the map - will be processed by MapRewritePolicy
logger.info(logMap);
}
}Interface for custom object-to-string conversion in log messages.
public interface ObjectRenderer {
/**
* Render the object as a String
* @param o object to render
* @return String representation of the object
*/
String doRender(Object o);
}Manages mapping between classes and their corresponding ObjectRenderer implementations.
public class RendererMap {
// Constructor
public RendererMap();
// Static methods
public static void addRenderer(RendererSupport repository, String renderedClassName, String renderingClassName);
// Instance methods
public ObjectRenderer get(Object o);
public ObjectRenderer get(Class clazz);
public void put(Class clazz, ObjectRenderer renderer);
public void clear();
}Parameters:
repository - RendererSupport instance (typically LoggerRepository)renderedClassName - Class name to be renderedrenderingClassName - ObjectRenderer implementation class nameo - Object instance to find renderer forclazz - Class to find renderer forrenderer - ObjectRenderer to associate with classReturns:
get() methods return ObjectRenderer instance or default rendererput() and clear() methods return voidUsage Example:
import org.apache.log4j.*;
import org.apache.log4j.or.ObjectRenderer;
import org.apache.log4j.or.RendererMap;
public class ObjectRendererExample {
// Custom renderer for User objects
public static class UserRenderer implements ObjectRenderer {
public String doRender(Object o) {
if (o instanceof User) {
User user = (User) o;
return "User[id=" + user.getId() + ", name=" + user.getName() + "]";
}
return o.toString();
}
}
public void setupCustomRenderer() {
// Get logger repository that supports renderers
LoggerRepository repository = LogManager.getLoggerRepository();
// Add custom renderer for User class
RendererMap.addRenderer(
(org.apache.log4j.spi.RendererSupport) repository,
"com.myapp.User",
"com.myapp.UserRenderer"
);
// Now User objects will be rendered using UserRenderer
Logger logger = Logger.getLogger("com.myapp");
User user = new User(123, "John Doe");
logger.info("Created user: " + user); // Uses custom renderer
}
}Log4j 1.x compatibility API includes deprecated JMX management classes for backward compatibility. These classes are primarily for legacy applications and new code should use Log4j 2.x JMX features directly.
// Main JMX agent (deprecated)
@Deprecated
public class Agent {
public static Object createServer(int port);
public static void start(Object server);
}
// MBean implementations (deprecated)
@Deprecated
public class HierarchyDynamicMBean extends AbstractDynamicMBean;
@Deprecated
public class LoggerDynamicMBean extends AbstractDynamicMBean;
@Deprecated
public class AppenderDynamicMBean extends AbstractDynamicMBean;Note: These JMX classes are deprecated and maintained only for compatibility. For new applications, use Log4j 2.x's built-in JMX support instead.
Install with Tessl CLI
npx tessl i tessl/maven-org-apache-logging-log4j--log4j-1-2-api