From 9c3be2e14d3c414a8d77906f9f89f6f59e67e295 Mon Sep 17 00:00:00 2001 From: Nick Wemekamp Date: Thu, 2 Jul 2020 15:52:35 +0200 Subject: [PATCH 1/6] Add SLF4J MDC support for JUL --- jul-ecs-formatter/pom.xml | 13 ++- .../co/elastic/logging/jul/EcsFormatter.java | 2 + .../co/elastic/logging/jul/MdcSupplier.java | 82 +++++++++++++++++++ ...ggingTestTest.java => JulLoggingTest.java} | 11 ++- 4 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 jul-ecs-formatter/src/main/java/co/elastic/logging/jul/MdcSupplier.java rename jul-ecs-formatter/src/test/java/co/elastic/logging/jul/{JulLoggingTestTest.java => JulLoggingTest.java} (95%) diff --git a/jul-ecs-formatter/pom.xml b/jul-ecs-formatter/pom.xml index de993cfd..dd4db6ba 100644 --- a/jul-ecs-formatter/pom.xml +++ b/jul-ecs-formatter/pom.xml @@ -27,6 +27,17 @@ test-jar test + + org.slf4j + slf4j-api + 1.7.30 + true + + + org.slf4j + slf4j-jdk14 + 1.7.30 + true + - \ No newline at end of file diff --git a/jul-ecs-formatter/src/main/java/co/elastic/logging/jul/EcsFormatter.java b/jul-ecs-formatter/src/main/java/co/elastic/logging/jul/EcsFormatter.java index 9964e834..940c5a54 100644 --- a/jul-ecs-formatter/src/main/java/co/elastic/logging/jul/EcsFormatter.java +++ b/jul-ecs-formatter/src/main/java/co/elastic/logging/jul/EcsFormatter.java @@ -33,6 +33,7 @@ public class EcsFormatter extends Formatter { private static final String UNKNOWN_FILE = ""; + private static final MdcSupplier mdcSupplier = MdcSupplier.Resolver.INSTANCE.resolve(); private boolean stackTraceAsArray; private String serviceName; @@ -57,6 +58,7 @@ public String format(final LogRecord record) { EcsJsonSerializer.serializeObjectStart(builder, record.getMillis()); EcsJsonSerializer.serializeLogLevel(builder, record.getLevel().getName()); EcsJsonSerializer.serializeFormattedMessage(builder, super.formatMessage(record)); + EcsJsonSerializer.serializeMDC(builder, mdcSupplier.getMDC()); EcsJsonSerializer.serializeServiceName(builder, serviceName); EcsJsonSerializer.serializeEventDataset(builder, eventDataset); EcsJsonSerializer.serializeThreadId(builder, record.getThreadID()); diff --git a/jul-ecs-formatter/src/main/java/co/elastic/logging/jul/MdcSupplier.java b/jul-ecs-formatter/src/main/java/co/elastic/logging/jul/MdcSupplier.java new file mode 100644 index 00000000..b0f8cbcd --- /dev/null +++ b/jul-ecs-formatter/src/main/java/co/elastic/logging/jul/MdcSupplier.java @@ -0,0 +1,82 @@ +/*- + * #%L + * Java ECS logging + * %% + * Copyright (C) 2019 - 2020 Elastic and contributors + * %% + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * #L% + */ +package co.elastic.logging.jul; + +import org.slf4j.MDC; + +import java.util.HashMap; +import java.util.Map; + +public interface MdcSupplier { + Map getMDC(); + + enum Resolver { + INSTANCE; + + MdcSupplier resolve() { + try { + Class.forName("org.slf4j.MDC"); + + // The SLF4J API dependency does not contain an MDC binder by itself, the MDC binders come from an SLF4j + // implementation. When no MDC bindings are available calls to MDC.put will be ignored by slf4j. + // That is why we want to ensure that the StaticMDCBinder exists + Class.forName("org.slf4j.impl.StaticMDCBinder"); + return Available.INSTANCE; + } catch (Exception e) { + return Unavailable.INSTANCE; + } catch (LinkageError e ) { + return Unavailable.INSTANCE; + } + } + } + + enum Available implements MdcSupplier { + INSTANCE; + + Available() { + } + + @Override + public Map getMDC() { + Map copyOfContextMap = MDC.getCopyOfContextMap(); + if (copyOfContextMap != null ) { + return copyOfContextMap; + } + return new HashMap(); + } + } + + enum Unavailable implements MdcSupplier { + INSTANCE; + + Unavailable() { + } + + @Override + public Map getMDC() { + return new HashMap(); + } + } +} diff --git a/jul-ecs-formatter/src/test/java/co/elastic/logging/jul/JulLoggingTestTest.java b/jul-ecs-formatter/src/test/java/co/elastic/logging/jul/JulLoggingTest.java similarity index 95% rename from jul-ecs-formatter/src/test/java/co/elastic/logging/jul/JulLoggingTestTest.java rename to jul-ecs-formatter/src/test/java/co/elastic/logging/jul/JulLoggingTest.java index 41a6ff4b..0f7e1de2 100644 --- a/jul-ecs-formatter/src/test/java/co/elastic/logging/jul/JulLoggingTestTest.java +++ b/jul-ecs-formatter/src/test/java/co/elastic/logging/jul/JulLoggingTest.java @@ -48,8 +48,9 @@ import com.fasterxml.jackson.databind.JsonNode; import co.elastic.logging.AbstractEcsLoggingTest; +import org.slf4j.MDC; -public class JulLoggingTestTest extends AbstractEcsLoggingTest { +public class JulLoggingTest extends AbstractEcsLoggingTest { private static final class InMemoryStreamHandler extends StreamHandler { private InMemoryStreamHandler(OutputStream out, Formatter formatter) { @@ -86,6 +87,12 @@ public void debug(String message) { logger.log(Level.FINE, message); } + @Override + public boolean putMdc(String key, String value) { + MDC.put(key, value); + return true; + } + @Override public ParameterizedLogSupport getParameterizedLogSettings() { return ParameterizedLogSupport.NUMBER_AND_BRACKETS; @@ -131,7 +138,7 @@ void testLogException() throws Exception { String stackTrace = StreamSupport.stream(getLastLogLine().get("error.stack_trace").spliterator(), false) .map(JsonNode::textValue) .collect(Collectors.joining("\n", "", "\n")); - assertThat(stackTrace).contains("at co.elastic.logging.jul.JulLoggingTestTest.testLogException"); + assertThat(stackTrace).contains("at co.elastic.logging.jul.JulLoggingTest.testLogException"); } @Test From bf4b196cbafe137dbe099a023a83e848dd837b73 Mon Sep 17 00:00:00 2001 From: Nick Wemekamp Date: Thu, 2 Jul 2020 15:54:58 +0200 Subject: [PATCH 2/6] Remove unneeded constructor --- .../src/main/java/co/elastic/logging/jul/MdcSupplier.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/jul-ecs-formatter/src/main/java/co/elastic/logging/jul/MdcSupplier.java b/jul-ecs-formatter/src/main/java/co/elastic/logging/jul/MdcSupplier.java index b0f8cbcd..4e088c2f 100644 --- a/jul-ecs-formatter/src/main/java/co/elastic/logging/jul/MdcSupplier.java +++ b/jul-ecs-formatter/src/main/java/co/elastic/logging/jul/MdcSupplier.java @@ -55,9 +55,6 @@ MdcSupplier resolve() { enum Available implements MdcSupplier { INSTANCE; - Available() { - } - @Override public Map getMDC() { Map copyOfContextMap = MDC.getCopyOfContextMap(); From 88e837e4571cc5fb3a0f545a650d760ba9a599c1 Mon Sep 17 00:00:00 2001 From: Nick Wemekamp Date: Thu, 2 Jul 2020 17:28:27 +0200 Subject: [PATCH 3/6] Use Collections.emptyMap() instead of new HashMap() --- .../src/main/java/co/elastic/logging/jul/MdcSupplier.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jul-ecs-formatter/src/main/java/co/elastic/logging/jul/MdcSupplier.java b/jul-ecs-formatter/src/main/java/co/elastic/logging/jul/MdcSupplier.java index 4e088c2f..d9683b91 100644 --- a/jul-ecs-formatter/src/main/java/co/elastic/logging/jul/MdcSupplier.java +++ b/jul-ecs-formatter/src/main/java/co/elastic/logging/jul/MdcSupplier.java @@ -26,7 +26,7 @@ import org.slf4j.MDC; -import java.util.HashMap; +import java.util.Collections; import java.util.Map; public interface MdcSupplier { @@ -61,7 +61,7 @@ public Map getMDC() { if (copyOfContextMap != null ) { return copyOfContextMap; } - return new HashMap(); + return Collections.emptyMap(); } } @@ -73,7 +73,7 @@ enum Unavailable implements MdcSupplier { @Override public Map getMDC() { - return new HashMap(); + return Collections.emptyMap(); } } } From 84fd627175239277b486eee3586f8f337f7de04c Mon Sep 17 00:00:00 2001 From: Nick Wemekamp Date: Thu, 2 Jul 2020 17:34:51 +0200 Subject: [PATCH 4/6] Refer to Available.INSTANCE with Class.forname so as to prevent loading MDC in some JVM implementations. --- .../src/main/java/co/elastic/logging/jul/MdcSupplier.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jul-ecs-formatter/src/main/java/co/elastic/logging/jul/MdcSupplier.java b/jul-ecs-formatter/src/main/java/co/elastic/logging/jul/MdcSupplier.java index d9683b91..a6ee91c3 100644 --- a/jul-ecs-formatter/src/main/java/co/elastic/logging/jul/MdcSupplier.java +++ b/jul-ecs-formatter/src/main/java/co/elastic/logging/jul/MdcSupplier.java @@ -43,7 +43,7 @@ MdcSupplier resolve() { // implementation. When no MDC bindings are available calls to MDC.put will be ignored by slf4j. // That is why we want to ensure that the StaticMDCBinder exists Class.forName("org.slf4j.impl.StaticMDCBinder"); - return Available.INSTANCE; + return (MdcSupplier) Class.forName("co.elastic.logging.jul.MdcSupplier$Available").getEnumConstants()[0]; } catch (Exception e) { return Unavailable.INSTANCE; } catch (LinkageError e ) { From 60d8c9ed73a838b0a6151a788bed5b7ea616bf96 Mon Sep 17 00:00:00 2001 From: Nick Wemekamp Date: Thu, 2 Jul 2020 19:01:15 +0200 Subject: [PATCH 5/6] Slf4j jdk 14 dependency is only needed for unittests. --- jul-ecs-formatter/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/jul-ecs-formatter/pom.xml b/jul-ecs-formatter/pom.xml index dd4db6ba..9c2a4cbf 100644 --- a/jul-ecs-formatter/pom.xml +++ b/jul-ecs-formatter/pom.xml @@ -38,6 +38,7 @@ slf4j-jdk14 1.7.30 true + test \ No newline at end of file From a6fb6906dc151ad5d1a5d0d097e0f153d5dd9452 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Fri, 3 Jul 2020 15:03:20 +0200 Subject: [PATCH 6/6] No need to mark test dependency as optional --- jul-ecs-formatter/pom.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/jul-ecs-formatter/pom.xml b/jul-ecs-formatter/pom.xml index 9c2a4cbf..b5865ce9 100644 --- a/jul-ecs-formatter/pom.xml +++ b/jul-ecs-formatter/pom.xml @@ -37,8 +37,7 @@ org.slf4j slf4j-jdk14 1.7.30 - true test - \ No newline at end of file +