SLF4J

Slf4j Format String Example

In this example, we are going to see how String log messages can be constructed in SLF4J with parameter substitution.

1. Introduction

SLF4J is a facade or an abstraction layer over various logging frameworks. Also known as Simple logging Facade for Java is not actually a logging implementation, instead, it’s an abstraction layer. It allows you to use any logging library with it.

Now if you would ask why SLF4J, when we already have so many logging frameworks. The answer is, you can write your piece of pluggable code using SLF4J for logging without worrying about the underlying implementation. Now whatever the application which will use your pluggable piece, can use the logging implementation of it’s own choice.

While constructing logging messages, programmers often need to provide some piece of information to be able to trace the cause of the problem as well as to know general flow of information in erroneous as well as normal cases. SLF4J provides an easy way to construct these messages; in this example we will see how.

2. Technologies Used

For this example, we use the following tools on a Windows 10 platform:

  • Eclipse IDE
  • Apache Maven
  • JDK 1.8
  • Slf4j 1.7.25
  • Log4J 1.2.17

3. SLF4J Format String Example

3.1 Create a Maven Project

We will create a bare minimum Maven project. Once you have the Maven installed and running on your machine, issue the following command from the command line.

mvn archetype:generate -DgroupId=com.javacodegeeks -DartifactId=slf4j-formatting -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

In this example, Maven will manage dependencies for us and we don’t need to download any jars explicitly.

3.2 Add Maven Dependencies

Add the required dependencies for SLF4J and log4j. Your pom.xml should look like this.

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.javacodegeeks</groupId>
  <artifactId>slf4-formatting</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>slf4-formatting</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
    	<groupId>org.slf4j</groupId>
    	<artifactId>slf4j-api</artifactId>
    	<version>1.7.25</version>
    </dependency>
    <dependency>
    	<groupId>org.slf4j</groupId>
    	<artifactId>slf4j-log4j12</artifactId>
    	<version>1.7.25</version>
    </dependency>
    <dependency>
    	<groupId>log4j</groupId>
    	<artifactId>log4j</artifactId>
    	<version>1.2.17</version>
    </dependency>
  </dependencies>
</project>

3.3 Log4J Properties

SLF4J being an abstraction layer needs to have an underlying logging implementation. For this example we are using log4j. Create log4j.properties for the log4j configuration.

log4j.properties

# Root logger option
log4j.rootLogger=INFO, stdout

# Direct log messages to stdout
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} %-5p %c{1} - %m%n

3.4 Test Class

We are going to use SLF4J’s style of parameter substitution for log messages formatting. Though these logging calls look simple but behind the scenes it uses org.slf4j.helpers.MessageFormatter to format messages.

Slf4jSusbstitutionExample.java

package com.javacodegeeks.slf4.formatting;

import java.lang.invoke.MethodHandles;
import java.text.MessageFormat;
import java.util.Calendar;

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

/**
 * Substituting Parameters!
 *
 */
public class Slf4jSusbstitutionExample 
{
	private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
	
    public static void main( String[] args )
    {
    	String user = "john";
    	String application = "gateway";
    	
    	// Crafting a message without substitution.
    	// Not a good idea as the String concatenation and evaluation will happen irrespective of whether
    	// logging level is permissible or not to be logged.
        LOGGER.info("Bad experience for user " + user + " at time " + Calendar.getInstance().getTime());
    	
        // Substitution with one formatting anchor and one argument
        LOGGER.info("Bad experience for user {}", user);
        
        // If you happen to forget to provide a substituting object
        LOGGER.info("Bad experience for user {}");
        
        // Substitution with two formatting anchors and two arguments
        LOGGER.info("Bad experience for user {} at time {}", user, Calendar.getInstance().getTime());
        
        // Substitution with three formatting anchors and three arguments
        LOGGER.info("Bad experience for user {} at time {} while accessing {}", user, Calendar.getInstance().getTime(), application);
        
        // Escaping formatting anchor
        LOGGER.info("ERROR CODE \\{}; Bad experience for user {} at time {}", user, Calendar.getInstance().getTime());
        
        // Formatting anchor with data inside; no problem
        LOGGER.info("ERROR CODE {22}; Bad experience for user {} at time {}", user, Calendar.getInstance().getTime());
        
        // Crafting a message with Java's own MessageFormatter.
        // Not a good idea as per SLF4J's documentation.
        // 1. SLF4J's implementation is 10 times faster than that of MessageFormat.
        // 2. Moreover to make sure that the evaluation happens only if that particular logging
        // level is allowed, you need to do a check.
        if(LOGGER.isInfoEnabled()) {
        	String message = MessageFormat.format("Bad experience for user {0} at time {1} while accessing {2}", user, Calendar.getInstance().getTime(), application);
        	LOGGER.info(message);
        }
    }
}

Output

2017-04-20 20:25:42 INFO  Slf4jSusbstitutionExample - Bad experience for user john at time Thu Apr 20 20:25:42 IST 2017
2017-04-20 20:25:42 INFO  Slf4jSusbstitutionExample - Bad experience for user john
2017-04-20 20:25:42 INFO  Slf4jSusbstitutionExample - Bad experience for user {}
2017-04-20 20:25:42 INFO  Slf4jSusbstitutionExample - Bad experience for user john at time Thu Apr 20 20:25:42 IST 2017
2017-04-20 20:25:42 INFO  Slf4jSusbstitutionExample - Bad experience for user john at time Thu Apr 20 20:25:42 IST 2017 while accessing gateway
2017-04-20 20:25:42 INFO  Slf4jSusbstitutionExample - ERROR CODE {}; Bad experience for user john at time Thu Apr 20 20:25:42 IST 2017
2017-04-20 20:25:42 INFO  Slf4jSusbstitutionExample - ERROR CODE {22}; Bad experience for user john at time Thu Apr 20 20:25:42 IST 2017
2017-04-20 20:25:42 INFO  Slf4jSusbstitutionExample - Bad experience for user john at time 4/20/17 8:25 PM while accessing gateway

As per SLF4J’s documentation of org.slf4j.helpers.MessageFormatter, following points are worth noting:

Formats messages according to very simple substitution rules. Substitutions can be made 1, 2 or more arguments.

  1. The {} pair is called the formatting anchor. It serves to designate the location where arguments need to be substituted within the message pattern.
  2. If for whatever reason you need to place the string “{}” in the message without its formatting anchor meaning, then you need to escape the ‘{‘ character with ‘\’, that is the backslash character. Only the ‘{‘ character should be escaped. There is no need to escape the ‘}’ character.
  3. The formatting conventions are different than those of MessageFormat which ships with the Java platform. This is justified by the fact that SLF4J’s implementation is 10 times faster than that of MessageFormat. This local performance difference is both measurable and significant in the larger context of the complete logging processing chain.

4. Summary

SLF4J’s substitution parameters while constructing log messages is suggested over String concatenation for the following two reasons:

  1. No explicit check needed for log level
  2. Performance improvement – If the log message is not supposed to be logged then the message will not simply be constructed.

NOTE:

  1. SLF4J provides a mechanism for parameters substitution not C style parameters formatting. Formatting parameters lives with the underlying logging implementation (like the one PatternLayout provided by log4j).
  2. Markers are beyond the scope of this example. Also, SLF4J doesn’t provide any implementation for markers and leaves that part with the logging frameworks.

5. References

  1. https://www.slf4j.org/faq.html#yet_another_facade
  2. https://examples.javacodegeeks.com/enterprise-java/slf4j/slf4j-configuration-file-example/
  3. https://www.slf4j.org/api/org/slf4j/helpers/MessageFormatter.html

6. Download the Eclipse Project

You can download the full source code of this example here: slf4j-formatting.

Mayank Gupta

Senior JEE developer with experience in large scale IT projects, especially in the telecommunications and financial services sectors. Mayank has been designing and building J2EE applications since 2007. Fascinated by all forms of software development; keen to explore upcoming areas of technology like AI, machine learning, blockchain development and AR. Lover of gadgets, apps, technology and gaming.
Subscribe
Notify of
guest

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

0 Comments
Inline Feedbacks
View all comments
Back to top button