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