4
votes

I'm using Log4j 2 to log the events of my application. However I'm stuck at the following problem.

Currently all logging messages are being written to two different appenders. One has RollingFile type, while the other has Console type.

What I want is for the RollingFile appender to log messages with an INFO level or higher (ERROR, FATAL), and for the Console appender to log messages with an ERROR level or higher (FATAL).

Inside my log4j2.xml file I seem to be only able to declare the logging level for an entire logger (including all of its appenders). Here is my log4j2.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration monitorInterval="30">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout>
                <Pattern>%d %level %msg%n</Pattern>
            </PatternLayout>
        </Console>
        
        <RollingFile name="Log" fileName="log/Log.log" filePattern="log/Log-%d{yyyy-MM-dd}-%i.log" append="false">
            <PatternLayout>
                <Pattern>%d %level %msg%n</Pattern>
            </PatternLayout>
            <Policies>
                <SizeBasedTriggeringPolicy size="1 MB" />
            </Policies>
            <DefaultRolloverStrategy max="10"/>
        </RollingFile>
    </Appenders>

    <Loggers>
        <Root level="info">
            <AppenderRef ref="Console" />
            <AppenderRef ref="Log" />
        </Root>
    </Loggers>
</Configuration>

Is there an easy way of doing so? I searched log4j documentation but couldn't find what I was looking for (Maybe I missed it?). If it's possible I would really prefer for the solution to be applicable on any appenders' types; not specific for RollingFile and Console.

EDIT:

I saw many questions where it was asked to write ONLY the messages from a certain level to a file, while writing the messages from a different level to a different file. In my case I need the messages with a certain level of HIGHER to be written to different files. For example in the case I provided messages with level ERROR or FATAL will be written to both the RollingFile and Console, while messages with level INFO will be written to RollingFile only.

2
I really don't think so. In the question you provided it was about writing ONLY the INFO messages to a file, and ONLY the ERROR messages to a different file. In my case I want to write the messages from a certain level or HIGHER to separate files.Said A. Sryheni

2 Answers

4
votes

To limit logging level on specific appender in log4j2 you should use ThresholdFilter element of an appender.

In your case log4j2.xml file will look like:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration monitorInterval="30">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout>
                <Pattern>%d %level %msg%n</Pattern>
            </PatternLayout>
        </Console>
    
        <RollingFile name="Log" fileName="log/Log.log" filePattern="log/Log-%d{yyyy-MM-dd}-%i.log" append="false">
            <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout>
                <Pattern>%d %level %msg%n</Pattern>
            </PatternLayout>
            <Policies>
                <SizeBasedTriggeringPolicy size="1 MB" />
            </Policies>
            <DefaultRolloverStrategy max="10"/>
        </RollingFile>
    </Appenders>

    <Loggers>
        <Root level="info">
            <AppenderRef ref="Console" />
            <AppenderRef ref="Log" />
        </Root>
    </Loggers>
</Configuration>

Here is a simple test:

public class Log4jTest {
    private static final Logger logger = LogManager.getLogger(Log4jTest.class);

    public static void main(String[] args) {
        logger.debug("Debug");
        logger.info("Info");
        logger.warn("Warning");
        logger.error("Error");
        logger.fatal("Fatal");
    }
}

Console output:

2020-02-25 12:33:50,587 ERROR Error
2020-02-25 12:33:50,589 FATAL Fatal

Log.log contents:

2020-02-25 12:33:50,585 INFO Info
2020-02-25 12:33:50,587 WARN Warning
2020-02-25 12:33:50,587 ERROR Error
2020-02-25 12:33:50,589 FATAL Fatal

In first version of log4j it was Threshold property of appender. On how to solve the same in log4j see the answer on question.

With aid of filters Log4j2 allows to configure the output to a specific appender much more flexible then log4j.

1
votes

This should do the trick.

<Loggers>
    <Root level="debug" additivity="false">
        <AppenderRef ref="Console"/>
    </Root>
    <Logger name="com.project.package" level="info" additivity="false">
        <AppenderRef ref="Log" />
    </Logger>
</Loggers>

Alternatively, you could do it like this - Different level of logs in different log files

BTW, this is explained very nicely in the Log4j2 documentation. See - https://logging.apache.org/log4j/2.x/manual/configuration.html