You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rp...@apache.org on 2016/05/24 16:21:07 UTC
[2/2] logging-log4j2 git commit: LOG4J2-623,
LOG4J2-1362: fixed format of ThreadContext map to be a "natural"
JSON/YAML map,
instead of a list of map entries where each entry has a "key" attribute with
the key value and a "value" attribute with the value
LOG4J2-623, LOG4J2-1362: fixed format of ThreadContext map to be a "natural" JSON/YAML map, instead of a list of map entries where each entry has a "key" attribute with the key value and a "value" attribute with the value value
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/10316c39
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/10316c39
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/10316c39
Branch: refs/heads/master
Commit: 10316c393a3912d7e0e0717c177b720aec96cd1d
Parents: 42a7154
Author: rpopma <rp...@apache.org>
Authored: Wed May 25 01:21:45 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Wed May 25 01:21:45 2016 +0900
----------------------------------------------------------------------
.../log4j/core/jackson/Initializers.java | 20 +++
.../log4j/core/jackson/Log4jJsonModule.java | 10 +-
.../core/jackson/Log4jJsonObjectMapper.java | 9 +-
.../log4j/core/jackson/Log4jYamlModule.java | 10 +-
.../core/jackson/Log4jYamlObjectMapper.java | 9 +-
.../log4j/core/jackson/LogEventJsonMixIn.java | 140 +++++++++++++++++++
.../log4j/core/layout/JacksonFactory.java | 12 +-
.../logging/log4j/core/layout/JsonLayout.java | 15 +-
.../server/JsonInputStreamLogEventBridge.java | 6 +-
.../log4j/core/jackson/LevelMixInJsonTest.java | 2 +-
.../jackson/StackTraceElementMixInTest.java | 3 +-
.../log4j/core/layout/JsonLayoutTest.java | 52 ++++---
.../log4j/core/layout/YamlLayoutTest.java | 13 +-
.../net/server/AbstractSocketServerTest.java | 12 +-
src/changes/changes.xml | 6 +
src/site/xdoc/manual/layouts.xml.vm | 7 +
16 files changed, 279 insertions(+), 47 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/10316c39/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Initializers.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Initializers.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Initializers.java
index f6cc708..d0cbe2d 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Initializers.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Initializers.java
@@ -53,6 +53,26 @@ class Initializers {
}
/**
+ * Used to set up {@link SetupContext} from different {@link SimpleModule}s.
+ * Differs from SetupContextInitializer by installing {@code LogEventJsonMixIn} for LogEvents,
+ * not {@code LogEventMixIn}, so it handles ThreadContext serialization differently.
+ */
+ static class SetupContextJsonInitializer {
+
+ void setupModule(final SetupContext context) {
+ // JRE classes: we cannot edit those with Jackson annotations
+ context.setMixInAnnotations(StackTraceElement.class, StackTraceElementMixIn.class);
+ // Log4j API classes: we do not want to edit those with Jackson annotations because the API module should not depend on Jackson.
+ context.setMixInAnnotations(Marker.class, MarkerMixIn.class);
+ context.setMixInAnnotations(Level.class, LevelMixIn.class);
+ context.setMixInAnnotations(LogEvent.class, LogEventJsonMixIn.class); // different ThreadContext handling
+ // Log4j Core classes: we do not want to bring in Jackson at runtime if we do not have to.
+ context.setMixInAnnotations(ExtendedStackTraceElement.class, ExtendedStackTraceElementMixIn.class);
+ context.setMixInAnnotations(ThrowableProxy.class, ThrowableProxyMixIn.class);
+ }
+ }
+
+ /**
* Used to set up {@link SimpleModule} from different {@link SimpleModule} subclasses.
*/
static class SimpleModuleInitializer {
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/10316c39/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jJsonModule.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jJsonModule.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jJsonModule.java
index 1525fad..87f7eb6 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jJsonModule.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jJsonModule.java
@@ -30,9 +30,11 @@ import com.fasterxml.jackson.databind.module.SimpleModule;
class Log4jJsonModule extends SimpleModule {
private static final long serialVersionUID = 1L;
+ private final boolean encodeThreadContextAsList;
- Log4jJsonModule() {
+ Log4jJsonModule(final boolean encodeThreadContextAsList) {
super(Log4jJsonModule.class.getName(), new Version(2, 0, 0, null, null, null));
+ this.encodeThreadContextAsList = encodeThreadContextAsList;
// MUST init here.
// Calling this from setupModule is too late!
//noinspection ThisEscapedInObjectConstruction
@@ -43,6 +45,10 @@ class Log4jJsonModule extends SimpleModule {
public void setupModule(final SetupContext context) {
// Calling super is a MUST!
super.setupModule(context);
- new SetupContextInitializer().setupModule(context);
+ if (encodeThreadContextAsList) {
+ new SetupContextInitializer().setupModule(context);
+ } else {
+ new Initializers.SetupContextJsonInitializer().setupModule(context);
+ }
}
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/10316c39/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jJsonObjectMapper.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jJsonObjectMapper.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jJsonObjectMapper.java
index 3e2f0da..ebb8dbd 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jJsonObjectMapper.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jJsonObjectMapper.java
@@ -33,7 +33,14 @@ public class Log4jJsonObjectMapper extends ObjectMapper {
* Create a new instance using the {@link Log4jJsonModule}.
*/
public Log4jJsonObjectMapper() {
- this.registerModule(new Log4jJsonModule());
+ this(false);
+ }
+
+ /**
+ * Create a new instance using the {@link Log4jJsonModule}.
+ */
+ public Log4jJsonObjectMapper(final boolean encodeThreadContextAsList) {
+ this.registerModule(new Log4jJsonModule(encodeThreadContextAsList));
this.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/10316c39/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jYamlModule.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jYamlModule.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jYamlModule.java
index 4052320..106942f 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jYamlModule.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jYamlModule.java
@@ -30,9 +30,11 @@ import com.fasterxml.jackson.databind.module.SimpleModule;
final class Log4jYamlModule extends SimpleModule {
private static final long serialVersionUID = 1L;
+ private final boolean encodeThreadContextAsList;
- Log4jYamlModule() {
+ Log4jYamlModule(final boolean encodeThreadContextAsList) {
super(Log4jYamlModule.class.getName(), new Version(2, 0, 0, null, null, null));
+ this.encodeThreadContextAsList = encodeThreadContextAsList;
// MUST init here.
// Calling this from setupModule is too late!
//noinspection ThisEscapedInObjectConstruction
@@ -43,6 +45,10 @@ final class Log4jYamlModule extends SimpleModule {
public void setupModule(final SetupContext context) {
// Calling super is a MUST!
super.setupModule(context);
- new SetupContextInitializer().setupModule(context);
+ if (encodeThreadContextAsList) {
+ new SetupContextInitializer().setupModule(context);
+ } else {
+ new Initializers.SetupContextJsonInitializer().setupModule(context);
+ }
}
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/10316c39/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jYamlObjectMapper.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jYamlObjectMapper.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jYamlObjectMapper.java
index 9ab787a..2e6ce1a 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jYamlObjectMapper.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jYamlObjectMapper.java
@@ -34,7 +34,14 @@ public class Log4jYamlObjectMapper extends YAMLMapper {
* Create a new instance using the {@link Log4jYamlModule}.
*/
public Log4jYamlObjectMapper() {
- this.registerModule(new Log4jYamlModule());
+ this(false);
+ }
+
+ /**
+ * Create a new instance using the {@link Log4jYamlModule}.
+ */
+ public Log4jYamlObjectMapper(final boolean encodeThreadContextAsList) {
+ this.registerModule(new Log4jYamlModule(encodeThreadContextAsList));
this.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/10316c39/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventJsonMixIn.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventJsonMixIn.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventJsonMixIn.java
new file mode 100644
index 0000000..717815d
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventJsonMixIn.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.
+ */
+package org.apache.logging.log4j.core.jackson;
+
+import java.util.Map;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.ThreadContext.ContextStack;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.impl.ThrowableProxy;
+import org.apache.logging.log4j.message.Message;
+
+import com.fasterxml.jackson.annotation.JsonFilter;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.annotation.JsonRootName;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.deser.std.MapDeserializer;
+import com.fasterxml.jackson.databind.ser.std.MapSerializer;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
+
+@JsonRootName(XmlConstants.ELT_EVENT)
+@JacksonXmlRootElement(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_EVENT)
+@JsonFilter("org.apache.logging.log4j.core.impl.Log4jLogEvent")
+@JsonPropertyOrder({ "timeMillis", "threadName", "level", "loggerName", "marker", "message", "thrown", XmlConstants.ELT_CONTEXT_MAP,
+ JsonConstants.ELT_CONTEXT_STACK, "loggerFQCN", "Source", "endOfBatch" })
+abstract class LogEventJsonMixIn implements LogEvent {
+
+ private static final long serialVersionUID = 1L;
+
+ @JsonProperty(JsonConstants.ELT_CONTEXT_MAP)
+ @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CONTEXT_MAP)
+// @JsonSerialize(using = MapSerializer.class)
+// @JsonDeserialize(using = MapDeserializer.class)
+ @Override
+ public abstract Map<String, String> getContextMap();
+
+ @JsonProperty(JsonConstants.ELT_CONTEXT_STACK)
+ @JacksonXmlElementWrapper(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CONTEXT_STACK)
+ @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CONTEXT_STACK_ITEM)
+ @Override
+ public abstract ContextStack getContextStack();
+
+ @JsonProperty()
+ @JacksonXmlProperty(isAttribute = true)
+ @Override
+ public abstract Level getLevel();
+
+ @JsonProperty()
+ @JacksonXmlProperty(isAttribute = true)
+ @Override
+ public abstract String getLoggerFqcn();
+
+ @JsonProperty()
+ @JacksonXmlProperty(isAttribute = true)
+ @Override
+ public abstract String getLoggerName();
+
+ @JsonProperty(JsonConstants.ELT_MARKER)
+ @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_MARKER)
+ @Override
+ public abstract Marker getMarker();
+
+ @JsonProperty(JsonConstants.ELT_MESSAGE)
+ @JsonSerialize(using = MessageSerializer.class)
+ @JsonDeserialize(using = SimpleMessageDeserializer.class)
+ @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_MESSAGE)
+ @Override
+ public abstract Message getMessage();
+
+ @JsonProperty(JsonConstants.ELT_SOURCE)
+ @JsonDeserialize(using = Log4jStackTraceElementDeserializer.class)
+ @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_SOURCE)
+ @Override
+ public abstract StackTraceElement getSource();
+
+ @Override
+ @JsonProperty("threadId")
+ @JacksonXmlProperty(isAttribute = true, localName = "threadId")
+ public abstract long getThreadId();
+
+ @Override
+ @JsonProperty("thread")
+ @JacksonXmlProperty(isAttribute = true, localName = "thread")
+ public abstract String getThreadName();
+
+ @Override
+ @JsonProperty("threadPriority")
+ @JacksonXmlProperty(isAttribute = true, localName = "threadPriority")
+ public abstract int getThreadPriority();
+
+ @JsonIgnore
+ @Override
+ public abstract Throwable getThrown();
+
+ @JsonProperty(JsonConstants.ELT_THROWN)
+ @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_THROWN)
+ @Override
+ public abstract ThrowableProxy getThrownProxy();
+
+ @JsonProperty()
+ @JacksonXmlProperty(isAttribute = true)
+ @Override
+ public abstract long getTimeMillis();
+
+ @JsonProperty()
+ @JacksonXmlProperty(isAttribute = true)
+ @Override
+ public abstract boolean isEndOfBatch();
+
+ @JsonIgnore
+ @Override
+ public abstract boolean isIncludeLocation();
+
+ @Override
+ public abstract void setEndOfBatch(boolean endOfBatch);
+
+ @Override
+ public abstract void setIncludeLocation(boolean locationRequired);
+
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/10316c39/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JacksonFactory.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JacksonFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JacksonFactory.java
index ea0877f..5869435 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JacksonFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JacksonFactory.java
@@ -42,6 +42,12 @@ abstract class JacksonFactory {
static class JSON extends JacksonFactory {
+ private final boolean encodeThreadContextAsList;
+
+ public JSON(final boolean encodeThreadContextAsList) {
+ this.encodeThreadContextAsList = encodeThreadContextAsList;
+ }
+
@Override
protected String getPropertNameForContextMap() {
return JsonConstants.ELT_CONTEXT_MAP;
@@ -64,7 +70,7 @@ abstract class JacksonFactory {
@Override
protected ObjectMapper newObjectMapper() {
- return new Log4jJsonObjectMapper();
+ return new Log4jJsonObjectMapper(encodeThreadContextAsList);
}
@Override
@@ -76,7 +82,7 @@ abstract class JacksonFactory {
static class XML extends JacksonFactory {
static final int DEFAULT_INDENT = 1;
-
+
@Override
protected String getPropertNameForContextMap() {
return XmlConstants.ELT_CONTEXT_MAP;
@@ -133,7 +139,7 @@ abstract class JacksonFactory {
@Override
protected ObjectMapper newObjectMapper() {
- return new Log4jYamlObjectMapper();
+ return new Log4jYamlObjectMapper(false);
}
@Override
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/10316c39/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JsonLayout.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JsonLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JsonLayout.java
index ff4bf0b..90074bc 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JsonLayout.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JsonLayout.java
@@ -808,10 +808,11 @@ public final class JsonLayout extends AbstractJacksonLayout {
static final String CONTENT_TYPE = "application/json";
protected JsonLayout(final Configuration config, final boolean locationInfo, final boolean properties,
+ final boolean encodeThreadContextAsList,
final boolean complete, final boolean compact, final boolean eventEol, final String headerPattern,
final String footerPattern, final Charset charset) {
- super(config, new JacksonFactory.JSON().newWriter(locationInfo, properties, compact), charset, compact,
- complete, eventEol,
+ super(config, new JacksonFactory.JSON(encodeThreadContextAsList).newWriter(locationInfo, properties, compact),
+ charset, compact, complete, eventEol,
PatternLayout.createSerializer(config, null, headerPattern, DEFAULT_HEADER, null, false, false),
PatternLayout.createSerializer(config, null, footerPattern, DEFAULT_FOOTER, null, false, false));
}
@@ -872,7 +873,7 @@ public final class JsonLayout extends AbstractJacksonLayout {
/**
* Creates a JSON Layout.
- * @param config
+ * @param config
* The plugin configuration.
* @param locationInfo
* If "true", includes the location information in the generated JSON.
@@ -899,6 +900,7 @@ public final class JsonLayout extends AbstractJacksonLayout {
@PluginConfiguration final Configuration config,
@PluginAttribute(value = "locationInfo", defaultBoolean = false) final boolean locationInfo,
@PluginAttribute(value = "properties", defaultBoolean = false) final boolean properties,
+ @PluginAttribute(value = "propertiesAsList", defaultBoolean = false) final boolean propertiesAsList,
@PluginAttribute(value = "complete", defaultBoolean = false) final boolean complete,
@PluginAttribute(value = "compact", defaultBoolean = false) final boolean compact,
@PluginAttribute(value = "eventEol", defaultBoolean = false) final boolean eventEol,
@@ -907,7 +909,9 @@ public final class JsonLayout extends AbstractJacksonLayout {
@PluginAttribute(value = "charset", defaultString = "UTF-8") final Charset charset
// @formatter:on
) {
- return new JsonLayout(config, locationInfo, properties, complete, compact, eventEol, headerPattern, footerPattern, charset);
+ final boolean encodeThreadContextAsList = properties && propertiesAsList;
+ return new JsonLayout(config, locationInfo, properties, encodeThreadContextAsList, complete, compact, eventEol,
+ headerPattern, footerPattern, charset);
}
/**
@@ -916,7 +920,8 @@ public final class JsonLayout extends AbstractJacksonLayout {
* @return A JSON Layout.
*/
public static JsonLayout createDefaultLayout() {
- return new JsonLayout(new DefaultConfiguration(), false, false, false, false, false, DEFAULT_HEADER, DEFAULT_FOOTER, StandardCharsets.UTF_8);
+ return new JsonLayout(new DefaultConfiguration(), false, false, false, false, false, false,
+ DEFAULT_HEADER, DEFAULT_FOOTER, StandardCharsets.UTF_8);
}
@Override
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/10316c39/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/JsonInputStreamLogEventBridge.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/JsonInputStreamLogEventBridge.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/JsonInputStreamLogEventBridge.java
index 8ed2732..cf89b5a 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/JsonInputStreamLogEventBridge.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/JsonInputStreamLogEventBridge.java
@@ -33,13 +33,15 @@ public class JsonInputStreamLogEventBridge extends InputStreamLogEventBridge {
private static final char EVENT_START_MARKER = '{';
private static final char JSON_ESC = '\\';
private static final char JSON_STR_DELIM = Chars.DQUOTE;
+ private static final boolean THREAD_CONTEXT_MAP_AS_LIST = false;
public JsonInputStreamLogEventBridge() {
this(1024, Charset.defaultCharset());
}
public JsonInputStreamLogEventBridge(final int bufferSize, final Charset charset) {
- super(new Log4jJsonObjectMapper(), bufferSize, charset, String.valueOf(EVENT_END_MARKER));
+ super(new Log4jJsonObjectMapper(THREAD_CONTEXT_MAP_AS_LIST), bufferSize, charset,
+ String.valueOf(EVENT_END_MARKER));
}
@Override
@@ -58,7 +60,7 @@ public class JsonInputStreamLogEventBridge extends InputStreamLogEventBridge {
if (inEsc) {
// Skip this char and continue
inEsc = false;
- } else {
+ } else {
switch (c) {
case EVENT_START_MARKER:
if (!inStr) {
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/10316c39/log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/LevelMixInJsonTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/LevelMixInJsonTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/LevelMixInJsonTest.java
index f2e63e5..da77aa0 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/LevelMixInJsonTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/LevelMixInJsonTest.java
@@ -23,7 +23,7 @@ public class LevelMixInJsonTest extends LevelMixInTest {
@Override
protected ObjectMapper newObjectMapper() {
- return new Log4jJsonObjectMapper();
+ return new Log4jJsonObjectMapper(false);
}
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/10316c39/log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/StackTraceElementMixInTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/StackTraceElementMixInTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/StackTraceElementMixInTest.java
index 5f3383b..3be145c 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/StackTraceElementMixInTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/StackTraceElementMixInTest.java
@@ -77,7 +77,8 @@ public class StackTraceElementMixInTest {
@Test
public void testFromJsonWithLog4jModule() throws Exception {
final ObjectMapper mapper = new ObjectMapper();
- final SimpleModule module = new Log4jJsonModule();
+ final boolean encodeThreadContextAsList = false;
+ final SimpleModule module = new Log4jJsonModule(encodeThreadContextAsList);
module.addDeserializer(StackTraceElement.class, new Log4jStackTraceElementDeserializer());
mapper.registerModule(module);
final StackTraceElement expected = new StackTraceElement("package.SomeClass", "someMethod", "SomeClass.java", 123);
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/10316c39/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/JsonLayoutTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/JsonLayoutTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/JsonLayoutTest.java
index 22b017f..55a22b9 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/JsonLayoutTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/JsonLayoutTest.java
@@ -84,11 +84,18 @@ public class JsonLayoutTest {
Assert.fail("Cannot find " + expected + " in " + list);
}
- private void checkMapEntry(final String key, final String value, final boolean compact, final String str) {
+ private void checkMapEntry(final String key, final String value, final boolean compact, final String str,
+ final boolean contextMapAslist) {
final String propSep = this.toPropertySeparator(compact);
- // "name":"value"
- final String expected = String.format("{\"key\":\"%s\",\"value\":\"%s\"}", key, value);
- assertTrue("Cannot find " + expected + " in " + str, str.contains(expected));
+ if (contextMapAslist) {
+ // {"key":"KEY", "value":"VALUE"}
+ final String expected = String.format("{\"key\":\"%s\",\"value\":\"%s\"}", key, value);
+ assertTrue("Cannot find contextMapAslist " + expected + " in " + str, str.contains(expected));
+ } else {
+ // "KEY":"VALUE"
+ final String expected = String.format("\"%s\":\"%s\"", key, value);
+ assertTrue("Cannot find contextMap " + expected + " in " + str, str.contains(expected));
+ }
}
private void checkProperty(final String key, final String value, final boolean compact, final String str) {
@@ -103,11 +110,12 @@ public class JsonLayoutTest {
assertTrue(str, str.contains(DQUOTE + name + DQUOTE + propSep));
}
- private void testAllFeatures(final boolean includeSource, final boolean compact, final boolean eventEol, final boolean includeContext)
+ private void testAllFeatures(final boolean includeSource, final boolean compact, final boolean eventEol,
+ final boolean includeContext, final boolean contextMapAslist)
throws Exception {
final Log4jLogEvent expected = LogEventFixtures.createLogEvent();
final AbstractJacksonLayout layout = JsonLayout.createLayout(null, includeSource,
- includeContext, false, compact, eventEol, null, null, StandardCharsets.UTF_8);
+ includeContext, contextMapAslist, false, compact, eventEol, null, null, StandardCharsets.UTF_8);
final String str = layout.toSerializable(expected);
// System.out.println(str);
final String propSep = this.toPropertySeparator(compact);
@@ -115,11 +123,11 @@ public class JsonLayoutTest {
assertEquals(str, !compact || eventEol, str.contains("\n"));
assertEquals(str, includeSource, str.contains("source"));
assertEquals(str, includeContext, str.contains("contextMap"));
- final Log4jLogEvent actual = new Log4jJsonObjectMapper().readValue(str, Log4jLogEvent.class);
+ final Log4jLogEvent actual = new Log4jJsonObjectMapper(contextMapAslist).readValue(str, Log4jLogEvent.class);
LogEventFixtures.assertEqualLogEvents(expected, actual, includeSource, includeContext);
if (includeContext) {
- this.checkMapEntry("MDC.A", "A_Value", compact, str);
- this.checkMapEntry("MDC.B", "B_Value", compact, str);
+ this.checkMapEntry("MDC.A", "A_Value", compact, str, contextMapAslist);
+ this.checkMapEntry("MDC.B", "B_Value", compact, str, contextMapAslist);
}
//
assertNull(actual.getThrown());
@@ -179,7 +187,9 @@ public class JsonLayoutTest {
}
final Configuration configuration = rootLogger.getContext().getConfiguration();
// set up appender
- final AbstractJacksonLayout layout = JsonLayout.createLayout(configuration, true, true, true, false, false, null, null, null);
+ final boolean propertiesAsList = false;
+ final AbstractJacksonLayout layout = JsonLayout.createLayout(configuration, true, true, propertiesAsList,
+ true, false, false, null, null, null);
final ListAppender appender = new ListAppender("List", null, layout, true, false);
appender.start();
@@ -216,7 +226,9 @@ public class JsonLayoutTest {
final Configuration configuration = rootLogger.getContext().getConfiguration();
// set up appender
// Use [[ and ]] to test header and footer (instead of [ and ])
- final AbstractJacksonLayout layout = JsonLayout.createLayout(configuration, true, true, true, false, false, "[[", "]]", null);
+ final boolean propertiesAsList = false;
+ final AbstractJacksonLayout layout = JsonLayout.createLayout(configuration, true, true, propertiesAsList,
+ true, false, false, "[[", "]]", null);
final ListAppender appender = new ListAppender("List", null, layout, true, false);
appender.start();
@@ -255,8 +267,9 @@ public class JsonLayoutTest {
@Test
public void testLayoutLoggerName() throws Exception {
- final AbstractJacksonLayout layout = JsonLayout.createLayout(null, false, false, false, true, false, null, null,
- StandardCharsets.UTF_8);
+ final boolean propertiesAsList = false;
+ final AbstractJacksonLayout layout = JsonLayout.createLayout(null, false, false, propertiesAsList,
+ false, true, false, null, null, StandardCharsets.UTF_8);
final Log4jLogEvent expected = Log4jLogEvent.newBuilder() //
.setLoggerName("a.B") //
.setLoggerFqcn("f.q.c.n") //
@@ -266,24 +279,29 @@ public class JsonLayoutTest {
.setTimeMillis(1).build();
final String str = layout.toSerializable(expected);
assertTrue(str, str.contains("\"loggerName\":\"a.B\""));
- final Log4jLogEvent actual = new Log4jJsonObjectMapper().readValue(str, Log4jLogEvent.class);
+ final Log4jLogEvent actual = new Log4jJsonObjectMapper(propertiesAsList).readValue(str, Log4jLogEvent.class);
assertEquals(expected.getLoggerName(), actual.getLoggerName());
assertEquals(expected, actual);
}
@Test
public void testLocationOffCompactOffMdcOff() throws Exception {
- this.testAllFeatures(false, false, false, false);
+ this.testAllFeatures(false, false, false, false, false);
}
@Test
public void testLocationOnCompactOnMdcOn() throws Exception {
- this.testAllFeatures(true, true, false, true);
+ this.testAllFeatures(true, true, false, true, false);
}
@Test
public void testLocationOnCompactOnEventEolOnMdcOn() throws Exception {
- this.testAllFeatures(true, true, true, true);
+ this.testAllFeatures(true, true, true, true, false);
+ }
+
+ @Test
+ public void testLocationOnCompactOnEventEolOnMdcOnMdcAsList() throws Exception {
+ this.testAllFeatures(true, true, true, true, true);
}
private String toPropertySeparator(final boolean compact) {
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/10316c39/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/YamlLayoutTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/YamlLayoutTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/YamlLayoutTest.java
index fd30bbd..ae588a2 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/YamlLayoutTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/YamlLayoutTest.java
@@ -88,7 +88,8 @@ public class YamlLayoutTest {
private void checkMapEntry(final String key, final String value, final boolean compact, final String str) {
final String propSep = this.toPropertySeparator(compact, true);
// "name":"value"
- final String expected = String.format("- key: \"%s\"\n value: \"%s\"", key, value);
+ //final String expected = String.format("- key: \"%s\"\n value: \"%s\"", key, value);
+ final String expected = String.format("%s: \"%s\"", key, value);
assertTrue("Cannot find " + expected + " in " + str, str.contains(expected));
}
@@ -106,7 +107,7 @@ public class YamlLayoutTest {
}
private void testAllFeatures(final boolean includeSource, final boolean compact, final boolean eventEol,
- final boolean includeContext) throws Exception {
+ final boolean includeContext, final boolean contextMapAslist) throws Exception {
final Log4jLogEvent expected = LogEventFixtures.createLogEvent();
final AbstractJacksonLayout layout = YamlLayout.createLayout(null, includeSource, includeContext, null, null,
StandardCharsets.UTF_8);
@@ -117,7 +118,7 @@ public class YamlLayoutTest {
assertEquals(str, !compact || eventEol, str.contains("\n"));
assertEquals(str, includeSource, str.contains("source"));
assertEquals(str, includeContext, str.contains("contextMap"));
- final Log4jLogEvent actual = new Log4jYamlObjectMapper().readValue(str, Log4jLogEvent.class);
+ final Log4jLogEvent actual = new Log4jYamlObjectMapper(contextMapAslist).readValue(str, Log4jLogEvent.class);
LogEventFixtures.assertEqualLogEvents(expected, actual, includeSource, includeContext);
if (includeContext) {
this.checkMapEntry("MDC.A", "A_Value", compact, str);
@@ -266,19 +267,19 @@ public class YamlLayoutTest {
.setTimeMillis(1).build();
final String str = layout.toSerializable(expected);
assertTrue(str, str.contains("loggerName: \"a.B\""));
- final Log4jLogEvent actual = new Log4jYamlObjectMapper().readValue(str, Log4jLogEvent.class);
+ final Log4jLogEvent actual = new Log4jYamlObjectMapper(false).readValue(str, Log4jLogEvent.class);
assertEquals(expected.getLoggerName(), actual.getLoggerName());
assertEquals(expected, actual);
}
@Test
public void testLocationOffCompactOffMdcOff() throws Exception {
- this.testAllFeatures(false, false, false, false);
+ this.testAllFeatures(false, false, false, false, false);
}
@Test
public void testLocationOnCompactOffEventEolOffMdcOn() throws Exception {
- this.testAllFeatures(true, false, false, true);
+ this.testAllFeatures(true, false, false, true, false);
}
private String toPropertySeparator(final boolean compact, final boolean value) {
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/10316c39/log4j-core/src/test/java/org/apache/logging/log4j/core/net/server/AbstractSocketServerTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/server/AbstractSocketServerTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/server/AbstractSocketServerTest.java
index ee5c2de..9000698 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/server/AbstractSocketServerTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/server/AbstractSocketServerTest.java
@@ -54,9 +54,9 @@ public abstract class AbstractSocketServerTest {
private static final String MESSAGE = "This is test message";
private static final String MESSAGE_2 = "This is test message 2";
-
+
private static final String MESSAGE_WITH_SPECIAL_CHARS = "{This}\n[is]\"n\"a\"\r\ntrue:\n\ttest,\nmessage";
-
+
static final int PORT_NUM = AvailablePortFinder.getNextAvailable();
static final int PORT = PORT_NUM;
@@ -78,7 +78,7 @@ public abstract class AbstractSocketServerTest {
}
protected Layout<String> createJsonLayout() {
- return JsonLayout.createLayout(null, true, true, false, false, false, null, null, null);
+ return JsonLayout.createLayout(null, true, true, false, false, false, false, null, null, null);
}
protected abstract Layout<? extends Serializable> createLayout();
@@ -145,13 +145,13 @@ public abstract class AbstractSocketServerTest {
testServer(m1, m2);
}
}
-
-
+
+
@Test
public void testMessagesWithSpecialChars() throws Exception {
testServer(MESSAGE_WITH_SPECIAL_CHARS);
}
-
+
private void testServer(final int size) throws Exception {
final String[] messages = new String[size];
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/10316c39/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index ca6b2d4..3593ad7 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -92,6 +92,12 @@
<action issue="LOG4J2-1269" dev="rpopma" type="fix">
(GC) AsyncLogger should use thread-local translator by default.
</action>
+ <action issue="LOG4J2-623" dev="rpopma" type="fix">
+ Generate MDC properties as a JSON map in JSONLayout, with option to output as list of map entries.
+ </action>
+ <action issue="LOG4J2-1362" dev="rpopma" type="add" due-to="Gary Gregory">
+ Added a YAML layout.
+ </action>
<action issue="LOG4J2-1387" dev="rpopma" type="fix">
Fixed memory leak related to shutdown hook.
</action>
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/10316c39/src/site/xdoc/manual/layouts.xml.vm
----------------------------------------------------------------------
diff --git a/src/site/xdoc/manual/layouts.xml.vm b/src/site/xdoc/manual/layouts.xml.vm
index 3a9d175..9d6924e 100644
--- a/src/site/xdoc/manual/layouts.xml.vm
+++ b/src/site/xdoc/manual/layouts.xml.vm
@@ -369,6 +369,13 @@ logger.debug("one={}, two={}, three={}", 1, 2, 3);
<td>If true, the appender includes the thread context map in the generated JSON. Defaults to false.</td>
</tr>
<tr>
+ <td>propertiesAsList</td>
+ <td>boolean</td>
+ <td>If true, the thread context map is included as a list of map entry objects, where each entry has
+ a "key" attribute (whose value is the key) and a "value" attribute (whose value is the value).
+ Defaults to false, in which case the thread context map is included as a simple map of key-value pairs.</td>
+ </tr>
+ <tr>
<td>locationInfo</td>
<td>boolean</td>
<td>