Entering the world of Java Web technology 9: the birth and development of Java log system

Posted by subalan on Fri, 11 Feb 2022 15:29:35 +0100

How is a famous log system designed

Reprinted from: Manon turned over

1 Preface

At the beginning of its birth, the Java Empire provided common functions such as collection, thread, IO and network, which attracted a large number of programmers from C and C + + territory, but intentionally or unintentionally ignored an important function: output log.


In this regard, Minister IO is very clear that the log is a very important thing, because after the program runs, it is basically a black box. If the behavior of the program is inconsistent with the expectation, there is a Bug. How to locate the Bug?    


There are two tools that the subjects can use. The first is single-step debugging, tracking and checking the value of variables in the code step by step. This method is time-consuming and laborious, and can only be used on the programmer's machine.  


The second is to print the log in a specific place to help quickly locate through the output of the log. Especially when the code runs in the production environment, log information is essential. Otherwise, if something goes wrong, where can I find the problem? Can't subjects turn themselves into a thread into the system to execute?


But IO minister also has his own small abacus: log, use my system out. println(.....) No?! I also provided system err. Println isn't it?   


Under the obstruction of IO minister, from the first generation king to the third generation king of the Empire, there was no log related toolkit in JDK, and the subjects had to endure using system out. Println to output the log, output all the information to the console, and turn it into a pile of garbage.


2 Zhangjia Village

Zhangjiacun's e-commerce system is not immune, and naturally encountered the problem of log. The experienced old village head is tired of the system out. Println outputs a large amount of useless information that is difficult to understand, watching the villagers and people struggling with these systems all day Out to fight, he found Xiao Zhang and ordered him to design a general log processing system.


Xiao Zhang has spent a lot of time and accumulated rich experience in the design of message queue and JMS. Since then, she has always implemented business code and CRUD. Zhang Erni jokes that she is an HTML filler all day. This time, she must see her design skills!


(portal:< Java Empire message queue>,<The birth of JMS in the Java Empire>)

The requirements given by the old village head to Xiao Zhang are as follows:


1. In addition to printing to the console, log messages can also be output to files, or even sent out by mail (for example, generating environment error messages)


2. The log content should be formatted, such as plain text, XML, HTML, etc


3. For different Java class es, different package s and different levels of logs, they should be flexibly output to different files.

For example, for com Foo this package, all logs are output to foo Log file

For com Bar package, all files are output to bar Log file

All ERROR level logs are output to ERROR Log file


4. It can classify logs. Some logs are purely debug and can be used in the local machine or test environment, which is convenient for programmers to debug. There is no need for the production environment. Some logs describe errors. If an error occurs in the production environment, it must be recorded to help subsequent analysis.


Xiao Zhang looked carefully, patted his chest and said to the old village head, "no problem. You will see the results tomorrow."


3 design of Xiao Zhang

After the old village head left, Xiao Zhang began to analyze the needs and offered the "big method of object-oriented design", trying to abstract some concepts from the needs of the village head.


First of all, to record logs, you must have a class to express the concept of logs. This class should have at least two properties, one is the timestamp and the other is the message itself. Call it LoggingEvent. Logging is like recording an event.


Secondly, logs can be output to different places, such as console, files, mail, etc. this can be abstracted. Isn't it written to different destinations? Can it be called LogDestination?  


Well, it's simpler. It's called Appender, which implies that you can continuously add logs.

As for the second item, the log content can be formatted, which can be compared with the gourd drawing gourd. Define a Formatter interface to format the message.


By the way, the Appender should reference the Formatter so that the LoggingEvent record can be formatted and sent later.  


The third requirement baffles Xiao Zhang. Different classes and packages output different destinations? The concept of "destination" is expressed by Appender. Can different classes and packages be associated with Appender? No, no, no!  


A new concept is needed. What is this concept?  


From the perspective of users, if villagers want to obtain logs, they must first obtain something. Can this thing be called a Logger? The spark of inspiration flashed, and then Xiao Zhang caught it: when obtaining the Logger, you should pass in the class name or package name!  

In this way, different classes and packages can be distinguished, and then the Logger and Appender can be associated to flexibly set the log destination. In addition, a Logger can have multiple Appenders, and the same log message can be output to multiple places. Perfect!

Xiao Zhang quickly drew the class diagram of the core class




It was pretty. Xiao Zhang enjoyed himself.  


Make persistent efforts and design the fourth requirement. The log should be graded. This is simple. Define a Priority class, which defines five constants: DEBUG, info, warn, error and FATAL, indicating that five different levels are OK. Of course, there are five levels, DEBUG level is the lowest and FATAL level is the highest.


You can also add some auxiliary programming methods to the logger, such as logger debug(....) , Logger. info(...)   , Logger.warn(...) Wait, so that the villagers can easily output various levels of logs in the future.


Wait a minute, the old village head also said that "all ERROR level logs are output to the ERROR.log file". Such requirements seem to be ignored.


It's easy to do. Just add an attribute on the Appender, which is called Priority. If the user wants to output the log at the DEBUG level, but the Priority of a FileAppender is the ERROR level, then the log doesn't need to be output in the FileAppender, because the ERROR level is higher than the DEBUG level.


Similarly, a Priority attribute can be added to the Logger class, which can be set by the user. If the Priority of a Logger is ERROR and the user calls the debug method of the Logger, the debug message will not be output.


Xiao Zhang threw himself into the design wholeheartedly. When he saw the time, it was almost midnight. Take a break and report to the village head tomorrow.  


4 orthogonality

The next day, Xiao Zhang showed the old village head his designed loggerevent, logger, appender, formatter, priority and other classes and interfaces. The old village head twirled his beard and nodded with satisfaction: "good, good, great progress compared with the last time. Do you know that I actually gave you guidance in my needs?"


"Guidance? What guidance?"


"Is to make you work in an orthogonal direction"




"If you regard logger, appender and formatter as X-axis, Y-axis and Z-axis in the coordinate system, can they change independently without affecting each other?"


"I believe that's true. I can arbitrarily extend the Appender interface without affecting the Logger and Formatter. No matter how many loggers there are, they can't affect the Appender and Formatter. That's orthogonality?"


"Yes, when you extract orthogonal concepts from the system, it's very powerful, because changes are encapsulated in a dimension. You can combine these concepts arbitrarily without turning them into spaghetti like code."


Hearing that the village head sublimated his theory, Xiao Zhang rubbed his hands with excitement.  


"Well, you have implemented this design. By the way, what's your name?" Asked the village head


"I'm going to call him Log4j, which means Log for Java"


"Yes, that's it."



Xiao Zhang spent another two months to develop Log4j. Because Log4j has good design and excellent performance, it is not only used by people in Zhangjia village, but also loved by many villages, towns and tribes in Java empire.


Later, zhangjiacun opened Log4j in the Apache tribe, which attracted countless people to help test it, expand it and improve it for free. It soon became the most popular logging tool in the Empire.


Zhangjiacun suggested that the Empire include Log4j into JDK, but the Empire's inefficient bureaucracy refused. When the news reached the ears of minister IO, he couldn't help sighing: Alas, he lost an excellent opportunity to recruit security. Now the only way is to play the emperor quickly and provide a set in the official, so as to make the subjects use the official version.


By the fourth King (JDK1.4), the subjects finally saw the Java provided by the Empire util. The logging package is also used to record logs. The core concepts of Logger, Formatter, Handler and log4j are very similar, but it is too late. Log4j has long been deeply rooted in the hearts of the people and cannot be shaken.   


6 ending

After log4j became open source in Apache, Xiao Zhang gradually became a little lonely. He couldn't stop writing a tool called logback. With previous experience, logback is faster than log4j.  


Today's log world has many choices, except Java util. Besides logging and log4j, there are other tools such as logback and tinylog.


Xiao Zhang thought about it. With so many logging tools, what should users do if they want to switch? I don't want to use log4j anymore. Can I change to logback?  


I'd better provide an abstraction layer. Users use the API of this abstraction layer to write logs. It doesn't matter what logging tools are used at the bottom, so they can be transplanted.  


Xiao Zhang called this abstraction layer Simple Logging Facade for Java, SLF4J for short.   


For log4j, JDK, logging, tinylog and other tools, an adaptation layer is needed to convert the API of SLF4J into the calling interface of specific tools.  


Since Logback is also a tool created by Xiao Zhang and directly implements the API of SLF4J, it doesn't even need the adaptation layer. It is used quickly and has the highest efficiency. SLFJ4+Logback has become the favorite of many people and has the potential to surpass Apache Common Logging + Log4j.  


Postscript: This article mainly wants to talk about the history and current situation of logging tools, especially the design concept of Log4j core.


Xiao Zhang in this article is actually Ceki G ü lc ü. He developed log4j, logback and slfj4, which has made outstanding contributions to the logging industry of Java.


journal? Have a chat slf4j

Transfer from https://juejin.im/post/5ad1ccc86fb9a028c14ae528

As a Java programmer, Ken https://juejin.im/post/5ad1ccc86fb9a028c14ae528 It is no stranger to logging. Logging is necessary regardless of the size of the project; Because good logs can easily help us locate some production problems.

What I miss is saying nothing out. Println ("here is the important log");

What I miss is dreaming together err. Println ("here is the error log");

For daily development, system out. Println works well, but why not use it to output logs in actual development applications?

System.out.println() is really of little use except for its convenience. Where is the convenience? In Eclipse, you just need to enter syso [output out in IDEA], and then press the code prompt key, and this method will come out automatically. I believe this is also the reason why many novices of Java love it, because I did it in the beginning until [tears are omitted here]. What are the shortcomings? There are too many. For example, the log printing is uncontrollable, the printing time cannot be determined, the filter cannot be added, and the log has no level distinction

I remember that I first came into contact with log4j. Log4j is an open source project of Apache. By using log4j, we can control that the destination of log information transmission is the console, files and other places we expect it to output; We can also control the output format of each log; By defining the level of each log information, we can control the log generation process in more detail. Importantly, these can be flexibly configured through a configuration file without modifying the application code.

Indeed, log4j, as the first popular logging framework, has brought us great convenience in application development and maintenance. So why did such an excellent framework slowly walk down the "altar" in the end? And gradually replaced by logback? The following is an explanation of this problem from a big man on the Internet:

In terms of design and implementation, logback has made relatively many improvements compared with log4j. However, although it is difficult to count them one by one, here are some reasons why logback is selected instead of log4j. Keep in mind that logback and log4j are very similar in concept. They are established by the same group of developers.

  • Faster execution

    Based on our previous work on log4j, logback rewrites the internal implementation. In some specific scenarios, it can even be 10 times faster than before. While ensuring that the components of logback are faster, it requires less memory.

  • Adequate testing

    Logback has been tested for years and countless hours. Although log4j has also been tested, logback is more fully tested, which is not at the same level as log4j. We believe that this is the most important reason why people choose logback instead of log4j. People want your diary framework to be stable and reliable even under bad conditions.

slf4j log4j logback

slf4j:The Simple Logging Facade for Java is the simple logging facade of java

In short, slf4j is a series of logging interfaces. Slf4j exists as an abstract behavior of logging, but it does not provide a real implementation.

slf4j provides a unified interface for various logging frameworks, so that users can record logs with a unified interface, but dynamically determine the real implementation framework. logback, log4j, common logging and other frameworks implement these interfaces.

slf4j source code analysis

After thinking for a long time, I don't know where to start. There are 29 classes in slf4j package [version 1.7.21], which can't be listed one by one. So from the statement we are familiar with.

private static final Logger logger =

The above code is actually a common way for us to declare a log object in the code.


Let's first look at the methods provided by the Logger interface;

package org.slf4j;
public interface Logger {
    //Root Logger
    String getName();
    //Judge whether the recorder Trace tracking is activated; After Trace tracking is activated, more detailed information will be printed.
    boolean isTraceEnabled();
    //trace level
    void trace(String var1);
    void trace(String var1, Object var2);
    void trace(String var1, Object var2, Object var3);
    void trace(String var1, Object... var2);
    void trace(String var1, Throwable var2);
    boolean isTraceEnabled(Marker var1);
    void trace(Marker var1, String var2);
    void trace(Marker var1, String var2, Object var3);
    void trace(Marker var1, String var2, Object var3, Object var4);
    void trace(Marker var1, String var2, Object... var3);
    void trace(Marker var1, String var2, Throwable var3);
    //Make pre judgment and improve system performance
    boolean isDebugEnabled();
    void debug(String var1);
    void debug(String var1, Object var2);
    void debug(String var1, Object var2, Object var3);
    void debug(String var1, Object... var2);
    void debug(String var1, Throwable var2);
    boolean isDebugEnabled(Marker var1);
    void debug(Marker var1, String var2);
    void debug(Marker var1, String var2, Object var3);
    void debug(Marker var1, String var2, Object var3, Object var4);
    void debug(Marker var1, String var2, Object... var3);
    void debug(Marker var1, String var2, Throwable var3);
    //info level
    boolean isInfoEnabled();
    void info(String var1);
    void info(String var1, Object var2);
    void info(String var1, Object var2, Object var3);
    void info(String var1, Object... var2);
    void info(String var1, Throwable var2);
    boolean isInfoEnabled(Marker var1);
    void info(Marker var1, String var2);
    void info(Marker var1, String var2, Object var3);
    void info(Marker var1, String var2, Object var3, Object var4);
    void info(Marker var1, String var2, Object... var3);
    void info(Marker var1, String var2, Throwable var3);
    //warn level
    boolean isWarnEnabled();
    void warn(String var1);
    void warn(String var1, Object var2);
    void warn(String var1, Object... var2);
    void warn(String var1, Object var2, Object var3);
    void warn(String var1, Throwable var2);
    boolean isWarnEnabled(Marker var1);
    void warn(Marker var1, String var2);
    void warn(Marker var1, String var2, Object var3);
    void warn(Marker var1, String var2, Object var3, Object var4);
    void warn(Marker var1, String var2, Object... var3);
    void warn(Marker var1, String var2, Throwable var3);
    //error level
    boolean isErrorEnabled();
    void error(String var1);
    void error(String var1, Object var2);
    void error(String var1, Object var2, Object var3);
    void error(String var1, Object... var2);
    void error(String var1, Throwable var2);
    boolean isErrorEnabled(Marker var1);
    void error(Marker var1, String var2);
    void error(Marker var1, String var2, Object var3);
    void error(Marker var1, String var2, Object var3, Object var4);
    void error(Marker var1, String var2, Object... var3);
    void error(Marker var1, String var2, Throwable var3);


Use isdebuginabled to illustrate the function of this isXXXXEnabled method.

logger.debug("the debug msg is " +doMethod());

Assuming that our log level is set to info, this sentence will not output the log, but this method will still be called (pre judgment function). To call this method, you must provide parameters. The result returned by the domethod () method is part of the parameter. doMethod() needs to be executed for n seconds. After n seconds, enter the debug() method;

But the log level is info. The result is that although the log has no output, it takes n seconds to construct parameters. Obviously, the gains here are not worth the losses. Although it is almost impossible to take n seconds to construct such a parameter in practical application, if the number of concurrency is large, such writing will still affect the performance of the system. At this time, it should be written as:

    logger.debug("the debug msg is " + doMethod());

Next, the LoggerFactory class; Let's start with getLogger as the entry:

public static Logger getLogger(String name) {
    ILoggerFactory iLoggerFactory = getILoggerFactory();
    return iLoggerFactory.getLogger(name);
public static Logger getLogger(Class<?> clazz) {
    Logger logger = getLogger(clazz.getName());
        Class<?> autoComputedCallingClass = Util.getCallingClass();
        if (autoComputedCallingClass != null && nonMatchingClasses(clazz, autoComputedCallingClass)) {
            Util.report(String.format("Detected logger name mismatch. Given name: \"%s\"; computed name: \"%s\".", logger.getName(), autoComputedCallingClass.getName()));
            Util.report("See http://www.slf4j.org/codes.html#loggerNameMismatch for an explanation");
    return logger;

The getLogger method provides two overload methods. One is to pass in a name to mark the name of the current log. The other is to provide a Class object. In fact, it is also through clazz Getname() as the name of the log.

From the above code, you can clearly see the ILoggerFactory interface.

package org.slf4j;
public interface ILoggerFactory {
    Logger getLogger(String var1);

The ILoggerFactory interface actually provides a unified top-level type for different log implementations; Each logging framework needs to implement ILoggerFactory interface to explain how it provides loggers. log4j and logback, which can provide parent-child hierarchical relationship, are implemented in the implementation class of ILoggerFactory. At the same time, they also need to implement the Logger interface to complete logging.

Implementation in logback

public class LoggerContext extends ContextBase implements
ILoggerFactory, LifeCycle

As mentioned above, the implementation of different logging frameworks implements the ILoggerFactory interface.

public final Logger getLogger(final String name) {
    if (name == null) {
        throw new IllegalArgumentException("name argument cannot be null");
    // if we are asking for the root logger, then let us return it without
    // wasting time
    if (Logger.ROOT_LOGGER_NAME.equalsIgnoreCase(name)) {
        return root;
    int i = 0;
    Logger logger = root;
    // check if the desired logger exists, if it does, return it
    // without further ado.
    Logger childLogger = (Logger) loggerCache.get(name);
    // if we have the child, then let us return it without wasting time
    if (childLogger != null) {
        return childLogger;
    // if the desired logger does not exist, them create all the loggers
    // in between as well (if they don't already exist)
    String childName;
    while (true) {
        int h = LoggerNameUtil.getSeparatorIndexOf(name, i);
        if (h == -1) {
            childName = name;
        } else {
            childName = name.substring(0, h);
        // move i left of the last point
        i = h + 1;
        synchronized (logger) {
            childLogger = logger.getChildByName(childName);
            if (childLogger == null) {
                childLogger = logger.createChildByName(childName);
                loggerCache.put(childName, childLogger);
        logger = childLogger;
        if (h == -1) {
            return childLogger;

For the source code of logback, please refer to this series of articles: logback source code series articles


Java log framework combing - SLF4J+log4j

Transfer from https://blog.csdn.net/xktxoo/article/details/76359366

The configuration file of log4j is used to set the level, storage location and layout of the recorder. It can be set in Java property file (key = value) format or XML format. Log4j profile element introduction:


Logger is an Object that allows applications to record logs. Developers do not have to consider the output location. The application can transfer the specific information to be printed through an Object. Loggers are named entities. Each logger is independent of each other. Their names are case sensitive and follow hierarchical naming rules:

If the name of a logger is prefixed with the name of another logger after a period, the former is called the ancestor of the latter. If there is no other ancestor between the logger and its offspring, the former is called the father of the child logger.

The root logger is located at the top of the logger level and is the common ancestor of each level. How to get the root logger:

Logger rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
  • 1

The logger can be assigned a level. If the logger is not assigned a level, it will inherit the level from the nearest ancestor without the assigned level to the root logger. By default, the root logger level is DEBUG.

The additivity of the Appender is defined as follows:

The output of logger A's record statement will be sent to all Appenders of a and its ancestors. If an ancestor B of logger a sets the superposition flag to false, the output of a will be sent to all Appenders between a and B (including B), but will not be sent to any ancestor Appender of B


Each Appender can configure log recording devices independently, including console, file, database, message system, etc. The Appenders provided by log4j are as follows:

org.apache.log4j.DailyRollingFileAppenderOne log file is generated every day
org.apache.log4j.RollingFileAppenderWhen the file size reaches the specified size, a new file is generated
org.apache.log4j.WriterAppenderSend log information to any specified place in stream format


The format of the data in the log is also called Layout, which is responsible for the conversion of the final data in the log. log4j provides the following layouts:

org.apache.log4j.HTMLLayoutLayout in HTML form
org.apache.log4j.PatternLayoutYou can flexibly specify the layout mode
org.apache.log4j.SimpleLayoutThe level and information string containing the log information
org.apache.log4j.TTCCLayoutIt contains the time, thread, category and other information of log generation

log4j uses the print format similar to printf in C language to format the log information. The print parameters are as follows

%mOutput messages specified in the code
%pOutput log level
%rOutput the number of milliseconds that the logging took from the start of the application to the origin
%cOutput the class that triggers the log event
%tOutputs the thread that triggered the log event
%dOutput the time when the log event occurs, such as:%-d{yyyy-MM-dd HH:mm:ss}
%lThe location where the output log occurs, including class information, threads, and number of lines


Each print log can specify the log level separately, and the output level can be controlled through the configuration file. log4j provides the following log levels:

ALLLowest level, used to turn on all logging
TRACESpecify events with finer granularity than DEBUG
DEBUGSpecifying fine-grained information events is helpful for debugging applications
INFOSpecify coarse-grained information events and highlight the running process of the program
WARNSpecify situations with potential hazards
ERRORSpecify the error event and the program is still allowed to run
FATALSpecify a very serious error event that may cause the application to terminate
OFFThe highest level used to turn off logging


SLF4J+log4j practice

The following pom dependencies can be added to the log4j adapter binding. After adding the configuration, two dependency packages will be automatically pulled down, namely slf4j-api-1.7.25 and log4j-1.2.17.



Log4j must specify a configuration file or default configuration. If the above package is introduced into the program and the log is printed when the configuration file is not written and the default configurator is not set, log4j will report the following error:

public class Test {
    public static void main(String [] args) {
        Logger logger  = LoggerFactory.getLogger(Test.class);
        logger.debug( " this is {} debug log", Test.class.getName() );
        logger.error( " this is {} error log", Test.class.getName());
log4j:WARN No appenders could be found for logger (com.xiaofan.test.Test).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.

Through basicconfigurator Configure() can specify log4j default configurator, which generates rootLogger by default and adds a console Appender. The source code is as follows:


    static public void configure() {
        Logger root = Logger.getRootLogger();
        root.addAppender(new ConsoleAppender(
               new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN)));



The log printing results are as follows:

0 [main] DEBUG com.xiaofan.test.Test  -  this is com.xiaofan.test.Test debug log
2 [main] ERROR com.xiaofan.test.Test  -  this is com.xiaofan.test.Test error log


There are two ways to write log4j configuration files: Java attribute file (key=value) and XML.

  • log4j.properties 
    An example of a property configuration file is as follows:
### set log levels ###
log4j.rootLogger = debug,stdout,D,E
### Output to console ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern =  %-d{yyyy-MM-dd HH:mm:ss} %p [%c] %m%n
### Output to log file ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG 
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
### Save exception information to a separate file ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File = logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
### logger ### 
# After setting, com The log under Xiaofan path will only output ERROR log

Set log4j The properties file is placed in the resources folder of the project. If the program does not specify other configuration files, log4j will load log4j by default The properties file is used as the configuration file. Through propertyconfigurator Configure() displays the specified external configuration file.  

The test code is as follows:

package com.xiaofan.test;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.xml.DOMConfigurator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 * Created by Jerry on 17/7/24.
public class Test {
    public static void main(String [] args) {
        Logger logger  = LoggerFactory.getLogger(Test.class);
        logger.debug( " this is {} debug log", Test.class.getName() );
        logger.error( " this is {} error log", Test.class.getName());
    2017-07-27 09:44:50 DEBUG [com.xiaofan.test.Test]  this is com.xiaofan.test.Test debug log
    2017-07-27 09:44:50 ERROR [com.xiaofan.test.Test]  this is com.xiaofan.test.Test error log
    2017-07-27 09:48:27  [ main:1 ] - [ ERROR ]   this is com.xiaofan.test.Test error log
    2017-07-27 09:48:27  [ main:0 ] - [ DEBUG ]   this is com.xiaofan.test.Test debug log
    2017-07-27 09:48:27  [ main:1 ] - [ ERROR ]   this is com.xiaofan.test.Test error log
  • log4j.xml

    The XML configuration file is as follows:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/' >
    <appender name="console" class="org.apache.log4j.ConsoleAppender">
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern"
                   value="[%d{yyyy-MM-dd HH:mm:ss,SSS\} %-5p] %c{2\} [%t] - %m%n" />
        <filter class="org.apache.log4j.varia.LevelRangeFilter">
            <param name="levelMin" value="debug" />
            <param name="levelMax" value="error" />
            <param name="AcceptOnMatch" value="true" />
    <appender name="ERROR" class="org.apache.log4j.RollingFileAppender">
        <param name="File" value="logs/error.log" />
        <param name="Append" value="true" />
        <param name="threshold" value="error" />
        <param name="MaxBackupIndex" value="10" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%p (%c:%L)- %m%n" />
    <appender name="INFO" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="File" value="logs/log.log" />
        <param name="DatePattern" value="'.'yyyy-MM-dd'.log'" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern"
                   value="[%d{MMdd HH:mm:ss SSS\} %-5p] [%t] %c{3\} - %m%n" />
    <logger name="mylogger" additivity="true">
        <level value="debug" />
        <appender-ref ref="INFO" />
        <priority value ="debug"/>
        <appender-ref ref="INFO"/>
        <appender-ref ref="ERROR" />
        <appender-ref ref="console" />

Set log4j The XML file is placed in the resources folder of the project. If the program does not display other configuration files, log4j will load log4j by default XML file as configuration file. You can use domconfigurator Configure() displays the external configuration file.  
The test code is as follows:


    public class Test {
        public static void main(String [] args) {
            Logger logger  = LoggerFactory.getLogger(Test.class);
            logger.debug( " this is {} debug log", Test.class.getName() );
            logger.error( " this is {} error log", Test.class.getName());
        [2017-07-27 12:43:20,474 DEBUG] test.Test [main] -  this is com.xiaofan.test.Test debug log
        [2017-07-27 12:43:20,484 ERROR] test.Test [main] -  this is com.xiaofan.test.Test error log
        ERROR (com.xiaofan.test.Test:18)-  this is com.xiaofan.test.Test error log
        [0727 12:50:04 829 DEBUG] [main] xiaofan.test.Test -  this is com.xiaofan.test.Test debug log
        [0727 12:50:04 830 ERROR] [main] xiaofan.test.Test -  this is com.xiaofan.test.Test error log


Topics: Java