diff --git a/src/main/java/org/slf4j/impl/Constant.java b/src/main/java/org/slf4j/impl/Constant.java index 32d8955..29cd1ac 100644 --- a/src/main/java/org/slf4j/impl/Constant.java +++ b/src/main/java/org/slf4j/impl/Constant.java @@ -106,6 +106,11 @@ public interface Constant { */ String DISABLE_COLOR = SYSTEM_PREFIX + "disable-color"; + /** + * logger.open-trace-id + */ + String OPEN_TRACE_ID = SYSTEM_PREFIX + "open-trace-id"; + Map LOG_DESC_MAP = new HashMap() { private static final long serialVersionUID = -8216579733086302246L; diff --git a/src/main/java/org/slf4j/impl/MDC.java b/src/main/java/org/slf4j/impl/MDC.java new file mode 100644 index 0000000..efa5a2b --- /dev/null +++ b/src/main/java/org/slf4j/impl/MDC.java @@ -0,0 +1,229 @@ +package org.slf4j.impl; + +import org.slf4j.helpers.BasicMDCAdapter; +import org.slf4j.helpers.NOPMDCAdapter; +import org.slf4j.helpers.Util; +import org.slf4j.spi.MDCAdapter; + +import java.io.Closeable; +import java.util.Map; + +/** + * use {@link BasicMDCAdapter} as default {@link MDCAdapter} to save some info + * like trace id ... + * @author makaikai + * @DATE 2022/8/2 + */ +public class MDC { + + + static final String NULL_MDCA_URL = "http://www.slf4j.org/codes.html#null_MDCA"; + static final String NO_STATIC_MDC_BINDER_URL = "http://www.slf4j.org/codes.html#no_static_mdc_binder"; + static MDCAdapter mdcAdapter; + + /** + * An adapter to remove the key when done. + */ + public static class MDCCloseable implements Closeable { + private final String key; + + private MDCCloseable(String key) { + this.key = key; + } + + public void close() { + org.slf4j.MDC.remove(this.key); + } + } + + private MDC() { + } + + /** + * 使用{@link BasicMDCAdapter} 作为默认的MDCAdapter + * + * @return MDCAdapter + * @throws NoClassDefFoundError in case no binding is available + * @since 1.7.14 + */ + private static MDCAdapter bwCompatibleGetMDCAdapterFromBinder() throws NoClassDefFoundError { + try { + return new BasicMDCAdapter(); + } catch (NoSuchMethodError nsme) { + // binding is probably a version of SLF4J older than 1.7.14 + return StaticMDCBinder.SINGLETON.getMDCA(); + } + } + + static { + try { + mdcAdapter = bwCompatibleGetMDCAdapterFromBinder(); + } catch (NoClassDefFoundError ncde) { + mdcAdapter = new NOPMDCAdapter(); + String msg = ncde.getMessage(); + if (msg != null && msg.contains("StaticMDCBinder")) { + Util.report("Failed to load class \"org.slf4j.impl.StaticMDCBinder\"."); + Util.report("Defaulting to no-operation MDCAdapter implementation."); + Util.report("See " + NO_STATIC_MDC_BINDER_URL + " for further details."); + } else { + throw ncde; + } + } catch (Exception e) { + // we should never get here + Util.report("MDC binding unsuccessful.", e); + } + } + + /** + * Put a diagnostic context value (the val parameter) as identified with the + * key parameter into the current thread's diagnostic context map. The + * key parameter cannot be null. The val parameter + * can be null only if the underlying implementation supports it. + * + *

+ * This method delegates all work to the MDC of the underlying logging system. + * + * @param key non-null key + * @param val value to put in the map + * + * @throws IllegalArgumentException + * in case the "key" parameter is null + */ + public static void put(String key, String val) throws IllegalArgumentException { + if (key == null) { + throw new IllegalArgumentException("key parameter cannot be null"); + } + if (mdcAdapter == null) { + throw new IllegalStateException("MDCAdapter cannot be null. See also " + NULL_MDCA_URL); + } + mdcAdapter.put(key, val); + } + + /** + * Put a diagnostic context value (the val parameter) as identified with the + * key parameter into the current thread's diagnostic context map. The + * key parameter cannot be null. The val parameter + * can be null only if the underlying implementation supports it. + * + *

+ * This method delegates all work to the MDC of the underlying logging system. + *

+ * This method return a Closeable object who can remove key when + * close is called. + * + *

+ * Useful with Java 7 for example : + * + * try(MDC.MDCCloseable closeable = MDC.putCloseable(key, value)) { + * .... + * } + * + * + * @param key non-null key + * @param val value to put in the map + * @return a Closeable who can remove key when close + * is called. + * + * @throws IllegalArgumentException + * in case the "key" parameter is null + */ + public static MDCCloseable putCloseable(String key, String val) throws IllegalArgumentException { + put(key, val); + return new MDCCloseable(key); + } + + /** + * Get the diagnostic context identified by the key parameter. The + * key parameter cannot be null. + * + *

+ * This method delegates all work to the MDC of the underlying logging system. + * + * @param key + * @return the string value identified by the key parameter. + * @throws IllegalArgumentException + * in case the "key" parameter is null + */ + public static String get(String key) throws IllegalArgumentException { + if (key == null) { + throw new IllegalArgumentException("key parameter cannot be null"); + } + + if (mdcAdapter == null) { + throw new IllegalStateException("MDCAdapter cannot be null. See also " + NULL_MDCA_URL); + } + return mdcAdapter.get(key); + } + + /** + * Remove the diagnostic context identified by the key parameter using + * the underlying system's MDC implementation. The key parameter + * cannot be null. This method does nothing if there is no previous value + * associated with key. + * + * @param key + * @throws IllegalArgumentException + * in case the "key" parameter is null + */ + public static void remove(String key) throws IllegalArgumentException { + if (key == null) { + throw new IllegalArgumentException("key parameter cannot be null"); + } + + if (mdcAdapter == null) { + throw new IllegalStateException("MDCAdapter cannot be null. See also " + NULL_MDCA_URL); + } + mdcAdapter.remove(key); + } + + /** + * Clear all entries in the MDC of the underlying implementation. + */ + public static void clear() { + if (mdcAdapter == null) { + throw new IllegalStateException("MDCAdapter cannot be null. See also " + NULL_MDCA_URL); + } + mdcAdapter.clear(); + } + + /** + * Return a copy of the current thread's context map, with keys and values of + * type String. Returned value may be null. + * + * @return A copy of the current thread's context map. May be null. + * @since 1.5.1 + */ + public static Map getCopyOfContextMap() { + if (mdcAdapter == null) { + throw new IllegalStateException("MDCAdapter cannot be null. See also " + NULL_MDCA_URL); + } + return mdcAdapter.getCopyOfContextMap(); + } + + /** + * Set the current thread's context map by first clearing any existing map and + * then copying the map passed as parameter. The context map passed as + * parameter must only contain keys and values of type String. + * + * @param contextMap + * must contain only keys and values of type String + * @since 1.5.1 + */ + public static void setContextMap(Map contextMap) { + if (mdcAdapter == null) { + throw new IllegalStateException("MDCAdapter cannot be null. See also " + NULL_MDCA_URL); + } + mdcAdapter.setContextMap(contextMap); + } + + /** + * Returns the MDCAdapter instance currently in use. + * + * @return the MDcAdapter instance currently in use. + * @since 1.4.2 + */ + public static MDCAdapter getMDCAdapter() { + return mdcAdapter; + } + +} diff --git a/src/main/java/org/slf4j/impl/SimpleLogger.java b/src/main/java/org/slf4j/impl/SimpleLogger.java index cb983b4..7724d4d 100755 --- a/src/main/java/org/slf4j/impl/SimpleLogger.java +++ b/src/main/java/org/slf4j/impl/SimpleLogger.java @@ -260,6 +260,15 @@ private void log(int level, String message, Throwable t) { buf.append(threadName); } + if(CONFIG_PARAMS.openTraceId){ + String traceId = MDC.get("traceId"); + if(null != traceId){ + buf.append("[traceId: "); + buf.append(traceId); + buf.append("] "); + } + } + // Append the name of the impl instance if so configured if (CONFIG_PARAMS.showShortLogName) { if (shortLogName == null) { diff --git a/src/main/java/org/slf4j/impl/SimpleLoggerConfiguration.java b/src/main/java/org/slf4j/impl/SimpleLoggerConfiguration.java index 1119613..e3f8136 100755 --- a/src/main/java/org/slf4j/impl/SimpleLoggerConfiguration.java +++ b/src/main/java/org/slf4j/impl/SimpleLoggerConfiguration.java @@ -38,6 +38,7 @@ public class SimpleLoggerConfiguration { boolean showDateTime = true; boolean showConsole = true; boolean disableColor = false; + boolean openTraceId = false; int defaultLogLevel = SimpleLogger.LOG_LEVEL_INFO; FileRunner fileRunner; @@ -56,6 +57,7 @@ void init() { this.showThreadName = getBoolProp(Constant.SHOW_THREAD_NAME_KEY, showThreadName); this.showConsole = getBoolProp(Constant.SHOW_CONSOLE_KEY, showConsole); this.disableColor = getBoolProp(Constant.DISABLE_COLOR, disableColor); + this.openTraceId = getBoolProp(OPEN_TRACE_ID,openTraceId); String dateTimeFormatStr = getStringProp(Constant.DATE_TIME_FORMAT_KEY, DATE_TIME_FORMAT_STR_DEFAULT); this.levelInBrackets = getBoolProp(Constant.LEVEL_IN_BRACKETS_KEY, levelInBrackets); diff --git a/src/test/java/com/blade/log/LoggerTest.java b/src/test/java/com/blade/log/LoggerTest.java index 5a5b1dd..d040074 100644 --- a/src/test/java/com/blade/log/LoggerTest.java +++ b/src/test/java/com/blade/log/LoggerTest.java @@ -2,7 +2,12 @@ import lombok.extern.slf4j.Slf4j; import org.junit.Test; +import org.slf4j.impl.MDC; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; /** @@ -40,4 +45,42 @@ public void testError() { } } + + @Test + public void testMDCLog() throws InterruptedException { + + ExecutorService executorService = Executors.newFixedThreadPool(3); + executorService.execute(this::testMDCLogAsync); + executorService.execute(this::testMDCLogAsync); + TimeUnit.SECONDS.sleep(10); + System.out.println("over"); + } + + private void testMDCLogAsync() { + try { + + log.info("Hello World"); + MDC.put("traceId", UUID.randomUUID().toString()); + + new Thread(() -> { + log.info("Thread ,test traceId"); + }).start(); + + Executors.newFixedThreadPool(1).execute(() -> { + log.info("newFixedThreadPool,test traceId"); + }); + + CompletableFuture.runAsync(() -> { + log.info("CompletableFuture ,test traceId"); + }).join(); + + TimeUnit.SECONDS.sleep(5); + MDC.clear(); + log.info("Hello World"); + } catch (Exception e) { + log.error("eee", e); + } + + + } } diff --git a/src/test/resources/application-test.properties b/src/test/resources/application-test.properties index 6222303..84c4de2 100644 --- a/src/test/resources/application-test.properties +++ b/src/test/resources/application-test.properties @@ -1,4 +1,5 @@ com.blade.logger.rootLevel=error com.blade.logger.dir=./logs com.blade.logger.name=app -com.blade.logger.console=false \ No newline at end of file +com.blade.logger.console=false +logger.open-trace-id=true \ No newline at end of file diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties index dc22039..792750a 100644 --- a/src/test/resources/application.properties +++ b/src/test/resources/application.properties @@ -1,4 +1,5 @@ logger.root-level=debug logger.dir=./logs logger.name=app -logger.console=true \ No newline at end of file +logger.console=true +logger.open-trace-id = true \ No newline at end of file