
io.bdeploy.common.util.MdcLogger Maven / Gradle / Ivy
package io.bdeploy.common.util;
import java.util.Arrays;
import java.util.function.Consumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import com.google.common.base.Joiner;
/**
* Utility class that simplifies writing log statements with MDC data.
*
* The logger is typically {@link #setMdcValue initialized} with a fixed MDC value that is attached to all log calls.
* If required {@link #log(Consumer, Object...) additional} data can be passed to each log call.
*
* Typical usage pattern:
*
*
* public class MyClass {
* private final MdcLogger logger = new MdcLogger(MyClass.class);
*
* public MyClass() {
* logger.setMdc("green");
* }
*
* public void foo() {
* logger.log((l) -> l.info("Doing some work."));
*
* logger.log((l) -> l.info("Doing more work."),"red");
* }
* }
*
* The following output will be printed when a pattern layout is used:
* %-12.12MDC{BDEPLOY} | %-5level | %-20msg - (%F)%n
*
* green | INFO | Doing some work. - (MyClass.java)
* green / red | INFO | Doing more work. - (MyClass.java)
*
*
* The actual log call is delegated to a functional interface so that the line numbers and the class is preserved in the log
* statements. As consequence it is also up the the caller to check if the desired log level is enabled.
*
*/
public class MdcLogger {
/**
* The key to which all MDC data is associated with.
*/
public static final String MDC_NAME = "BDEPLOY";
private final Logger log;
private Object[] mdcData = new Object[0];
/**
* Creates a new instance using the given logger.
*
* @param clazz the class used by the logger
*/
public MdcLogger(Class> clazz) {
this.log = LoggerFactory.getLogger(clazz);
}
/**
* Sets the MDC value that will be associated with all subsequent log calls.
*
* @param value
* the value to associate with the MDC key.
*/
public void setMdcValue(Object... value) {
this.mdcData = value;
}
/**
* Writes the desired log statement. The previously configured MDC value will be set during the logger is called.
*
* @param writer
* the logger to be used to write the log statement
*/
public void log(Consumer writer) {
doLog(log, writer, mdcData);
}
/**
* Writes the desired log statement. The given MDC data is added to the already defined MDC data. Typically used when there is
* a base MDC value that should be present in all statements but in some additional values are required.
*
* @param writer
* logger to be used to write the log statement
* @param mdcData
* data to associate with the MDC key
*/
public void log(Consumer writer, Object... mdcData) {
Object[] unifiedMdc = Arrays.copyOf(this.mdcData, this.mdcData.length + mdcData.length);
System.arraycopy(mdcData, 0, unifiedMdc, this.mdcData.length, mdcData.length);
doLog(log, writer, unifiedMdc);
}
/** Writes the desired log statement */
private static void doLog(Logger logger, Consumer writer, Object... mdcData) {
MDC.put(MDC_NAME, Joiner.on(" / ").join(mdcData));
try {
writer.accept(logger);
} finally {
MDC.remove(MDC_NAME);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy