Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

Small question regarding MDC with Java please.

At first, I had very straightforward methods, some methods with many parameters (I shorten the list of parameters to keep things short just for this question, but please imagine a lot of parameters)

 public String invokeMethodForPerson(int age, String name, boolean isCool, long distanceRun, double weight) {
        LOGGER.info("begin to invoke method invokeMethodForPerson");
        return methodForPerson(age, name, isCool, distanceRun, weight);
    public String invokeMethodForCar(String model, boolean isElectric, long price, int numberOfDoors) {
        LOGGER.info("begin to invoke method invokeMethodForCar");
        return methodForCar(model, isElectric, price, numberOfDoors);
    public String invokeMethodForFlower(String name, String color) {
        LOGGER.info("begin to invoke method invokeMethodForFlower");
        return methodForFlower(name, color);

(This question is not about how to refactor the long list of parameters)

Then, I wanted to leverage MDC. MDC is very helpful, it allow better search in log aggregator tools etc. Having them as first level, not inside the logger itself is very helpful.

Therefore, in order to leverage MDC, the code went from simple, to something now similar to this, here is what I tried.

public String invokeMethodForPerson(int age, String name, boolean isCool, long distanceRun, double weight) {
        MDC.put("age", age);
        MDC.put("name", name);
        MDC.put("isCool", isCool);
        MDC.put("distanceRun", distanceRun);
        MDC.put("weight", weight);
        LOGGER.info("begin to invoke method invokeMethodForPerson");
        return methodForPerson(age, name, isCool, distanceRun, weight);
    public String invokeMethodForCar(String model, boolean isElectric, long price, int numberOfDoors) {
        MDC.put("model", model);
        MDC.put("isElectric", isElectric);
        MDC.put("price", price);
        MDC.put("numberOfDoors", numberOfDoors);
        LOGGER.info("begin to invoke method invokeMethodForCar");
        return methodForCar(model, isElectric, price, numberOfDoors);
    public String invokeMethodForFlower(String name, String color) {
        MDC.put("name", name);
        MDC.put("color", color);
        LOGGER.info("begin to invoke method invokeMethodForFlower");
        return methodForFlower(name, color);

Problem: now looking at the code, there is actually more lines of MDC.put() than actual business logic code

Question: Is there a cleaner way to leveraging MDC, for many parameters, other than just adding tons of lines of MDC.put(), if possible, using AOP/aspects/advice/pointcut please?

Thank you

Interesting question. I have something on my mind, not unlike Eugene's answer, but not requiring you to make lengthy method calls with two parameters per method argument. Instead, I am rather going to use AspectJ. But just now I am too busy to create an example and try, and I do not want to post untested code. So if until then you did not receive another similar AOP-style answer, I think I can answer later today or tomorrow. – kriegaex Apr 19, 2022 at 7:43

You can create your own utils to work with MDC.

public class MDCUtils {
    private MDCUtils() {
    public static void putAll(Object... params) {
        if ((params.length & 1) != 0) {
            throw new IllegalArgumentException("Length is odd");
        for (int i = 0; i < params.length; i += 2) {
            String key = Objects.requireNonNull((String) params[i]); //The key parameter cannot be null
            Object value = params[i + 1]; //The val parameter can be null only if the underlying implementation supports it.
            MDC.put(key, value);
    public static void putAll(Map<String, Object> map) {
        map.forEach(MDC::put);
    public static <K extends String, V> void put(K k1, V v1, K k2, V v2) {
        putAll(k1, v1, k2, v2);
    public static <K extends String, V> void put(K k1, V v1, K k2, V v2, K k3, V v3) {
        putAll(k1, v1, k2, v2, k3, v3);

Example of usage:

    public String invokeMethodForPerson(int age, String name, boolean isCool, long distanceRun, double weight) {
        MDCUtils.putAll("age",age, "name", name,"isCool", isCool,"distanceRun", distanceRun,"weight", weight);
        LOGGER.info("begin to invoke method invokeMethodForPerson");
        return methodForPerson(age, name, isCool, distanceRun, weight);

More strict example:

    public String invokeMethodForFlower(String name, String color) {
        MDCUtils.put("name", name, "color", color);
        LOGGER.info("begin to invoke method invokeMethodForFlower");
        return methodForFlower(name, color);

Example using Map.of, but it does not support nullable values.

    public String invokeMethodForPerson(int age, String name, boolean isCool, long distanceRun, double weight) {
        MDCUtils.putAll(Map.of( "age",age,"name", name,"isCool", isCool,"distanceRun", distanceRun,"weight", weight));
        LOGGER.info("begin to invoke method invokeMethodForPerson");
        return methodForPerson(age, name, isCool, distanceRun, weight);

UPDATE:
AOP solution via AspectJ
Add annotation @LogMDC for method and parameter target. The idea is to add the ability to put all method arguments or specific ones to MDC

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface LogMDC {

Add aspect which will catch methods marked with @LogMDCannotation and perform storing arguments to the MDC.

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
@Aspect
public class MDCAspect {
    //match the method marked @LogMDC annotation
    @Before("@annotation(LogMDC) && execution(* *(..))")
    public void beforeMethodAnnotation(JoinPoint joinPoint) {
        String[] argNames = ((MethodSignature) joinPoint.getSignature()).getParameterNames();
        Object[] values = joinPoint.getArgs();
        if (argNames.length != 0) {
            for (int i = 0; i < argNames.length; i++) {
                MDC.put(argNames[i], values[i]);
    //match the method which has any parameter with @LogMDC annotation
    @Before("execution(* *(.., @LogMDC (*), ..))")
    public void beforeParamsAnnotation(JoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String[] argNames = methodSignature.getParameterNames();
        Object[] values = joinPoint.getArgs();
        Method method = methodSignature.getMethod();
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        for (int i = 0; i < parameterAnnotations.length; i++) {
            Annotation[] annotations = parameterAnnotations[i];
            for (Annotation annotation : annotations) {
                if (annotation.annotationType() == LogMDC.class) {
                    MDC.put(argNames[i], values[i]);

Example of using. Put all parameters of method to MDC

    @LogMDC
    public String invokeMethodForPerson(int age, String name, boolean isCool, long distanceRun, double weight) {
        LOGGER.info("begin to invoke method invokeMethodForPerson");
        return methodForPerson(age, name, isCool, distanceRun, weight);

Example of using. Put only specific parameters of the method to MDC, that marked with annotation.

    public String invokeMethodForPerson(@LogMDC int age, @LogMDC String name, boolean isCool, long distanceRun, @LogMDC double weight) {
        LOGGER.info("begin to invoke method invokeMethodForPerson");
        return methodForPerson(age, name, isCool, distanceRun, weight);

Please note, AspecJ have a little performace impact
Performance penalty for using AspectJ
Performance impact of using aop
Performance: using AspectJ to log run time of all methods

Depends on your use cases you should decide what to use simple util method call or aop solution.

I am not going to write another answer out of respect to you, because you updated yours with an AOP solution before I could start implementing one. But I want to say a few things: (1) The performance impact, like I said in the answer you linked to, is small and usually not noticeable compared to what the cross-cutting concern extracted into the aspect actually does. I.e., if you would do the same in every method instead of in the aspect, there would not be a big difference, but lots of scattered logger calls in the application code. – kriegaex Apr 20, 2022 at 3:46 (2) I also said in my answer that with native AspectJ it is even less overhead. Some aspect functionality is directly inlined into the code, there are not proxies and not indirection for method calls. The overhead in those cases is zero. But anyway, it should not be a big concern, especially compared to the reflection code used to gather the parameter information. You are using Spring AOP in your example. The OP did not give any indication that he is using Spring at all. A native AspectJ example would therefore have been better, because it would also work outside of Spring. – kriegaex Apr 20, 2022 at 3:49 (3) The OP asked for a solution to log all parameters. So why bother scattering the many annotations across the code? AOP ideally does not require the application code to be aspect-aware. The OP can write his pointcut in such a way that only the methods he wants to log are actually targeted by the aspect. Furthermore, your example logs all annotated parameters anyway, not just the annotated ones. That seems to be a bug. – kriegaex Apr 20, 2022 at 3:51 Like I said, I do not want to steal your success by writing my own AOP answer, unless you agree with it or the OP asks me to. Then I would write one, otherwise maybe you want to refactor yours. – kriegaex Apr 20, 2022 at 3:53 Hi, feel free to add another answer, I used compile-time weaving (ajc compiler), proxy aop implementation is not an option it is slow. I do not agree that performance impact will be "zero", I would say little or not significant. Log specific parameter is flexible and can be useful, for example log only one parameter from certain method – Eugene Apr 20, 2022 at 8:53

I'd try to leverage MDC.setContextMap() and getCopyOfContextMap.

This way you can provide a whole map of parameters at once.

Just be careful as setContextMap clears any existing values put there before.

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.