Understanding Log4j’s Logger Hierarchy and Configuration Inheritance
This article explains how Log4j creates and organizes Logger instances into a hierarchical graph, illustrates the role of the root logger, details level definitions and inheritance, and shows practical XML configurations for unified and isolated logging across modules.
Abstract
When writing logs we first obtain a logger. In any Log4j‑based project there are many places where loggers are retrieved; each logger is a real instantiated Logger object that may be scattered across numerous classes. The logging architecture describes how these logger objects are organized and related.
Architecture
Consider a concrete example with the following package structure:
The package com.flu.jdk contains two classes, LogTest1 and LogTest2, while com.flu contains LogTest3. Clearly com.flu.jdk is a sub‑package of com.flu. Assuming each class obtains a logger via LogManager.getLogger(ClassName.class), we get three logger instances: logger1, logger2, and logger3. Their relationships are illustrated below.
When logger2 is created, the graph becomes:
Adding logger3 further changes the structure:
Even with just three logger instances the graph becomes fairly complex; in real applications the number of loggers can be huge, forming a directed graph that, while seemingly chaotic, follows a clear hierarchical rule. The next section shows why this structure matters for configuration inheritance.
Configuration Inheritance
Log4j Log Level Definitions
Before proceeding, note Log4j’s log‑level constants:
public final static int OFF_INT = Integer.MAX_VALUE;
public final static int FATAL_INT = 50000;
public final static int ERROR_INT = 40000;
public final static int WARN_INT = 30000;
public final static int INFO_INT = 20000;
public final static int DEBUG_INT = 10000;
//public final static int FINE_INT = DEBUG_INT;
public final static int ALL_INT = Integer.MIN_VALUE;The ordering is: OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL Log4j writes a log entry only when the message’s level is greater than or equal to the logger’s effective level. For example, if a logger’s level is INFO, calls to log.info succeed while log.debug is ignored.
Log Writing Source Code Analysis
Consider the simple call log.info("this is log message"). The relevant source code is:
public void info(Object message) {
if(repository.isDisabled(Level.INFO_INT))
return;
if(Level.INFO.isGreaterOrEqual(this.getEffectiveLevel()))
forcedLog(FQCN, Level.INFO, message, null);
}
public boolean isDisabled(int level) {
return thresholdInt > level;
}The method first checks whether the INFO level is globally disabled (the default thresholdInt is ALL, so it is not). Then it compares INFO with the logger’s effective level, obtained via:
public Level getEffectiveLevel() {
for(Category c = this; c != null; c = c.parent) {
if(c.level != null)
return c.level;
}
return null; // If reached will cause a NullPointerException.
}If the logger itself has no explicit level, the search walks up the parent chain until it finds a configured level, ultimately reaching the root logger. This demonstrates inheritance not only for levels but also for other configurations such as appenders.
Project Application
After understanding the hierarchy and level inheritance, a typical Log4j configuration can be minimal: set the level for the root logger in Log4j.xml:
<root>
<level value="INFO" />
<appender-ref ref="CONSOLE" />
</root>With this root level of INFO and a convention of using the fully‑qualified class name as the logger name, all loggers inherit the root’s level.
Configuration Isolation
For finer‑grained control, different modules can have separate configurations. For example, business code under com.dianping.biz and RPC components under com.dianping.pigeon can be configured as follows:
<!-- Business log configuration -->
<category name="com.dianping.biz">
<level value="INFO" />
<appender-ref ref="CONSOLE" />
</category>
<!-- Pigeon component log configuration -->
<category name="com.dianping.pigeon">
<level value="DEBUG" />
<appender-ref ref="CONSOLE" />
</category>This ensures that all classes in com.dianping.biz inherit the INFO level, while those in com.dianping.pigeon inherit DEBUG. Well‑designed middleware typically provides its own logging configuration to keep middleware logs separate from business logs.
Source: http://www.uml.org.cn/zjjs/201701042.asp
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
ITFLY8 Architecture Home
ITFLY8 Architecture Home - focused on architecture knowledge sharing and exchange, covering project management and product design. Includes large-scale distributed website architecture (high performance, high availability, caching, message queues...), design patterns, architecture patterns, big data, project management (SCRUM, PMP, Prince2), product design, and more.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
