Search code examples
log4j2

Log4j2: Log ERROR level into a specific file


In my log4j2 configuration, I have an AsyncRoot set to INFO because I want to log this level and upper in a file.

But I would like also to log the ERROR level into a specific file AND in the appender configured in the AsyncRoot

Here is my configuration:

<?xml version="1.0" encoding="utf-8"?>
<Configuration>
    <Appenders>
        <RollingFile name="file" fileName="${LOG_PATH}/${APP_NAME}.log" filePattern="${LOG_PATH}/${APP_NAME}-${FILE_PATTERN_TRAILER}.log">
            <PatternLayout pattern="${PATTERN_LAYOUT}"/>
            <Policies>
                <SizeBasedTriggeringPolicy size="50 MB"/>
                <TimeBasedTriggeringPolicy/>
            </Policies>
            <DefaultRolloverStrategy max="5"/>
        </RollingFile>
        <RollingFile name="errorFile" fileName="${LOG_PATH}/${APP_NAME}-errors.log" filePattern="${LOG_PATH}/${APP_NAME}-errors-${FILE_PATTERN_TRAILER}.log">
            <PatternLayout pattern="${PATTERN_LAYOUT}"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
            </Policies>
        </RollingFile>
    </Appenders>
    <Loggers>
        <AsyncRoot level="INFO">
            <AppenderRef ref="file"/>
        </AsyncRoot>

        <AsyncLogger level="ERROR">
            <AppenderRef ref="errorFile"/>
        </AsyncLogger>
    </Loggers>
</Configuration>

Here is the logging behaviour I'd like to achieve (no matter the package) :

  • All the logs with INFO log level are logged into the appender file
  • All the logs with ERROR log level are logged into the appender file and errorFile
  • All the logs with a lower log level (DEBUG, TRACE) aren't logged at all

Thank you


Solution

  • You can achieve what you want by setting the root logger's level to info since you don't want any trace or debug events to reach your appenders. Set the level on the error file appender to error so that only events of that level or more specific are written to the file.

    Here's a simple example that you can adapt to your needs:

    Example Java class to generate some log events:

    package example;
    
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    
    public class SomeClass {
    
        private static final Logger log = LogManager.getLogger();
    
        public static void main(String[] args){
            log.debug("This is some debug!");
            log.info("Here's some info!");
            log.error("Some error happened!");
        }
    }
    

    log4j2.xml config file:

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="WARN">
        <Appenders>
            <File name="ErrorFile"
                  fileName="logs/error.log"
                  immediateFlush="false"
                  append="false">
                <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
            </File>
            <File name="InfoFile"
                  fileName="logs/info.log"
                  immediateFlush="false"
                  append="false">
                <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
            </File>
        </Appenders>
        <Loggers>
            <Root level="info">
                <AppenderRef ref="InfoFile"/>
                <AppenderRef ref="ErrorFile"
                             level="error"/>
            </Root>
        </Loggers>
    </Configuration>
    

    This generates 2 files: error.log and info.log

    error.log contains only the ERROR:

    2019-12-04 10:05:34.672 [main] ERROR example.SomeClass - Some error happened!
    

    info.log contains both the ERROR and the INFO events:

    2019-12-04 10:05:34.670 [main] INFO  example.SomeClass - Here's some info!
    2019-12-04 10:05:34.672 [main] ERROR example.SomeClass - Some error happened!