Skip to content

Commit 54be9db

Browse files
authored
Implement fallback MDC implementation for JUL (#190)
Add fallback MDC for JUL
1 parent 2526531 commit 54be9db

File tree

12 files changed

+165
-116
lines changed

12 files changed

+165
-116
lines changed

ecs-logging-core/src/test/java/co/elastic/logging/AbstractEcsLoggingTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ void testThreadContext() throws Exception {
171171

172172
@Test
173173
void testThreadContextStack() throws Exception {
174-
if (putNdc("foo")) {
174+
if (putMdc("foo")) {
175175
debug("test");
176176
assertThat(getAndValidateLastLogLine().get("tags").iterator().next().textValue()).isEqualTo("foo");
177177
}
@@ -223,7 +223,7 @@ public boolean putMdc(String key, String value) {
223223
return false;
224224
}
225225

226-
public boolean putNdc(String message) {
226+
public boolean putMdc(String message) {
227227
return false;
228228
}
229229

jboss-logmanager-ecs-formatter/src/test/java/co/elastic/logging/jboss/logmanager/JBossLogManagerTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public boolean putMdc(String key, String value) {
5555
}
5656

5757
@Override
58-
public boolean putNdc(String message) {
58+
public boolean putMdc(String message) {
5959
NDC.push(message);
6060
return true;
6161
}

jul-ecs-formatter/pom.xml

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,5 @@
2727
<type>test-jar</type>
2828
<scope>test</scope>
2929
</dependency>
30-
<dependency>
31-
<groupId>org.slf4j</groupId>
32-
<artifactId>slf4j-api</artifactId>
33-
<version>1.7.30</version>
34-
<optional>true</optional>
35-
</dependency>
36-
<dependency>
37-
<groupId>org.slf4j</groupId>
38-
<artifactId>slf4j-jdk14</artifactId>
39-
<version>1.7.30</version>
40-
<scope>test</scope>
41-
</dependency>
4230
</dependencies>
4331
</project>

jul-ecs-formatter/src/main/java/co/elastic/logging/jul/EcsFormatter.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
* the Apache License, Version 2.0 (the "License"); you may
1212
* not use this file except in compliance with the License.
1313
* You may obtain a copy of the License at
14-
*
14+
*
1515
* http://www.apache.org/licenses/LICENSE-2.0
16-
*
16+
*
1717
* Unless required by applicable law or agreed to in writing,
1818
* software distributed under the License is distributed on an
1919
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -24,20 +24,19 @@
2424
*/
2525
package co.elastic.logging.jul;
2626

27+
import co.elastic.logging.AdditionalField;
28+
import co.elastic.logging.EcsJsonSerializer;
29+
2730
import java.util.Collections;
2831
import java.util.List;
2932
import java.util.logging.Formatter;
3033
import java.util.logging.LogManager;
3134
import java.util.logging.LogRecord;
3235

33-
import co.elastic.logging.AdditionalField;
34-
import co.elastic.logging.EcsJsonSerializer;
35-
3636
public class EcsFormatter extends Formatter {
3737

3838
private static final String UNKNOWN_FILE = "<Unknown>";
39-
private static final MdcSupplier mdcSupplier = MdcSupplier.Resolver.INSTANCE.resolve();
40-
39+
4140
private boolean stackTraceAsArray;
4241
private String serviceName;
4342
private String serviceVersion;
@@ -52,8 +51,8 @@ public class EcsFormatter extends Formatter {
5251
*/
5352
public EcsFormatter() {
5453
serviceName = getProperty("co.elastic.logging.jul.EcsFormatter.serviceName", null);
55-
serviceVersion= getProperty("co.elastic.logging.jul.EcsFormatter.serviceVersion", null);
56-
serviceEnvironment= getProperty("co.elastic.logging.jul.EcsFormatter.serviceEnvironment", null);
54+
serviceVersion = getProperty("co.elastic.logging.jul.EcsFormatter.serviceVersion", null);
55+
serviceEnvironment = getProperty("co.elastic.logging.jul.EcsFormatter.serviceEnvironment", null);
5756
serviceNodeName = getProperty("co.elastic.logging.jul.EcsFormatter.serviceNodeName", null);
5857
includeOrigin = Boolean.parseBoolean(getProperty("co.elastic.logging.jul.EcsFormatter.includeOrigin", "false"));
5958
stackTraceAsArray = Boolean.parseBoolean(getProperty("co.elastic.logging.jul.EcsFormatter.stackTraceAsArray", "false"));
@@ -70,7 +69,7 @@ public String format(final LogRecord record) {
7069
EcsJsonSerializer.serializeFormattedMessage(builder, super.formatMessage(record));
7170
EcsJsonSerializer.serializeEcsVersion(builder);
7271
EcsJsonSerializer.serializeAdditionalFields(builder, additionalFields);
73-
EcsJsonSerializer.serializeMDC(builder, mdcSupplier.getMDC());
72+
EcsJsonSerializer.serializeMDC(builder, JulMdc.getEntries());
7473
EcsJsonSerializer.serializeServiceName(builder, serviceName);
7574
EcsJsonSerializer.serializeServiceVersion(builder, serviceVersion);
7675
EcsJsonSerializer.serializeServiceEnvironment(builder, serviceEnvironment);
@@ -116,7 +115,7 @@ public void setServiceNodeName(final String serviceNodeName) {
116115
public void setStackTraceAsArray(final boolean stackTraceAsArray) {
117116
this.stackTraceAsArray = stackTraceAsArray;
118117
}
119-
118+
120119
public void setEventDataset(String eventDataset) {
121120
this.eventDataset = eventDataset;
122121
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*-
2+
* #%L
3+
* Java ECS logging
4+
* %%
5+
* Copyright (C) 2019 - 2022 Elastic and contributors
6+
* %%
7+
* Licensed to Elasticsearch B.V. under one or more contributor
8+
* license agreements. See the NOTICE file distributed with
9+
* this work for additional information regarding copyright
10+
* ownership. Elasticsearch B.V. licenses this file to you under
11+
* the Apache License, Version 2.0 (the "License"); you may
12+
* not use this file except in compliance with the License.
13+
* You may obtain a copy of the License at
14+
*
15+
* http://www.apache.org/licenses/LICENSE-2.0
16+
*
17+
* Unless required by applicable law or agreed to in writing,
18+
* software distributed under the License is distributed on an
19+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20+
* KIND, either express or implied. See the License for the
21+
* specific language governing permissions and limitations
22+
* under the License.
23+
* #L%
24+
*/
25+
package co.elastic.logging.jul;
26+
27+
import java.util.Collections;
28+
import java.util.HashMap;
29+
import java.util.Map;
30+
31+
/**
32+
* MDC implementation for JUL as it does not have one.
33+
* This MDC will be used by the APM agent for logs correlation.
34+
*/
35+
public class JulMdc {
36+
37+
/**
38+
* This MDC is currently used with 3 key/values: trace,transaction and error IDs.
39+
*/
40+
private static final int INITIAL_CAPACITY = 4;
41+
42+
private static final ThreadLocal<Map<String, String>> tlm = new ThreadLocal<Map<String, String>>();
43+
44+
public static void put(String key, String value) {
45+
Map<String, String> map = tlm.get();
46+
if (map == null) {
47+
map = new HashMap<String, String>(INITIAL_CAPACITY);
48+
tlm.set(map);
49+
}
50+
map.put(key, value);
51+
}
52+
53+
public static void remove(String key) {
54+
Map<String, String> entries = tlm.get();
55+
if (entries != null) {
56+
entries.remove(key);
57+
}
58+
}
59+
60+
/**
61+
* Get the MDC entries, the returned map should not escape the current thread as the map implementation is not
62+
* thread-safe and thus concurrent modification is not supported.
63+
*
64+
* @return map of MDC entries
65+
*/
66+
static Map<String, String> getEntries() {
67+
Map<String, String> entries = tlm.get();
68+
return entries == null ? Collections.<String, String>emptyMap() : entries;
69+
}
70+
71+
}

jul-ecs-formatter/src/main/java/co/elastic/logging/jul/MdcSupplier.java

Lines changed: 0 additions & 79 deletions
This file was deleted.

jul-ecs-formatter/src/test/java/co/elastic/logging/jul/JulLoggingTest.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
* the Apache License, Version 2.0 (the "License"); you may
1212
* not use this file except in compliance with the License.
1313
* You may obtain a copy of the License at
14-
*
14+
*
1515
* http://www.apache.org/licenses/LICENSE-2.0
16-
*
16+
*
1717
* Unless required by applicable law or agreed to in writing,
1818
* software distributed under the License is distributed on an
1919
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -30,7 +30,6 @@
3030
import com.fasterxml.jackson.databind.JsonNode;
3131
import org.junit.jupiter.api.BeforeEach;
3232
import org.junit.jupiter.api.Test;
33-
import org.slf4j.MDC;
3433

3534
import java.io.ByteArrayOutputStream;
3635
import java.io.IOException;
@@ -71,9 +70,9 @@ public void publish(LogRecord record) {
7170
}
7271

7372
private EcsFormatter formatter;
74-
73+
7574
private final Logger logger = Logger.getLogger("");
76-
75+
7776
private final ByteArrayOutputStream out = new ByteArrayOutputStream();
7877

7978
private LogRecord record;
@@ -85,7 +84,7 @@ public void debug(String message) {
8584

8685
@Override
8786
public boolean putMdc(String key, String value) {
88-
MDC.put(key, value);
87+
JulMdc.put(key, value);
8988
return true;
9089
}
9190

@@ -103,7 +102,7 @@ public void debug(String message, Object... logParams) {
103102
public void error(String message, Throwable t) {
104103
logger.log(Level.SEVERE, message, t);
105104
}
106-
105+
107106
@Override
108107
public JsonNode getLastLogLine() throws IOException {
109108
return objectMapper.readTree(out.toString());
@@ -153,7 +152,7 @@ void testAdditionalFieldsAsList() throws Exception {
153152
formatter.setAdditionalFields(List.of(new AdditionalField("key1", "value1"), new AdditionalField("key2", "value2")));
154153
super.testAdditionalFields();
155154
}
156-
155+
157156
private void clearHandlers() {
158157
for (Handler handler : logger.getHandlers()) {
159158
logger.removeHandler(handler);
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*-
2+
* #%L
3+
* Java ECS logging
4+
* %%
5+
* Copyright (C) 2019 - 2022 Elastic and contributors
6+
* %%
7+
* Licensed to Elasticsearch B.V. under one or more contributor
8+
* license agreements. See the NOTICE file distributed with
9+
* this work for additional information regarding copyright
10+
* ownership. Elasticsearch B.V. licenses this file to you under
11+
* the Apache License, Version 2.0 (the "License"); you may
12+
* not use this file except in compliance with the License.
13+
* You may obtain a copy of the License at
14+
*
15+
* http://www.apache.org/licenses/LICENSE-2.0
16+
*
17+
* Unless required by applicable law or agreed to in writing,
18+
* software distributed under the License is distributed on an
19+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20+
* KIND, either express or implied. See the License for the
21+
* specific language governing permissions and limitations
22+
* under the License.
23+
* #L%
24+
*/
25+
package co.elastic.logging.jul;
26+
27+
import org.junit.jupiter.api.AfterEach;
28+
import org.junit.jupiter.api.BeforeEach;
29+
import org.junit.jupiter.api.Test;
30+
31+
import java.util.Map;
32+
33+
import static org.assertj.core.api.Assertions.assertThat;
34+
35+
public class JulMdcTest {
36+
37+
@BeforeEach
38+
void before(){
39+
// prevently empty if any other test have left something
40+
JulMdc.getEntries().clear();
41+
}
42+
43+
@AfterEach
44+
void after() {
45+
JulMdc.getEntries().clear();
46+
assertThat(JulMdc.getEntries()).isEmpty();
47+
}
48+
49+
@Test
50+
void emptyMdc() {
51+
Map<String, String> entries = JulMdc.getEntries();
52+
assertThat(entries).isEmpty();
53+
54+
assertThat(JulMdc.getEntries()).isSameAs(entries);
55+
56+
// should be a no-op
57+
JulMdc.remove("missing");
58+
}
59+
60+
@Test
61+
void putRemoveSingleEntry() {
62+
JulMdc.put("hello", "world");
63+
assertThat(JulMdc.getEntries()).containsEntry("hello", "world");
64+
65+
JulMdc.remove("hello");
66+
assertThat(JulMdc.getEntries()).isEmpty();
67+
}
68+
69+
}

0 commit comments

Comments
 (0)