Bart Pelle
Bart Pelle

Reputation: 757

Log4j 2 doesn't write to file

Having the following config file:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="[%d{HH:mm:ss.SSS} %-5level] %logger{36} - %msg%n"/>
        </Console>
        <File name="File" fileName="error.log">
            <PatternLayout pattern="[%d{ISO8601} %-5level] %logger{36} - %msg%n"/>
        </File>
    </Appenders>
    <Loggers>
        <Logger name="errors" level="error">
            <AppenderRef ref="File"/>
        </Logger>
        <Root level="all">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

only writes (all) logging output to the console. I however had the intention to write anything above error to a file named error.log with a slightly different format. However, running my application results in everything being written to the console, leaving an empty file behind (which gets created, just not filled).

Somehow it seems like the Root logger catches everything because I had also tried this:

<Logger name="errors" level="error">
    <AppenderRef ref="Console"/>
</Logger>

which does not log twice. I'm out of ideas really, I even copied an example from the docs (sample #2 from here) and that aswell leaves an empty file.

Upvotes: 13

Views: 27786

Answers (4)

Mike Ashby
Mike Ashby

Reputation: 51

Log4J2 doesn't write to file until the process has completed. By default the buffer isn't flushed with each call to the logger. For example,

<File name="File" fileName="LogfileName.log" immediateFlush="false" append="false">
<PatternLayout pattern="%d{yyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</File>

will not log to the file immediately. Change the values of immediateFlush to true to force the buffer to flush on each call to logger.

Upvotes: 1

Remko Popma
Remko Popma

Reputation: 36844

Yes, the root logger level is ALL so it will receive all events. One option is to do this:

<Loggers>
  <Root level="all">
    <AppenderRef ref="Console" level="trace" />
    <AppenderRef ref="File" level="error" />
  </Root>
</Loggers>

This way you only have one logger, so you don't need to worry about additivity and in your code you can just write LogManager.getLogger(MyClass.class) to get a Logger instance. (If you use a named Logger, you would need to use the logger name in your code: LogManager.getLogger("error").)

Upvotes: 18

Sireesh Yarlagadda
Sireesh Yarlagadda

Reputation: 13736

Try this something like this.

Here Target is important attribute to be noticed.

The console appender has one param element defined. Looking at the javadoc for ConsoleAppender , the setTarget method is used to choose which console stream to print messages to, System.out or System.err. The example configures the appender to use System.out.

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
  <appender name="console" class="org.apache.log4j.ConsoleAppender"> 
    <param name="Target" value="System.out"/> 
    <layout class="org.apache.log4j.PatternLayout"> 
      <param name="ConversionPattern" value="%-5p %c{1} - %m%n"/> 
    </layout> 
  </appender> 

  <root> 
    <priority value ="debug" /> 
    <appender-ref ref="console" /> 
  </root>

</log4j:configuration>

Upvotes: -2

Bart Pelle
Bart Pelle

Reputation: 757

Ah, I was being stupid. The attribute name seems to be a filter for which classes will use that logger. Changing name to my top level package resolved the issue.

Upvotes: 8

Related Questions