Core Java

Logback File Appender Example

Operating under the assumption that you’ve stumbled onto this article because you’re a programmer and trying to solve a problem as painlessly as possible, I’m going to keep this direct and to the point. This post in no way delves completely into the mysteries of Logback, logging filters, or appenders – for that you’re going to have to read the manual. Presented here is a quick solution to the problem: how do I get Logback to send messages of one type to a particular destination while sending messages of a different type to another destination?

Here’s how, from start to finish:
 
 

1. Create a Simple Program that Logs Stuff

Logback, by default, doesn’t require any sort of configuration file to run. You can create a simple program that logs messages to System.out very easily:

App.java

package com.holiday.jcga1;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class App {

   public static void main( String[] args ) {
      Logger logger = LoggerFactory.getLogger("Example App");
      logger.info("'sup? I'm your info logger");
      logger.debug("hey HEY hey! I'm your debug logger");
   }

}

Which will result in something like this:

23:20:15.692 [main] INFO  Example App - 'sup? I'm your info logger
23:20:15.696 [main] DEBUG Example App - hey HEY hey! I'm your debug logger

Now this is all well and good if your project isn’t logging much – but what happens when the messages get so voluminous that you lose track of important ones? Moreover, what if you need to archive log files for later analysis? With Logback, it’s pretty simple to create multiple repositories for your logging stream.

2. Create Multiple Repositories for Your Logging Stream

To make this happen, we’re going to be updating your logback.xml file. If you don’t have a logback.xml file, go ahead and create one and plunk it in whichever spot in your classpath tickles your pickle. If you’re using Maven to build the project, I highly suggest the src/main/resources directory. Here is a sample logback.xml file that we’ll use for this example:

logback.xml

<configuration>
   <timestamp key="byDay" datePattern="yyyyMMdd'T'HHmmss"/>

   <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
      <encoder>
         <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
      </encoder>
   </appender>

   <appender name="FILE" class="ch.qos.logback.core.FileAppender">
      <file> log-${byDay}.txt </file>
      <append>true</append>
      <encoder>
         <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
      </encoder>
   </appender>

   <root level="debug">
      <appender-ref ref="FILE" />
      <appender-ref ref="STDOUT" />
   </root>

</configuration>

Go ahead and build/run the program. You should see the same output to System.out as well as a new file added to your project that contains the same logging messages. This because by-in-large, this config file is doing exactly what the default configuration does – format logging messages into something pretty and pipe them to System.out. That’s the role of an appender – it directs logging messages to various places at which they can be printed/stored. Note that in addition to an appender definition for STDOUT, we also have one that pipes messages to a file.

3. Route Logging Messages Based On Level

The last thing we need to do is figure out how to route messages based on level. In this case, we may want to only see INFO messages at the console, but both INFO and DEBUG messages in the logfile. To make that happen, we need to add a filter parameter to the appender definition. Here’s what one looks like:

logback.xml

<configuration>
   <timestamp key="byDay" datePattern="yyyyMMdd'T'HHmmss"/>

   <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
      <filter class="ch.qos.logback.classic.filter.LevelFilter">
         <level>INFO</level>
         <onMatch>ACCEPT</onMatch>
         <onMismatch>DENY</onMismatch>
      </filter>
      <encoder>
         <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
      </encoder>
   </appender>

   <appender name="FILE" class="ch.qos.logback.core.FileAppender">
      <file> log-${byDay}.txt </file>
      <append>true</append>
      <encoder>
         <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
      </encoder>
   </appender>

   <root level="debug">
      <appender-ref ref="FILE" />
      <appender-ref ref="STDOUT" />
   </root>

</configuration>

Note the addition of the filter element in the STDOUT appender. It basically stands at the gates of System.out and bellows “You Shall Not Pass!” to any message that is the bearer of anything other than an INFO level message. You can add filters to any of your appenders in this way, or do fancier stuff by other means. As previously mentioned, logback has lots of useful features to handle these kinds of situations. While the contents of this article barely scratch the surface, I do hope it proved helpful in solving your immediate challenge of figuring out how to route logback messages of different logging levels to different places.

Download the Source Code

This was an example about Logback File Appender.

Download
You can download the full source code of this example here : LogbackAppenderExample.zip

David Holiday

David Holiday has a Masters in Philosophy and is currently pursuing a second in Computer Science. Currently employed as a software engineer, he is keenly interested in Emergence, the mind/body relationship, and issues of personhood. He is also unabashedly in love with both gaming and sci-fi.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Vadim
Vadim
5 years ago

I tried this example on Mac High Sierra,
Log file is created but stays empty.
Does anyone have any idea why log file is not populated?
Thanks

Jonn
Jonn
3 years ago
Reply to  Vadim

where the log file is created? In which directory?

Jane
Jane
4 years ago

very helpful

Back to top button