You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by gg...@apache.org on 2013/10/02 16:48:55 UTC

svn commit: r1528503 - in /logging/log4j/log4j2/trunk: log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ log4j-core/src/test/java/org/apache/logging/log4j/core/layout/ src/changes/ src/site/xdoc/manual/

Author: ggregory
Date: Wed Oct  2 14:48:54 2013
New Revision: 1528503

URL: http://svn.apache.org/r1528503
Log:
[lOG4J2-415] Format log event time as UNIX time (seconds or milliseconds).

Modified:
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/DatePatternConverter.java
    logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java
    logging/log4j/log4j2/trunk/src/changes/changes.xml
    logging/log4j/log4j2/trunk/src/site/xdoc/manual/layouts.xml.vm

Modified: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/DatePatternConverter.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/DatePatternConverter.java?rev=1528503&r1=1528502&r2=1528503&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/DatePatternConverter.java (original)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/DatePatternConverter.java Wed Oct  2 14:48:54 2013
@@ -27,9 +27,53 @@ import org.apache.logging.log4j.core.con
  * Convert and format the event's date in a StringBuilder.
  */
 @Plugin(name = "DatePatternConverter", category = "Converter")
-@ConverterKeys({"d", "date" })
+@ConverterKeys({ "d", "date" })
 public final class DatePatternConverter extends LogEventPatternConverter implements ArrayPatternConverter {
 
+    private abstract static class Formatter {
+        abstract String format(long time);
+
+        public String toPattern() {
+            return null;
+        }
+    }
+
+    private static class PatternFormatter extends Formatter {
+        private final SimpleDateFormat simpleDateFormat;
+
+        PatternFormatter(SimpleDateFormat simpleDateFormat) {
+            this.simpleDateFormat = simpleDateFormat;
+        }
+
+        @Override
+        String format(long time) {
+            return simpleDateFormat.format(Long.valueOf(time));
+        }
+
+        @Override
+        public String toPattern() {
+            return simpleDateFormat.toPattern();
+        }
+    }
+
+    private static class UnixFormatter extends Formatter {
+
+        @Override
+        String format(long time) {
+            return Long.toString(time / 1000);
+        }
+
+    }
+
+    private static class UnixMillisFormatter extends Formatter {
+
+        @Override
+        String format(long time) {
+            return Long.toString(time);
+        }
+
+    }
+
     /**
      * ABSOLUTE string literal.
      */
@@ -81,9 +125,20 @@ public final class DatePatternConverter 
     private static final String ISO8601_PATTERN = "yyyy-MM-dd HH:mm:ss,SSS";
 
     /**
+     * UNIX formatter in seconds (standard).
+     */
+    private static final String UNIX_FORMAT = "UNIX";
+
+    /**
+     * UNIX formatter in milliseconds
+     */
+    private static final String UNIX_MILLIS_FORMAT = "UNIX_MILLIS";
+
+    /**
      * Obtains an instance of pattern converter.
-     *
-     * @param options options, may be null.
+     * 
+     * @param options
+     *            options, may be null.
      * @return instance of pattern converter.
      */
     public static DatePatternConverter newInstance(final String[] options) {
@@ -95,29 +150,24 @@ public final class DatePatternConverter 
      */
     private String cachedDateString;
 
-    private long lastTimestamp;
+    private final Formatter formatter;
 
-    private final SimpleDateFormat simpleFormat;
+    private long lastTimestamp;
 
     /**
      * Private constructor.
-     *
-     * @param options options, may be null.
+     * 
+     * @param options
+     *            options, may be null.
      */
     private DatePatternConverter(final String[] options) {
         super("Date", "date");
 
-        String patternOption;
+        // null patternOption is OK.
+        final String patternOption = options != null && options.length > 0 ? options[0] : null;
 
-        if (options == null || options.length == 0) {
-            // the branch could be optimized, but here we are making explicit
-            // that null values for patternOption are allowed.
-            patternOption = null;
-        } else {
-            patternOption = options[0];
-        }
-
-        String pattern;
+        String pattern = null;
+        Formatter tempFormatter = null;
 
         if (patternOption == null || patternOption.equalsIgnoreCase(ISO8601_FORMAT)) {
             pattern = ISO8601_PATTERN;
@@ -129,38 +179,47 @@ public final class DatePatternConverter 
             pattern = DATE_AND_TIME_PATTERN;
         } else if (patternOption.equalsIgnoreCase(COMPACT_FORMAT)) {
             pattern = COMPACT_PATTERN;
+        } else if (patternOption.equalsIgnoreCase(UNIX_FORMAT)) {
+            tempFormatter = new UnixFormatter();
+        } else if (patternOption.equalsIgnoreCase(UNIX_MILLIS_FORMAT)) {
+            tempFormatter = new UnixMillisFormatter();
         } else {
             pattern = patternOption;
         }
 
-        SimpleDateFormat tempFormat;
+        if (pattern != null) {
+            SimpleDateFormat tempFormat;
 
-        try {
-            tempFormat = new SimpleDateFormat(pattern);
-        } catch (final IllegalArgumentException e) {
-            LOGGER.warn("Could not instantiate SimpleDateFormat with pattern " + patternOption, e);
+            try {
+                tempFormat = new SimpleDateFormat(pattern);
+            } catch (final IllegalArgumentException e) {
+                LOGGER.warn("Could not instantiate SimpleDateFormat with pattern " + patternOption, e);
 
-            // default to the ISO8601 format
-            tempFormat = new SimpleDateFormat(ISO8601_PATTERN);
-        }
+                // default to the ISO8601 format
+                tempFormat = new SimpleDateFormat(ISO8601_PATTERN);
+            }
 
-        // if the option list contains a TZ option, then set it.
-        if (options != null && options.length > 1) {
-            final TimeZone tz = TimeZone.getTimeZone(options[1]);
-            tempFormat.setTimeZone(tz);
+            // if the option list contains a TZ option, then set it.
+            if (options != null && options.length > 1) {
+                final TimeZone tz = TimeZone.getTimeZone(options[1]);
+                tempFormat.setTimeZone(tz);
+            }
+            tempFormatter = new PatternFormatter(tempFormat);
         }
-        simpleFormat = tempFormat;
+        formatter = tempFormatter;
     }
 
     /**
      * Append formatted date to string buffer.
-     *
-     * @param date       date
-     * @param toAppendTo buffer to which formatted date is appended.
+     * 
+     * @param date
+     *            date
+     * @param toAppendTo
+     *            buffer to which formatted date is appended.
      */
     public void format(final Date date, final StringBuilder toAppendTo) {
         synchronized (this) {
-            toAppendTo.append(simpleFormat.format(date.getTime()));
+            toAppendTo.append(formatter.format(date.getTime()));
         }
     }
 
@@ -174,7 +233,7 @@ public final class DatePatternConverter 
         synchronized (this) {
             if (timestamp != lastTimestamp) {
                 lastTimestamp = timestamp;
-                cachedDateString = simpleFormat.format(timestamp);
+                cachedDateString = formatter.format(timestamp);
             }
         }
         output.append(cachedDateString);
@@ -201,8 +260,13 @@ public final class DatePatternConverter 
         }
     }
 
+    /**
+     * Gets the pattern string describing this date format.
+     * 
+     * @return the pattern string describing this date format.
+     */
     public String getPattern() {
-        return simpleFormat.toPattern();
+        return formatter.toPattern();
     }
 
 }

Modified: logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java?rev=1528503&r1=1528502&r2=1528503&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java (original)
+++ logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java Wed Oct  2 14:48:54 2013
@@ -17,17 +17,20 @@
 package org.apache.logging.log4j.core.layout;
 
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
 
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.ThreadContext;
 import org.apache.logging.log4j.core.BasicConfigurationFactory;
+import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.Logger;
 import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.appender.FileAppender;
 import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.impl.Log4jLogEvent;
 import org.apache.logging.log4j.core.util.Compare;
-import org.junit.AfterClass;
+import org.apache.logging.log4j.message.SimpleMessage;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
@@ -37,13 +40,14 @@ import org.junit.Test;
 public class PatternLayoutTest {
     static ConfigurationFactory cf = new BasicConfigurationFactory();
     static String msgPattern = "%m%n";
-    static String OUTPUT_FILE   = "target/output/PatternParser";
+    static String OUTPUT_FILE = "target/output/PatternParser";
     static final String regexPattern = "%replace{%logger %msg}{\\.}{/}";
-    static String WITNESS_FILE  = "witness/PatternParser";
+    static String WITNESS_FILE = "witness/PatternParser";
 
     public static void cleanupClass() {
         ConfigurationFactory.removeConfigurationFactory(cf);
     }
+
     @BeforeClass
     public static void setupClass() {
         ConfigurationFactory.setConfigurationFactory(cf);
@@ -54,6 +58,7 @@ public class PatternLayoutTest {
     LoggerContext ctx = (LoggerContext) LogManager.getContext();
 
     Logger root = ctx.getLogger("");
+
     /**
      * Test case for MDC conversion pattern.
      */
@@ -68,9 +73,9 @@ public class PatternLayoutTest {
 
         // set up appender
         final PatternLayout layout = PatternLayout.createLayout(msgPattern, ctx.getConfiguration(), null, null, null);
-        //FileOutputStream fos = new FileOutputStream(OUTPUT_FILE + "_mdc");
-        final FileAppender appender = FileAppender.createAppender(OUTPUT_FILE + "_mdc", "false", "false", "File", "false",
-            "true", "false", null, layout, null, "false", null, null);
+        // FileOutputStream fos = new FileOutputStream(OUTPUT_FILE + "_mdc");
+        final FileAppender appender = FileAppender.createAppender(OUTPUT_FILE + "_mdc", "false", "false", "File",
+                "false", "true", "false", null, layout, null, "false", null, null);
         appender.start();
 
         // set appender on root and set level to debug
@@ -126,4 +131,64 @@ public class PatternLayoutTest {
         appender.stop();
     }
 
+    @Test
+    public void testRegex() throws Exception {
+        final LoggerContext ctx = (LoggerContext) LogManager.getContext();
+        final PatternLayout layout = PatternLayout.createLayout(regexPattern, ctx.getConfiguration(), null, null, null);
+        final LogEvent event = new Log4jLogEvent(this.getClass().getName(), null,
+                "org.apache.logging.log4j.core.Logger", Level.INFO, new SimpleMessage("Hello, world!"), null);
+        final byte[] result = layout.toByteArray(event);
+        assertEquals("org/apache/logging/log4j/core/layout/PatternLayoutTest Hello, world!", new String(result));
+    }
+
+    private void testUnixTime(String pattern) throws Exception {
+        final LoggerContext ctx = (LoggerContext) LogManager.getContext();
+        final PatternLayout layout = PatternLayout.createLayout(pattern + " %m", ctx.getConfiguration(), null, null,
+                null);
+        final LogEvent event1 = new Log4jLogEvent(this.getClass().getName(), null,
+                "org.apache.logging.log4j.core.Logger", Level.INFO, new SimpleMessage("Hello, world 1!"), null);
+        final byte[] result1 = layout.toByteArray(event1);
+        assertEquals(event1.getMillis() + " Hello, world 1!", new String(result1));
+        // System.out.println("event1=" + event1.getMillis());
+        final LogEvent event2 = new Log4jLogEvent(this.getClass().getName(), null,
+                "org.apache.logging.log4j.core.Logger", Level.INFO, new SimpleMessage("Hello, world 2!"), null);
+        final byte[] result2 = layout.toByteArray(event2);
+        assertEquals(event2.getMillis() + " Hello, world 2!", new String(result2));
+        // System.out.println("event2=" + event2.getMillis());
+    }
+
+    @Test
+    public void testUnixTime() throws Exception {
+        final LoggerContext ctx = (LoggerContext) LogManager.getContext();
+        final PatternLayout layout = PatternLayout
+                .createLayout("%d{UNIX} %m", ctx.getConfiguration(), null, null, null);
+        final LogEvent event1 = new Log4jLogEvent(this.getClass().getName(), null,
+                "org.apache.logging.log4j.core.Logger", Level.INFO, new SimpleMessage("Hello, world 1!"), null);
+        final byte[] result1 = layout.toByteArray(event1);
+        assertEquals(event1.getMillis() / 1000 + " Hello, world 1!", new String(result1));
+        System.out.println("event1=" + event1.getMillis() / 1000);
+        final LogEvent event2 = new Log4jLogEvent(this.getClass().getName(), null,
+                "org.apache.logging.log4j.core.Logger", Level.INFO, new SimpleMessage("Hello, world 2!"), null);
+        final byte[] result2 = layout.toByteArray(event2);
+        assertEquals(event2.getMillis() / 1000 + " Hello, world 2!", new String(result2));
+        System.out.println("event2=" + event2.getMillis() / 1000);
+    }
+
+    @Test
+    public void testUnixTimeMillis() throws Exception {
+        final LoggerContext ctx = (LoggerContext) LogManager.getContext();
+        final PatternLayout layout = PatternLayout.createLayout("%d{UNIX_MILLIS} %m", ctx.getConfiguration(), null,
+                null, null);
+        final LogEvent event1 = new Log4jLogEvent(this.getClass().getName(), null,
+                "org.apache.logging.log4j.core.Logger", Level.INFO, new SimpleMessage("Hello, world 1!"), null);
+        final byte[] result1 = layout.toByteArray(event1);
+        assertEquals(event1.getMillis() + " Hello, world 1!", new String(result1));
+        System.out.println("event1=" + event1.getMillis());
+        final LogEvent event2 = new Log4jLogEvent(this.getClass().getName(), null,
+                "org.apache.logging.log4j.core.Logger", Level.INFO, new SimpleMessage("Hello, world 2!"), null);
+        final byte[] result2 = layout.toByteArray(event2);
+        assertEquals(event2.getMillis() + " Hello, world 2!", new String(result2));
+        System.out.println("event2=" + event2.getMillis());
+    }
+
 }

Modified: logging/log4j/log4j2/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/changes/changes.xml?rev=1528503&r1=1528502&r2=1528503&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/changes/changes.xml (original)
+++ logging/log4j/log4j2/trunk/src/changes/changes.xml Wed Oct  2 14:48:54 2013
@@ -21,6 +21,9 @@
   </properties>
   <body>
     <release version="2.0RC1" date="2013-MM-DD" description="Bug fixes and enhancements">
+      <action issue="LOG4J2-415" dev="ggregory" type="add">
+        Format log event time as UNIX time (seconds or milliseconds).
+      </action>
       <action issue="LOG4J2-404" dev="rgoers" type="fix" due-to="Kamal Bahadur">
         @EnterpriseNumber" was missing in the ID of structured data when RFC5424Layout is used
       </action>

Modified: logging/log4j/log4j2/trunk/src/site/xdoc/manual/layouts.xml.vm
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/site/xdoc/manual/layouts.xml.vm?rev=1528503&r1=1528502&r2=1528503&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/site/xdoc/manual/layouts.xml.vm (original)
+++ logging/log4j/log4j2/trunk/src/site/xdoc/manual/layouts.xml.vm Wed Oct  2 14:48:54 2013
@@ -359,8 +359,25 @@ WARN  [main]: Message 2</pre>
                       <td>%d{HH:mm:ss}{GMT+0}</td>
                       <td>18:34:02,781</td>
                     </tr>
+                    <tr>
+                      <td>%d{UNIX}</td>
+                      <td>1351866842</td>
+                    </tr>
+                    <tr>
+                      <td>%d{UNIX_MILLIS}</td>
+                      <td>1351866842781</td>
+                    </tr>
                   </table>
                 </p>
+                <p>
+                  %d{UNIX} outputs the UNIX time in seconds. %d{UNIX_MILLIS} outputs the UNIX time in milliseconds. 
+                  The UNIX time is the difference, in seconds for UNIX and in milliseconds for UNIX_MILLIS, between
+                  the current time and midnight, January 1, 1970 UTC. While the time unit is milliseconds, the 
+                  granularity depends on the operating system 
+                  (<a href="http://msdn.microsoft.com/en-us/windows/hardware/gg463266.aspx">Windows</a>). 
+                  This is an efficient way to output the event time because only a conversion from long to String 
+                  takes place, there is no Date formatting involved.
+                </p>
               </td>
             </tr>
             <tr>