DevNotes
Support
Logging (SLF4J & Log4j2) · Chapter 02

Log4j2 Architecture & Configuration

How Log4j2 improves on Log4j 1.x, loggers, LoggerConfig and the logger hierarchy, log4j2.xml, console, file and rolling-file appenders, retention, PatternLayout symbols, additivity and multiple appenders.

◷ 7 min read§ 12 sections? 8 interview questions{ } 3 code examples

#What Is Log4j2?

Log4j2 is Apache's second-generation logging framework — a complete rewrite built to fix the limitations of Log4j 1.x.

Log4j 1.xLog4j2
SlowerMuch faster
Single-thread optimizedBuilt for multi-threaded applications
Limited async loggingHigh-performance async logging (LMAX Disruptor)
Properties / XML onlyXML, JSON, YAML or properties configuration
Basic rolling filesAdvanced rolling and retention policies
Can't reload configuration safelyAutomatic configuration reloading
End of life (2015)Actively maintained

#Log4j2 Architecture

Application calls logger.info()
Logger
LoggerConfig — level and appenders for that logger name
Filters — optional extra accept / deny rules
Appender — destination
Layout — format
Destination — console, file, network

Each component has one responsibility.

#Component 1 — Logger

The logger generates log events. Through SLF4J:

Java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class EmployeeService {
    private static final Logger logger = LoggerFactory.getLogger(EmployeeService.class);
}

Or with Log4j2's own API:

Java
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

private static final Logger logger = LogManager.getLogger(EmployeeService.class);

Every class generally has its own logger (EmployeeController, EmployeeService, EmployeeRepository…). Never use one global logger for the whole application — you'd lose the ability to control levels per class or package.

#The Logger Hierarchy

Logger names form a hierarchy based on the package, separated by dots:

  • Root logger
    • com
      • com.example
        • com.example.service
          • com.example.service.impl
        • com.example.controller

A child logger inherits its level and appenders from its nearest configured ancestor, unless it's explicitly configured. So setting com.example.service to DEBUG affects com.example.service.impl too.

The Root Logger

The root logger is the parent of all loggers and provides the default configuration:

XML
<Root level="INFO">
    <AppenderRef ref="Console"/>
</Root>

Levels in Action

With the root level at INFO:

CallResult
logger.trace()Ignored
logger.debug()Ignored
logger.info()Printed
logger.warn()Printed
logger.error()Printed

With <Root level="WARN">:

Java
logger.info("Information");
logger.warn("Warning");
logger.error("Error");
Output
Warning
Error

INFO isn't printed.

#The Configuration File

Log4j2 automatically looks for log4j2.xml, log4j2.json, log4j2.yaml or log4j2.properties on the classpath. Most projects use log4j2.xml in src/main/resources:

  • src
    • main
      • resources
        • log4j2.xml

A Basic log4j2.xml

XML
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d %p %c %m%n"/>
        </Console>
    </Appenders>

    <Loggers>
        <Root level="INFO">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>
  • Configuration
    • Appenderswhere logs go, and how they're formatted
    • Loggerswhich loggers use which appenders, at which level
      • Root logger

status="WARN" controls Log4j2's own internal messages — set it to DEBUG when your configuration doesn't seem to load.

#Appenders

An appender decides where logs go: Console, File, RollingFile, database (JDBC), Socket, SMTP, Kafka and more.

Console Appender

XML
<Console name="Console" target="SYSTEM_OUT">
    <PatternLayout pattern="%d %p %c %m%n"/>
</Console>
Output
2026-07-23 10:15:02,118 INFO com.example.EmployeeService Employee Saved

File Appender

XML
<File name="File" fileName="logs/application.log">
    <PatternLayout pattern="%d %p %m%n"/>
</File>

Writes to logs/application.log — a file that grows forever.

Rolling File Appender

The most common choice in production. A single application.log can reach 40 GB and become impossible to open or ship. A rolling appender starts a new file on a schedule or size limit:

XML
<RollingFile name="Rolling"
             fileName="logs/application.log"
             filePattern="logs/application-%d{yyyy-MM-dd}-%i.log.gz">
    <PatternLayout pattern="%d %p %c{1} %m%n"/>
    <Policies>
        <TimeBasedTriggeringPolicy/>                 <!-- new file every day -->
        <SizeBasedTriggeringPolicy size="100 MB"/>   <!-- …or when a file reaches 100 MB -->
    </Policies>
    <DefaultRolloverStrategy max="20">
        <Delete basePath="logs" maxDepth="1">
            <IfFileName glob="application-*.log.gz"/>
            <IfLastModified age="30d"/>             <!-- keep 30 days of logs -->
        </Delete>
    </DefaultRolloverStrategy>
</RollingFile>
Files on disk
application.log                  ← current file
application-2026-07-21-1.log.gz
application-2026-07-22-1.log.gz
application-2026-07-23-1.log.gz
application-2026-07-23-2.log.gz  ← second file the same day (size limit reached)
ElementMeaning
fileNameThe active log file
filePatternName of rolled files; %d{yyyy-MM-dd} sets the time granularity, %i is a counter, .gz compresses them
TimeBasedTriggeringPolicyRoll over when the date in filePattern changes
SizeBasedTriggeringPolicyRoll over when the file reaches a size
DefaultRolloverStrategy maxMaximum %i files kept per period
Delete actionRemoves old archives — without it, rolled files accumulate forever

#PatternLayout

PatternLayout controls how each log line looks:

XML
<PatternLayout pattern="%d %p %c %m%n"/>
PatternMeaning
%dDate and time (%d{yyyy-MM-dd HH:mm:ss.SSS} for a custom format)
%p / %levelLog level (%-5level pads it to 5 characters)
%cLogger name (%c{1} = just the last part, e.g. the class name)
%CFully qualified name of the calling class
%mThe log message
%tThread name
%nPlatform line separator
%LLine number
%MMethod name
%FFile name
%X{key}MDC value, e.g. %X{requestId}
%ex / %throwableException stack trace (added automatically if omitted)

A Production Pattern

Text
%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %c{1} - %m%n
Output
2026-07-23 11:02:12.125 [main] INFO  EmployeeService - Employee Saved

#Multiple Appenders

A logger can write to several destinations at once:

XML
<Root level="INFO">
    <AppenderRef ref="Console"/>
    <AppenderRef ref="Rolling"/>
</Root>

Logs go to both the console and the rolling file.

Per-Package Levels and Additivity

XML
<Loggers>
    <Logger name="com.example.payment" level="DEBUG" additivity="false">
        <AppenderRef ref="PaymentFile"/>
    </Logger>
    <Logger name="org.hibernate.SQL" level="DEBUG"/>
    <Root level="INFO">
        <AppenderRef ref="Console"/>
    </Root>
</Loggers>
  • com.example.payment logs at DEBUG to its own file.
  • By default a logger's events also flow up to its parents' appenders (additivity). additivity="false" stops payment logs being written to the console too — and prevents duplicate lines when a logger and its parent share an appender.

#Interview Questions

Q11. What is the difference between a logger and the root logger?

A logger belongs to a specific class or package. The root logger is the parent of all loggers and provides the default level and appenders.

Q22. Why use RollingFileAppender?

To stop log files growing indefinitely by rotating them by time or size — combined with a delete policy to cap disk usage.

Q33. What is PatternLayout?

The layout that defines the format of every log line using conversion patterns such as %d, %p and %m.

Q44. Where should log4j2.xml be placed?

In src/main/resources so it ends up on the classpath — named log4j2-spring.xml in Spring Boot projects.

Q55. What does %d %p %c %m%n represent?

Date/time, level, logger (class) name, message and a new line.

Q66. Can multiple appenders be attached to one logger?

Yes. A single logger can write simultaneously to the console, files, databases or other destinations.

Q77. What is logger additivity?

Events logged to a logger are also passed to the appenders of its ancestors. Setting additivity="false" stops that, which avoids duplicate log lines.

Q88. Why is Log4j2 faster than Log4j 1.x?

It was designed for multi-threaded use, avoids locking on the hot path, reuses objects to reduce garbage, and offers lock-free asynchronous loggers built on the LMAX Disruptor.

#Common Mistakes

  • Putting log4j2.xml outside src/main/resources, so it's never found.
  • A typo in <AppenderRef ref="..."> — the name must match an appender exactly.
  • Wrong logger levels, or a child logger silently overriding the root.
  • No retention policy on rolling files.
  • Duplicate log lines because additivity wasn't turned off.
  • Using %C, %L or %M in production patterns without needing them.

#Best Practices

  • Keep production at INFO; enable DEBUG only for the package you're troubleshooting.
  • Use a RollingFile appender with size and time triggers and a Delete policy.
  • Separate application and error logs when operations teams need it.
  • Use descriptive logger names — the class name.
  • Never log passwords, OTPs, JWTs or other sensitive information.

#Key Takeaways

  • Log4j2 is a faster, actively maintained rewrite of Log4j 1.x.
  • Logger names form a hierarchy; children inherit from the nearest configured ancestor, ultimately the root logger.
  • log4j2.xml defines appenders (where), layouts (how) and loggers (which level, which appenders).
  • RollingFile appenders need triggering policies and a retention policy.
  • %d %p %c %m%n = date, level, logger, message, new line; avoid costly location patterns.