spring-bootlogginglog4j2slf4j

Dynamically set DEBUG or INFO logging level per request based on request header in reactive Spring Boot with Log4j2


I'm working on a Reactive Spring Boot application that uses Log4j2 as the logging framework. By default, my application logs at the INFO level, and I set the logging level in the application.yml

I would like to be able to log at the DEBUG level for only one specific request without changing the logging level globally or affecting other concurrent requests. For example, if I pass a custom header (e.g., X-Debug-Logging: true) for a request, I want that request to log at the DEBUG level, but the other parallel requests should continue logging at the default INFO level.

What I've Tried: I have implemented a WebFilter to check for the X-Debug-Logging header and adjust the logging level, but I'm concerned that since Reactive Spring handles requests asynchronously, changing the log level could affect other requests that are processed concurrently.

Question: How can I dynamically log at the DEBUG level for a single request in a Reactive Spring application, using Log4j2, while ensuring that other concurrent requests continue logging at the default INFO level?

Use cases:


Solution

  • What you are looking for is the DynamicThresholdFilter or ContextMapFilter, which allows you to filter messages based on the current context data.

    When filters are used as global filters (i.e. direct children of <Configuration>):

    (see Logger stage for details).

    So all you need to do is:

    1. At each request add a value to the Log4j API Thread Context (e.g. sampled) and propagate it to all the threads, were the request will be handled.
    2. Configure a Log4j filter to return ACCEPT if sampled is true and NEUTRAL otherwise.

    Setting and propagating the Thread Context

    As you noticed, propagating the value is probably the hardest task. For that I suggest you to read Dariusz blog series on context propagation. In this particular case you need to:

    Configuring the Log4j filter

    You can use DynamicThresholdFilter, which:

    <Configuration xmlns="https://logging.apache.org/xml/ns"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xsi:schemaLocation="
                       https://logging.apache.org/xml/ns
                       https://logging.apache.org/xml/ns/log4j-config-2.xsd">
      <DynamicThresholdFilter key="sampled"
                              onMatch="ACCEPT"
                              onMismatch="NEUTRAL">
        <KeyValuePair key="true" value="DEBUG"/>
      </DynamicThresholdFilter>
      <!-- Your `Appenders` and `Loggers` go here: -->
    </Configuration>