[ 
https://issues.apache.org/jira/browse/LOG4J2-908?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15074388#comment-15074388
 ] 

Gary Gregory edited comment on LOG4J2-908 at 12/30/15 12:48 AM:
----------------------------------------------------------------

How about adding the "," if an event is not the 1st event and we are logging a 
"complete" document? (pardon some of the noise in the diff):

{noformat}
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 ca966fb..3b122e1 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
@@ -16,12 +16,16 @@
  */
 package org.apache.logging.log4j.core.layout;
 
+import java.io.IOException;
+import java.io.Writer;
 import java.nio.charset.Charset;
 
 import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.util.StringBuilderWriter;
 import org.apache.logging.log4j.util.Strings;
 
-import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.databind.JsonMappingException;
 import com.fasterxml.jackson.databind.ObjectWriter;
 
 abstract class AbstractJacksonLayout extends AbstractStringLayout {
@@ -51,13 +55,22 @@
      */
     @Override
     public String toSerializable(final LogEvent event) {
+        StringBuilderWriter writer = new StringBuilderWriter();        
         try {
-            return this.objectWriter.writeValueAsString(event) + eol;
-        } catch (final JsonProcessingException e) {
+            toSerializable(event, writer);
+            return writer.toString();
+        } catch (final IOException e) {
             // Should this be an ISE or IAE?
             LOGGER.error(e);
             return Strings.EMPTY;
         }
     }
 
+    public void toSerializable(final LogEvent event, Writer writer)
+            throws JsonGenerationException, JsonMappingException, IOException {
+        objectWriter.writeValue(writer, event);
+        writer.write(eol);
+        markEvent();
+    }
+
 }
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractLayout.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractLayout.java
index 4fa1d8e..9c5166e 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractLayout.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractLayout.java
@@ -50,6 +50,11 @@
     protected final byte[] footer;
 
     /**
+     * The count of events successfully processed by this layout.
+     */
+    protected long eventCount;
+
+    /**
      * Constructs a layout with an optional header and footer.
      * 
      * @param header
@@ -87,4 +92,8 @@
     public byte[] getHeader() {
         return header;
     }
+    
+    protected void markEvent() {
+        eventCount++;
+    }
 }
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 04cda2d..5f3969c 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
@@ -16,12 +16,15 @@
  */
 package org.apache.logging.log4j.core.layout;
 
+import java.io.IOException;
+import java.io.Writer;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.Map;
 
 import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.config.Node;
 import org.apache.logging.log4j.core.config.plugins.Plugin;
 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
@@ -32,8 +35,9 @@
  *
  * <h3>Complete well-formed JSON vs. fragment JSON</h3>
  * <p>
- * If you configure {@code complete="true"}, the appender outputs a 
well-formed JSON document. By default, with {@code complete="false"},
- * you should include the output as an <em>external file</em> in a separate 
file to form a well-formed JSON document.
+ * If you configure {@code complete="true"}, the appender outputs a 
well-formed JSON document. By default, with
+ * {@code complete="false"}, you should include the output as an <em>external 
file</em> in a separate file to form a
+ * well-formed JSON document.
  * </p>
  * <p>
  * A well-formed JSON event follows this pattern:
@@ -773,22 +777,22 @@
 }
  * </pre>
  * <p>
- * If {@code complete="false"}, the appender does not write the JSON open 
array character "[" at the start of the document. and "]" and the
- * end.
+ * If {@code complete="false"}, the appender does not write the JSON open 
array character "[" at the start of the
+ * document. and "]" and the end.
  * </p>
  * <p>
  * This approach enforces the independence of the JsonLayout and the appender 
where you embed it.
  * </p>
  * <h3>Encoding</h3>
  * <p>
- * Appenders using this layout should have their {@code charset} set to {@code 
UTF-8} or {@code UTF-16}, otherwise events containing non
- * ASCII characters could result in corrupted log files.
+ * Appenders using this layout should have their {@code charset} set to {@code 
UTF-8} or {@code UTF-16}, otherwise
+ * events containing non ASCII characters could result in corrupted log files.
  * </p>
  * <h3>Pretty vs. compact XML</h3>
  * <p>
- * By default, the JSON layout is not compact (a.k.a. not "pretty") with 
{@code compact="false"}, which means the appender uses end-of-line
- * characters and indents lines to format the text. If {@code compact="true"}, 
then no end-of-line or indentation is used. Message content
- * may contain, of course, escaped end-of-lines.
+ * By default, the JSON layout is not compact (a.k.a. not "pretty") with 
{@code compact="false"}, which means the
+ * appender uses end-of-line characters and indents lines to format the text. 
If {@code compact="true"}, then no
+ * end-of-line or indentation is used. Message content may contain, of course, 
escaped end-of-lines.
  * </p>
  */
 @Plugin(name = "JsonLayout", category = Node.CATEGORY, elementType = 
Layout.ELEMENT_TYPE, printObject = true)
@@ -798,9 +802,10 @@
 
     private static final long serialVersionUID = 1L;
 
-    protected JsonLayout(final boolean locationInfo, final boolean properties, 
final boolean complete, final boolean compact,
-            final boolean eventEol, final Charset charset) {
-        super(new JacksonFactory.JSON().newWriter(locationInfo, properties, 
compact), charset, compact, complete, eventEol);
+    protected JsonLayout(final boolean locationInfo, final boolean properties, 
final boolean complete,
+            final boolean compact, final boolean eventEol, final Charset 
charset) {
+        super(new JacksonFactory.JSON().newWriter(locationInfo, properties, 
compact), charset, compact, complete,
+                eventEol);
     }
 
     /**
@@ -851,18 +856,18 @@
      * Creates a JSON Layout.
      *
      * @param locationInfo
-     *        If "true", includes the location information in the generated 
JSON.
+     *            If "true", includes the location information in the 
generated JSON.
      * @param properties
-     *        If "true", includes the thread context in the generated JSON.
+     *            If "true", includes the thread context in the generated JSON.
      * @param complete
-     *        If "true", includes the JSON header and footer, defaults to 
"false".
+     *            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".
+     *            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.
+     *            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".
+     *            The character set to use, if {@code null}, uses "UTF-8".
      * @return A JSON Layout.
      */
     @PluginFactory
@@ -887,4 +892,12 @@
     public static AbstractJacksonLayout createDefaultLayout() {
         return new JsonLayout(false, false, false, false, false, 
StandardCharsets.UTF_8);
     }
+
+    @Override
+    public void toSerializable(final LogEvent event, Writer writer) throws 
IOException {
+        if (complete && eventCount > 1) {
+            writer.append(", ");
+        }
+        super.toSerializable(event, writer);
+    }
 }
{noformat}


was (Author: garydgregory):
How about adding the "," if an event is not the 1st event and we are logging a 
"complete" document? (pardon some of the noise in the diff):

{noformat}
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/PatternProcessor.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/PatternProcessor.java
index fbc74b4..7ec8eca 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/PatternProcessor.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/PatternProcessor.java
@@ -99,6 +99,7 @@
         final Calendar cal = Calendar.getInstance();
         cal.set(currentCal.get(Calendar.YEAR), 0, 1, 0, 0, 0);
         cal.set(Calendar.MILLISECOND, 0);
+        cal.setMinimalDaysInFirstWeek(1);
         if (frequency == RolloverFrequency.ANNUALLY) {
             increment(cal, Calendar.YEAR, increment, modulus);
             nextTime = cal.getTimeInMillis();
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 ca966fb..3b122e1 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
@@ -16,12 +16,16 @@
  */
 package org.apache.logging.log4j.core.layout;
 
+import java.io.IOException;
+import java.io.Writer;
 import java.nio.charset.Charset;
 
 import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.util.StringBuilderWriter;
 import org.apache.logging.log4j.util.Strings;
 
-import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.databind.JsonMappingException;
 import com.fasterxml.jackson.databind.ObjectWriter;
 
 abstract class AbstractJacksonLayout extends AbstractStringLayout {
@@ -51,13 +55,22 @@
      */
     @Override
     public String toSerializable(final LogEvent event) {
+        StringBuilderWriter writer = new StringBuilderWriter();        
         try {
-            return this.objectWriter.writeValueAsString(event) + eol;
-        } catch (final JsonProcessingException e) {
+            toSerializable(event, writer);
+            return writer.toString();
+        } catch (final IOException e) {
             // Should this be an ISE or IAE?
             LOGGER.error(e);
             return Strings.EMPTY;
         }
     }
 
+    public void toSerializable(final LogEvent event, Writer writer)
+            throws JsonGenerationException, JsonMappingException, IOException {
+        objectWriter.writeValue(writer, event);
+        writer.write(eol);
+        markEvent();
+    }
+
 }
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractLayout.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractLayout.java
index 4fa1d8e..9c5166e 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractLayout.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractLayout.java
@@ -50,6 +50,11 @@
     protected final byte[] footer;
 
     /**
+     * The count of events successfully processed by this layout.
+     */
+    protected long eventCount;
+
+    /**
      * Constructs a layout with an optional header and footer.
      * 
      * @param header
@@ -87,4 +92,8 @@
     public byte[] getHeader() {
         return header;
     }
+    
+    protected void markEvent() {
+        eventCount++;
+    }
 }
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 04cda2d..5f3969c 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
@@ -16,12 +16,15 @@
  */
 package org.apache.logging.log4j.core.layout;
 
+import java.io.IOException;
+import java.io.Writer;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.Map;
 
 import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.config.Node;
 import org.apache.logging.log4j.core.config.plugins.Plugin;
 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
@@ -32,8 +35,9 @@
  *
  * <h3>Complete well-formed JSON vs. fragment JSON</h3>
  * <p>
- * If you configure {@code complete="true"}, the appender outputs a 
well-formed JSON document. By default, with {@code complete="false"},
- * you should include the output as an <em>external file</em> in a separate 
file to form a well-formed JSON document.
+ * If you configure {@code complete="true"}, the appender outputs a 
well-formed JSON document. By default, with
+ * {@code complete="false"}, you should include the output as an <em>external 
file</em> in a separate file to form a
+ * well-formed JSON document.
  * </p>
  * <p>
  * A well-formed JSON event follows this pattern:
@@ -773,22 +777,22 @@
 }
  * </pre>
  * <p>
- * If {@code complete="false"}, the appender does not write the JSON open 
array character "[" at the start of the document. and "]" and the
- * end.
+ * If {@code complete="false"}, the appender does not write the JSON open 
array character "[" at the start of the
+ * document. and "]" and the end.
  * </p>
  * <p>
  * This approach enforces the independence of the JsonLayout and the appender 
where you embed it.
  * </p>
  * <h3>Encoding</h3>
  * <p>
- * Appenders using this layout should have their {@code charset} set to {@code 
UTF-8} or {@code UTF-16}, otherwise events containing non
- * ASCII characters could result in corrupted log files.
+ * Appenders using this layout should have their {@code charset} set to {@code 
UTF-8} or {@code UTF-16}, otherwise
+ * events containing non ASCII characters could result in corrupted log files.
  * </p>
  * <h3>Pretty vs. compact XML</h3>
  * <p>
- * By default, the JSON layout is not compact (a.k.a. not "pretty") with 
{@code compact="false"}, which means the appender uses end-of-line
- * characters and indents lines to format the text. If {@code compact="true"}, 
then no end-of-line or indentation is used. Message content
- * may contain, of course, escaped end-of-lines.
+ * By default, the JSON layout is not compact (a.k.a. not "pretty") with 
{@code compact="false"}, which means the
+ * appender uses end-of-line characters and indents lines to format the text. 
If {@code compact="true"}, then no
+ * end-of-line or indentation is used. Message content may contain, of course, 
escaped end-of-lines.
  * </p>
  */
 @Plugin(name = "JsonLayout", category = Node.CATEGORY, elementType = 
Layout.ELEMENT_TYPE, printObject = true)
@@ -798,9 +802,10 @@
 
     private static final long serialVersionUID = 1L;
 
-    protected JsonLayout(final boolean locationInfo, final boolean properties, 
final boolean complete, final boolean compact,
-            final boolean eventEol, final Charset charset) {
-        super(new JacksonFactory.JSON().newWriter(locationInfo, properties, 
compact), charset, compact, complete, eventEol);
+    protected JsonLayout(final boolean locationInfo, final boolean properties, 
final boolean complete,
+            final boolean compact, final boolean eventEol, final Charset 
charset) {
+        super(new JacksonFactory.JSON().newWriter(locationInfo, properties, 
compact), charset, compact, complete,
+                eventEol);
     }
 
     /**
@@ -851,18 +856,18 @@
      * Creates a JSON Layout.
      *
      * @param locationInfo
-     *        If "true", includes the location information in the generated 
JSON.
+     *            If "true", includes the location information in the 
generated JSON.
      * @param properties
-     *        If "true", includes the thread context in the generated JSON.
+     *            If "true", includes the thread context in the generated JSON.
      * @param complete
-     *        If "true", includes the JSON header and footer, defaults to 
"false".
+     *            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".
+     *            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.
+     *            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".
+     *            The character set to use, if {@code null}, uses "UTF-8".
      * @return A JSON Layout.
      */
     @PluginFactory
@@ -887,4 +892,12 @@
     public static AbstractJacksonLayout createDefaultLayout() {
         return new JsonLayout(false, false, false, false, false, 
StandardCharsets.UTF_8);
     }
+
+    @Override
+    public void toSerializable(final LogEvent event, Writer writer) throws 
IOException {
+        if (complete && eventCount > 1) {
+            writer.append(", ");
+        }
+        super.toSerializable(event, writer);
+    }
 }
{noformat}

> JSONLayout doesn't add a comma between log events
> -------------------------------------------------
>
>                 Key: LOG4J2-908
>                 URL: https://issues.apache.org/jira/browse/LOG4J2-908
>             Project: Log4j 2
>          Issue Type: Bug
>          Components: Layouts
>    Affects Versions: 2.1
>            Reporter: Konstantinos Liakos
>
> JSONLayout doesn't output a comma (,) between the log events. This makes it 
> quite difficult to read and deserialize the log files.



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to