Repository: logging-log4j2 Updated Branches: refs/heads/master 77505979e -> 5ad7d8124
[LOG4J2-941] Allow JSON layout to create one compact log record per line. Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/5ad7d812 Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/5ad7d812 Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/5ad7d812 Branch: refs/heads/master Commit: 5ad7d8124360b5cf5aa26d377dbf8c0057d4d11b Parents: 7750597 Author: Gary Gregory <[email protected]> Authored: Sat Jan 17 00:45:34 2015 -0500 Committer: Gary Gregory <[email protected]> Committed: Sat Jan 17 00:45:34 2015 -0500 ---------------------------------------------------------------------- .../core/layout/AbstractJacksonLayout.java | 6 +-- .../logging/log4j/core/layout/JsonLayout.java | 27 ++++++++----- .../logging/log4j/core/layout/XmlLayout.java | 2 +- .../core/appender/ConsoleAppenderTest.java | 41 +++++++++++++++++++- .../log4j/core/layout/JsonLayoutTest.java | 21 ++++++---- .../net/server/AbstractSocketServerTest.java | 2 +- src/changes/changes.xml | 3 ++ src/site/xdoc/manual/layouts.xml.vm | 8 ++++ 8 files changed, 86 insertions(+), 24 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/5ad7d812/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractJacksonLayout.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractJacksonLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractJacksonLayout.java index 0215de8..bed0e08 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractJacksonLayout.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractJacksonLayout.java @@ -34,12 +34,12 @@ abstract class AbstractJacksonLayout extends AbstractStringLayout { protected final boolean compact; protected final boolean complete; - protected AbstractJacksonLayout(final ObjectWriter objectWriter, final Charset charset, final boolean compact, final boolean complete) { + protected AbstractJacksonLayout(final ObjectWriter objectWriter, final Charset charset, final boolean compact, final boolean complete, boolean eventEol) { super(charset); this.objectWriter = objectWriter; this.compact = compact; this.complete = complete; - this.eol = compact ? COMPACT_EOL : DEFAULT_EOL; + this.eol = compact && !eventEol ? COMPACT_EOL : DEFAULT_EOL; } /** @@ -51,7 +51,7 @@ abstract class AbstractJacksonLayout extends AbstractStringLayout { @Override public String toSerializable(final LogEvent event) { try { - return this.objectWriter.writeValueAsString(event); + return this.objectWriter.writeValueAsString(event) + eol; } catch (final JsonProcessingException e) { // Should this be an ISE or IAE? LOGGER.error(e); http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/5ad7d812/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 97a916e..be0d96d 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 @@ -799,8 +799,8 @@ public final class JsonLayout extends AbstractJacksonLayout { private static final long serialVersionUID = 1L; protected JsonLayout(final boolean locationInfo, final boolean properties, final boolean complete, final boolean compact, - final Charset charset) { - super(new JacksonFactory.JSON().newWriter(locationInfo, properties, compact), charset, compact, complete); + boolean eventEol, final Charset charset) { + super(new JacksonFactory.JSON().newWriter(locationInfo, properties, compact), charset, compact, complete, eventEol); } /** @@ -850,11 +850,19 @@ public final class JsonLayout extends AbstractJacksonLayout { /** * Creates a JSON Layout. * - * @param locationInfo If "true", includes the location information in the generated JSON. - * @param properties If "true", includes the thread context in the generated JSON. - * @param complete If "true", includes the JSON header and footer, defaults to "false". - * @param compact If "true", does not use end-of-lines and indentation, defaults to "false". - * @param charset The character set to use, if {@code null}, uses "UTF-8". + * @param locationInfo + * If "true", includes the location information in the generated JSON. + * @param properties + * If "true", includes the thread context in the generated JSON. + * @param complete + * If "true", includes the JSON header and footer, defaults to "false". + * @param compact + * If "true", does not use end-of-lines and indentation, defaults to "false". + * @param eventEol + * If "true", forces an EOL after each log event (even if compact is "true"), defaults to "false". This + * allows one even per line, even in compact mode. + * @param charset + * The character set to use, if {@code null}, uses "UTF-8". * @return A JSON Layout. */ @PluginFactory @@ -864,10 +872,11 @@ public final class JsonLayout extends AbstractJacksonLayout { @PluginAttribute(value = "properties", defaultBoolean = false) final boolean properties, @PluginAttribute(value = "complete", defaultBoolean = false) final boolean complete, @PluginAttribute(value = "compact", defaultBoolean = false) final boolean compact, + @PluginAttribute(value = "eventEol", defaultBoolean = false) final boolean eventEol, @PluginAttribute(value = "charset", defaultString = "UTF-8") final Charset charset // @formatter:on ) { - return new JsonLayout(locationInfo, properties, complete, compact, charset); + return new JsonLayout(locationInfo, properties, complete, compact, eventEol, charset); } /** @@ -876,6 +885,6 @@ public final class JsonLayout extends AbstractJacksonLayout { * @return A JSON Layout. */ public static AbstractJacksonLayout createDefaultLayout() { - return new JsonLayout(false, false, false, false, Charsets.UTF_8); + return new JsonLayout(false, false, false, false, false, Charsets.UTF_8); } } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/5ad7d812/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/XmlLayout.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/XmlLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/XmlLayout.java index df83cca..e0c64a4 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/XmlLayout.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/XmlLayout.java @@ -194,7 +194,7 @@ public final class XmlLayout extends AbstractJacksonLayout { private static final String ROOT_TAG = "Events"; protected XmlLayout(final boolean locationInfo, final boolean properties, final boolean complete, final boolean compact, final Charset charset) { - super(new JacksonFactory.XML().newWriter(locationInfo, properties, compact), charset, compact, complete); + super(new JacksonFactory.XML().newWriter(locationInfo, properties, compact), charset, compact, complete, false); } /** http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/5ad7d812/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderTest.java index 78213d1..3c5fe35 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderTest.java @@ -16,26 +16,36 @@ */ package org.apache.logging.log4j.core.appender; +import static org.easymock.EasyMock.anyInt; +import static org.easymock.EasyMock.anyObject; +import static org.easymock.EasyMock.expectLastCall; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + import java.io.ByteArrayOutputStream; import java.io.PrintStream; import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.impl.Log4jLogEvent; +import org.apache.logging.log4j.core.layout.PatternLayout; import org.apache.logging.log4j.core.util.Constants; import org.apache.logging.log4j.message.SimpleMessage; +import org.easymock.EasyMockSupport; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; -import static org.junit.Assert.*; - /** * */ public class ConsoleAppenderTest { private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + EasyMockSupport mocks = new EasyMockSupport(); + PrintStream psMock = mocks.createMock("psMock", PrintStream.class); @BeforeClass public static void before() { @@ -48,6 +58,33 @@ public class ConsoleAppenderTest { } @Test + public void testConsoleStreamManagerDoesNotClose() { + final PrintStream ps = System.out; + + psMock.write((byte[]) anyObject(), anyInt(), anyInt()); + expectLastCall().anyTimes(); + psMock.flush(); + + mocks.replayAll(); + System.setOut(psMock); + final Layout<String> layout = PatternLayout.createLayout(null, null, null, null, false, false, null, null); + final ConsoleAppender app = ConsoleAppender.createAppender(layout, null, "SYSTEM_OUT", "Console", "false", + "false"); + app.start(); + assertTrue("Appender did not start", app.isStarted()); + + final LogEvent event = new Log4jLogEvent("TestLogger", null, ConsoleAppenderTest.class.getName(), Level.INFO, + new SimpleMessage("Test"), null); + app.append(event); + + app.stop(); + assertFalse("Appender did not stop", app.isStarted()); + + System.setOut(ps); + mocks.verifyAll(); + } + + @Test public void testFollow() { final PrintStream ps = System.out; final ConsoleAppender app = ConsoleAppender.newBuilder() http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/5ad7d812/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 368ead6..b043660 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 @@ -101,16 +101,16 @@ public class JsonLayoutTest { assertTrue(str, str.contains(DQUOTE + name + DQUOTE + propSep)); } - private void testAllFeatures(final boolean includeSource, final boolean compact, final boolean includeContext) + private void testAllFeatures(final boolean includeSource, final boolean compact, boolean eventEol, final boolean includeContext) throws Exception { final Log4jLogEvent expected = LogEventFixtures.createLogEvent(); final AbstractJacksonLayout layout = JsonLayout.createLayout(includeSource, - includeContext, false, compact, Charsets.UTF_8); + includeContext, false, compact, eventEol, Charsets.UTF_8); final String str = layout.toSerializable(expected); // System.out.println(str); final String propSep = this.toPropertySeparator(compact); // Just check for \n since \r might or might not be there. - assertEquals(str, !compact, str.contains("\n")); + 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); @@ -178,7 +178,7 @@ public class JsonLayoutTest { this.rootLogger.removeAppender(appender); } // set up appender - final AbstractJacksonLayout layout = JsonLayout.createLayout(true, true, true, false, null); + final AbstractJacksonLayout layout = JsonLayout.createLayout(true, true, true, false, false, null); final ListAppender appender = new ListAppender("List", null, layout, true, false); appender.start(); @@ -213,7 +213,7 @@ public class JsonLayoutTest { this.rootLogger.removeAppender(appender); } // set up appender - final AbstractJacksonLayout layout = JsonLayout.createLayout(true, true, true, false, null); + final AbstractJacksonLayout layout = JsonLayout.createLayout(true, true, true, false, false, null); final ListAppender appender = new ListAppender("List", null, layout, true, false); appender.start(); @@ -252,7 +252,7 @@ public class JsonLayoutTest { @Test public void testLayoutLoggerName() throws Exception { - final AbstractJacksonLayout layout = JsonLayout.createLayout(false, false, false, true, Charsets.UTF_8); + final AbstractJacksonLayout layout = JsonLayout.createLayout(false, false, false, true, false, Charsets.UTF_8); final Log4jLogEvent expected = Log4jLogEvent.createEvent("a.B", null, "f.q.c.n", Level.DEBUG, new SimpleMessage("M"), null, null, null, null, "threadName", null, 1); final String str = layout.toSerializable(expected); @@ -264,12 +264,17 @@ public class JsonLayoutTest { @Test public void testLocationOffCompactOffMdcOff() throws Exception { - this.testAllFeatures(false, false, false); + this.testAllFeatures(false, false, false, false); } @Test public void testLocationOnCompactOnMdcOn() throws Exception { - this.testAllFeatures(true, true, true); + this.testAllFeatures(true, true, false, true); + } + + @Test + public void testLocationOnCompactOnEventEolOnMdcOn() throws Exception { + this.testAllFeatures(true, true, true, true); } private String toPropertySeparator(final boolean compact) { http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/5ad7d812/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 f97b584..891e278 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 @@ -91,7 +91,7 @@ public abstract class AbstractSocketServerTest { } protected Layout<String> createJsonLayout() { - return JsonLayout.createLayout(true, true, false, false, null); + return JsonLayout.createLayout(true, true, false, false, false, null); } protected abstract Layout<? extends Serializable> createLayout(); http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/5ad7d812/src/changes/changes.xml ---------------------------------------------------------------------- diff --git a/src/changes/changes.xml b/src/changes/changes.xml index edf5dfa..de831a2 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -24,6 +24,9 @@ </properties> <body> <release version="2.2" date="201?-??-??" description="GA Release 2.2"> + <action issue="LOG4J2-941" dev="ggregory" type="add" due-to="Konstantinos Liakos"> + Allow JSON layout to create one compact log record per line. + </action> <action issue="LOG4J2-933" dev="ggregory" type="add" due-to="ppiman at gmail.com"> HTML layout should not use attribute minimalization for hr noshade. </action> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/5ad7d812/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 a64c92c..dd4683a 100644 --- a/src/site/xdoc/manual/layouts.xml.vm +++ b/src/site/xdoc/manual/layouts.xml.vm @@ -116,6 +116,14 @@ <td>If true, the appender does not use end-of-lines and indentation. Defaults to false.</td> </tr> <tr> + <td>eventEol</td> + <td>boolean</td> + <td> + If true, the appender appends an end-of-line after each record. Defaults to false. + Use with eventEol=true and compact=true to get one record per line. + </td> + </tr> + <tr> <td>complete</td> <td>boolean</td> <td>If true, the appender includes the JSON header and footer. Defaults to false.</td>
