Log4j2 ThreadContext – Fish Tagging

Log4j2 ThreadContext allows us to tag the log statements with multiple unique tags to analyze logs while diagnose a problem in runtime – mostly in multithreaded applications where applications generate plenty of logging in short duration.

For example, we may want to scan all logs for a particular user transaction or complete session. This process is also called fish tagging (i.e. add some extra context information in every log statement). The fish tagging can help using the automated tools for logs such as Splunk.

Let’s see how we can use ThreadContext class for fish tagging in log4j2.

1. Add and Remove Context Information

1.1. ThreadContext.put()

To uniquely stamp each request, ThreadContext provide put(String key, String value) method which accept a key and it’s value. We can add as many tags as we need to capture the whole context information. Note that all methods of the ThreadContext class are static.

package com.howtodoinjava.log4j2.examples;

import java.util.UUID;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;

public class Log4j2HelloWorldExample 
{
	private static final Logger LOGGER = LogManager.getLogger(Log4j2HelloWorldExample.class.getName());
	
	public static void main(String[] args) 
	{
		//Add context information
		ThreadContext.put("id", UUID.randomUUID().toString());
		ThreadContext.put("ipAddress", "192.168.21.9");
		
		LOGGER.debug("Debug Message Logged !!");
		LOGGER.info("Info Message Logged !!");
		LOGGER.debug("Another Debug Message !!");
		
		//Clear the map
		ThreadContext.clearMap();
		
		LOGGER.debug("Thread Context Cleaned up !!");
		LOGGER.debug("Log message with no context information !!");
	}
}

1.2. ThreadContext.push()

Or We can use ThreadContext’s Stack implemeration with ThreadContext.push(String value) as below:

//Add context information
ThreadContext.push(UUID.randomUUID().toString());
ThreadContext.push("192.168.21.9");

LOGGER.debug("Debug Message Logged !!");
LOGGER.info("Info Message Logged !!");
LOGGER.debug("Another Debug Message !!");

//Clear the map
ThreadContext.clearStack();

LOGGER.debug("Thread Context Cleaned up !!");
LOGGER.debug("Log message with no context information !!");

1.3. ThreadContext.clearMap()

After the transaction is over or context information is no more required, you can empty the information using ThreadContext.clearMap() method.

ThreadContext’s Stack and Map are managed per thread and are based on ThreadLocal by default. By setting system property isThreadContextMapInheritable to true, contents of context map will be passed to child threads.

2. Modify Conversion Pattern

Now to print the above tags in log statements, we need to modify the conversion pattern in the log4j2 configuration file.

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
	<Appenders>
		<Console name="console" target="SYSTEM_OUT">
			<PatternLayout
				pattern="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] [%X{id}] [%X{ipAddress}] %c{1} - %msg%n" />
		</Console>
	</Appenders>
	<Loggers>
		<Root level="debug" additivity="false">
			<AppenderRef ref="console" />
		</Root>
	</Loggers>
</Configuration>
  • Use %X by itself to include the full contents of the Map.
  • Use %X{key} to include the specified key.
  • Use %x to include the full contents of the Stack.

Now when you run the above code – we will get the below output:

 
[DEBUG] 2016-06-21 13:09:56.485 [main] [7cdd4cf0-2c26-4b81-b374-1adce3781499] [192.168.21.9] Log4j2HelloWorldExample - Debug Message Logged !!
[INFO ] 2016-06-21 13:09:56.487 [main] [7cdd4cf0-2c26-4b81-b374-1adce3781499] [192.168.21.9] Log4j2HelloWorldExample - Info Message Logged !!
[DEBUG] 2016-06-21 13:09:56.487 [main] [7cdd4cf0-2c26-4b81-b374-1adce3781499] [192.168.21.9] Log4j2HelloWorldExample - Another Debug Message !!
[DEBUG] 2016-06-21 13:09:56.487 [main] [] [] Log4j2HelloWorldExample - Thread Context Cleaned up !!
[DEBUG] 2016-06-21 13:09:56.487 [main] [] [] Log4j2HelloWorldExample - Log message with no context information !!

As you can see the first three log statements have context information added to them – and the other two statements do not have such information.

Happy Learning !!

Was this post helpful?

Join 7000+ Fellow Programmers

Subscribe to get new post notifications, industry updates, best practices, and much more. Directly into your inbox, for free.

1 thought on “Log4j2 ThreadContext – Fish Tagging”

  1. Hi I have a main function as below, though I am setting ‘log4j2.isThreadContextMapInheritable’ to ‘true’ the key-value pair I set to ThreadContext is not reaching the child thread(thread created on button click).
    Can you please help me to resolve this issue:

    public class Application {
    static {
        System.setProperty("log4j2.isThreadContextMapInheritable","true");
    }
    
    private final static Logger LOGGER = LogManager.getLogger(Application.class);
    
    public static void main(String[] args) throws Exception
    {
        ThreadContext.put("cfg","RLS");
    
        LOGGER.info("New window opening!!!"+ThreadContext.get("cfg"));
        newWindow();
    }
    
    private static void newWindow() throws Exception {
        ButtonFrame buttonFrame = new ButtonFrame("Button Demo");
        buttonFrame.setSize( 350, 275 );     
        buttonFrame.setVisible( true );
    }
    
    Reply

Leave a Comment

HowToDoInJava

A blog about Java and its related technologies, the best practices, algorithms, interview questions, scripting languages, and Python.