spring-projects / spring-boot

Spring Boot
https://spring.io/projects/spring-boot
Apache License 2.0
74.48k stars 40.53k forks source link

Support for registering a custom Logback Converter conversion rule #38687

Open filiphr opened 9 months ago

filiphr commented 9 months ago

In order to register a Custom Logback Converter through conversion rules it is currently required to provide a custom logback.xml file. It is also impossible to provide custom conversion rules through other auto configuration means such as a Spring Boot Auto configuration or some other spring factory mechanism.

The use case for this is to provide some additional context information to the logging. e.g. the currently authenticated user when logging.

If this is something that the Spring Boot team is willing to accept I am more than happy to work on providing an extension mechanism for this.

I have 2 approaches in mind (they can be complimentary to one another).

Using a Customizer

public interface LoggerContextCustomizer {

    void customize(LoggerContext context);

}

This can be applied in the DefaultLogbackConfinguration prior to applying the Spring defaults:

https://github.com/spring-projects/spring-boot/blob/6dff3c5978158f5ddae67b3b92200a90b3b188b7/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/DefaultLogbackConfiguration.java#L58

The LoggerContextCustomizer customizers won't be exposed as beans, but they would be registered in a similar way as the org.springframework.boot.diagnostics.FailureAnalyzer in the spring.factories.

Using properties

This approach could use a property to register custom conversion rules e.g.

logging.logback.conversion-rule.<conversionWord>=<converterClass>

This approach is more limiting that the one using a customizer and it does close the gap to Log4J 2. This approach might also be slightly less invasive and would only be targeted towards conversion rules.


Such an approach is not needed for Log4J 2 since Log4J 2 has a completely different mechanism of registering custom converters and the only thing we need to do there is to write our converter with the recommended approach by Log4J 2 and the converter keys will be automatically be available to be used in the log pattern

wilkinsona commented 9 months ago

https://github.com/spring-projects/spring-boot/issues/25847 is somewhat related to this.

philwebb commented 9 months ago

We discussed this today and we wondered if using the existing mechanisms in Logback would work for you? You can add a META-INF/services/ch.qos.logback.classic.spi.Configurator file that references a Configurator implementation which has the following signature ExecutionStatus configure(LoggerContext context). That looks quite similar to the LoggerContextCustomizer you're proposing.

The only thing we're not sure about is if our programmatic configuration will override what you want to do. Perhaps you can prototype something and let us know?

filiphr commented 9 months ago

Thanks a lot for looking into this.

You can add a META-INF/services/ch.qos.logback.classic.spi.Configurator file that references a Configurator implementation which has the following signature ExecutionStatus configure(LoggerContext context). That looks quite similar to the LoggerContextCustomizer you're proposing.

I wasn't aware about that configurator. Thanks for the suggestion @philwebb. I did some initial testing and it wasn't picked up. However, I'll spend some more time and try it out in a standalone Spring Boot project (ours is big and something else might be in the way)

The only thing we're not sure about is if our programmatic configuration will override what you want to do. Perhaps you can prototype something and let us know?

Yes sure, I will prototype something. From my initial exploration I believe that it should work, but let's see.

I hope to provide some more information in the following weeks.

filiphr commented 9 months ago

I had more time to try it out today and my custom configurator gets registered properly and I can add a custom converter. However, the Spring Boot LogbackLoggingSystem resets everything that was configured prior to that. This is happening in

https://github.com/spring-projects/spring-boot/blob/561c7f749ba05e65cdabaf3ecd505132edab3081/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java#L294C1-L300

And when LoggerContext#stop is called the objectMap (where I am adding the converter) gets cleared. I guess that is the reason why you have the RootLogLevelConfigurator as well.

Do you know why you are stopping and resetting the context? Should Spring Boot perhaps copy the Logback PATTERN_RULE_REGISTRY prior to resetting?

Should perhaps Spring apply some of the defaults via a Configurator and only the properties through the existing mechanism?

Depending on what you think about my questions I can go ahead and either prototype a mechanism that will allow for configuring what we need through Spring Boot or add something that will at least preserver the PATTERN_RULE_REGISTRY.