Explain Codes LogoExplain Codes Logo

Configuring Log4j Loggers Programmatically

java
logging
log4j
configuration
Anton ShumikhinbyAnton Shumikhin·Feb 2, 2025
TLDR

To set up Log4j2 loggers programmatically, wield the LoggerContext to handle logging configuration. Set up a logger with a ConsoleAppender and a PatternLayout using this code:

import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.config.Configurator; import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder; import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration; ConfigurationBuilder<BuiltConfiguration> builder = Configurator.newConfigurationBuilder(); builder.add(builder.newAppender("stdout", "Console") .add(builder.newLayout("PatternLayout") .addAttribute("pattern", "%d{HH:mm:ss.SSS} %-5level - %msg%n"))); //You'll see this pattern a lot. Like Deja vu, but less Matrix-y. builder.add(builder.newLogger("MyLogger", Level.DEBUG) .add(builder.newAppenderRef("stdout")) .addAttribute("additivity", false)); //It's a false truth, these aren't the logs you're looking for. Configurator.initialize(builder.build());

This snippet creates a ConsoleAppender with timestamped log messages, and initializes a logger named MyLogger at DEBUG level.

A new era: Programmatically configuring your loggers

The baptism: Early initialization

Kick off your logger setup with an init() method, setting up your logging like a newborn starting a fresh life:

public class LoggingConfigurer { static { init(); //Baptize the configurations with holy grace! } public static void init() { // Programmatic configuration code here } }

Master of all: Controlling with root logger

Omnipotent and omnipresent, the root logger controls across the application landscape:

LoggerContext context = (LoggerContext) LogManager.getContext(false); Configuration config = context.getConfiguration(); config.getAppender("stdout").stop(); //Stopping. Hammertime! config.getLoggerConfig(LogManager.ROOT_LOGGER_NAME).removeAppender("stdout"); //Goodbye stdout! Don't forget to write! context.updateLoggers(config); // Apply changes

Class-by-class refinement: The logger for each class

Exploit the power of object-oriented programming and log for specific classes:

LoggerConfig loggerConfig = config.getLoggerConfig("com.example.MyClass"); loggerConfig.setLevel(Level.INFO); //The logs are everywhere! Mighty INFO, save us! context.updateLoggers(); // Changes without updates are like forgotten dreams.

Because change is constant: Dynamic logger updates

Gracefully alter your logging at runtime, because change is the only constant.

Code patterns to live by

Wrapping the present: Use SLF4J

Wrap SLF4J around Log4j2. Like a gift wrapper for a log. Magic abstraction hides the scary bits:

import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SomeComponent { private static final Logger LOGGER = LoggerFactory.getLogger(SomeComponent.class); // LOGGER here, logging there, logging everywhere! }

Laziness for the win: Lazy logger creation

Embrace lazy initialization. Like slow-cooked meals, they taste better:

public class LazyLoggerProvider { private static Logger LOGGER = null; // Null today, initialized tomorrow public static Logger getLogger() { if (LOGGER == null) { LOGGER = LoggerFactory.getLogger(LazyLoggerProvider.class); // Initialize when needed, like a loyal rottweiler. } return LOGGER; } }

Directing the logs: Appender output

Guide your console appender's output to System.out, like a shepherd guiding his sheep:

Appender consoleAppender = ... // your console appender configuration consoleAppender.setTarget(ConsoleAppender.Target.SYSTEM_OUT); // System.out, the Little House on the Prairie for your logs. consoleAppender.start(); // Add appender to root logger rootLogger.addAppender(consoleAppender); //This appender and root logger, best friends forever!

Balancing act: Threshold management

Set thresholds for each appender. Each log has its place, like books in a shelf:

Appender debugAppender = ... // Create appender for debugging Appender errorAppender = ... // Create appender for errors debugAppender.setThreshold(Level.DEBUG); errorAppender.setThreshold(Level.ERROR); // This appender has no time for your debug levity! // Assign appenders where they belong