The MDC (mapped diagnostic context) is a common approach in application logging which helps identifying the context of a log message. For example, in a web application it could be desirable to have the username logged with each message, so that in case of an issue developers can easily trace what happened to that particular user.
Both major Java logging frameworks - Logback and Log4J - support this feature. Typically, you would access the MDC using the static methods of the MDC
class provided by the SLF4J library:
// Put a custom value to the MDC
MDC.put("Name", "Value");
// Get a custom value from the MDC
MDC.get("Name");
// Remove a custom value from the MDC
MDC.remove("Name");
However, this bloats the source code of your business logic with a rather technical aspect.
ExtendMDC provides a Java aspect which offers a declarative way of setting values in the MDC. It allows you to use Java annotations to define fixed values on method level or even have the values of method parameters written into the MDC.
ExtendMDC comes as a pure AspectJ implementation which can be used in any Java project. To facilitate usage in Spring-based projects we provide an auto-configuration and a plug-and-play Spring Boot starter.
See the following sections to get started…
If you want to use the plain aspect and do all what it takes to make it work, then you simply add the following dependency to your project:
<dependency>
<groupId>dev.bileto</groupId>
<artifactId>extend-mdc-aspect</artifactId>
<version>2.0.0-SNAPSHOT</version>
</dependency>
Hint: See the tags for the release versions.
The library provides the ExtendMDCAspect
class which defines the advice.
If you are using Spring you can let the framework set up the aspect for you (note that there is an easier way if you are using Spring Boot, see below). First add the following dependencies to your project:
<dependency>
<groupId>dev.bileto</groupId>
<artifactId>extend-mdc-aspect</artifactId>
<version>2.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
Hint: See the tags for the release versions.
Hint: Choose suitable versions for spring-aop
and aspectjweaver
depending on the version of Spring you are using in your project.
Then add the aspect as a bean to your application context and enable the aspect processing:
@Configuration
@EnableAspectJAutoProxy
public class AspectConfiguration {
@Bean
public ExtendMDCAspect extendMDCAspect() {
return new ExtendMDCAspect();
}
}
If you are using Spring Boot you can leverage its auto-configuration mechanism to wire up the aspect. All you need to do is add the following dependencies to your project:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>dev.bileto</groupId>
<artifactId>extend-mdc-spring-boot-starter</artifactId>
<version>2.0.0-SNAPSHOT</version>
</dependency>
Hint: See the tags for the release versions.
Hint: The spring-boot-starter-aop
is required to provide all the Spring-AOP dependencies since we want to keep our starter independent of the Spring version.
In order to apply the aspect to the execution of a certain method you simply annotate this method with @ExtendMDC
. This allows you to specify custom MDC values which should only be present during the execution of this method.
You can configure fixed values to be set during the execution of a certain method. The @ExtendMDC
annotation can take an arbitrary number of @MDCValue
arguments for those MDC values.
@ExtendMDC({
@MDCValue(value = "Name 1", content = "Fixed Value 1"),
@MDCValue(value = "Name 2", content = "Fixed Value 2")
})
public void someAdvisedMethod() {
// MDC contains "Name 1" and "Name 2" values while this is executed
}
You can configure the aspect to add certain method arguments as values to the MDC while the method is executed. Simply use the @MDCValue
annotation on the method parameters and provide the name of the MDC value.
@ExtendMDC
public void someAdvisedMethod(@MDCValue("Name") String interestingParam, String otherParam) {
// MDC contains "Name" with the value of interestingParam while this is executed
}