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 2015/07/18 17:05:18 UTC

[1/2] logging-log4j2 git commit: LOG4J2-1076 Added support for system nanosecond time in pattern layout

Repository: logging-log4j2
Updated Branches:
  refs/heads/master 8901ffc46 -> 7f075a710


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/PatternParserTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/PatternParserTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/PatternParserTest.java
index 3af9ba7..c9a927e 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/PatternParserTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/PatternParserTest.java
@@ -29,6 +29,7 @@ import org.apache.logging.log4j.core.Logger;
 import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
 import org.apache.logging.log4j.core.util.Constants;
+import org.apache.logging.log4j.core.util.NanoClockFactory;
 import org.apache.logging.log4j.message.SimpleMessage;
 import org.junit.Before;
 import org.junit.Test;
@@ -111,7 +112,7 @@ public class PatternParserTest {
             formatter.format(event, buf);
         }
         final String str = buf.toString();
-        final String expected = "INFO  [PatternParserTest        :97  ] - Hello, world" + Constants.LINE_SEPARATOR;
+        final String expected = "INFO  [PatternParserTest        :98  ] - Hello, world" + Constants.LINE_SEPARATOR;
         assertTrue("Expected to end with: " + expected + ". Actual: " + str, str.endsWith(expected));
     }
 
@@ -223,5 +224,36 @@ public class PatternParserTest {
         assertTrue("Expected to start with: " + expectedStart + ". Actual: " + str, str.startsWith(expectedStart));
         assertTrue("Expected to end with: \"" + expectedEnd + "\". Actual: \"" + str, str.endsWith(expectedEnd));
     }
-
+    
+    @Test
+    public void testNanoPatternShort() {
+        final List<PatternFormatter> formatters = parser.parse("%N");
+        assertNotNull(formatters);
+        assertEquals(1, formatters.size());
+        assertTrue(formatters.get(0).getConverter() instanceof NanoTimePatternConverter);
+    }
+    
+    @Test
+    public void testNanoPatternLong() {
+        final List<PatternFormatter> formatters = parser.parse("%nano");
+        assertNotNull(formatters);
+        assertEquals(1, formatters.size());
+        assertTrue(formatters.get(0).getConverter() instanceof NanoTimePatternConverter);
+    }
+    
+    @Test
+    public void testNanoPatternShortChangesNanoClockFactoryMode() {
+        parser.parse("%m");
+        assertEquals(NanoClockFactory.Mode.Dummy, NanoClockFactory.getMode());
+        parser.parse("%nano");
+        assertEquals(NanoClockFactory.Mode.System, NanoClockFactory.getMode());
+    }
+    
+    @Test
+    public void testNanoPatternLongChangesNanoClockFactoryMode() {
+        parser.parse("%m");
+        assertEquals(NanoClockFactory.Mode.Dummy, NanoClockFactory.getMode());
+        parser.parse("%N");
+        assertEquals(NanoClockFactory.Mode.System, NanoClockFactory.getMode());
+    }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/test/java/org/apache/logging/log4j/core/util/DummyNanoClockTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/DummyNanoClockTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/util/DummyNanoClockTest.java
new file mode 100644
index 0000000..8fc16b6
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/util/DummyNanoClockTest.java
@@ -0,0 +1,39 @@
+/*
+ * 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.util;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Tests the DummyNanoClock.
+ */
+public class DummyNanoClockTest {
+
+    @Test
+    public void testReturnsZeroByDefault() {
+        assertEquals(0, new DummyNanoClock().nanoTime());
+    }
+
+    @Test
+    public void testReturnsConstructorValue() {
+        assertEquals(123, new DummyNanoClock(123).nanoTime());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/test/java/org/apache/logging/log4j/core/util/NanoClockFactoryTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/NanoClockFactoryTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/util/NanoClockFactoryTest.java
new file mode 100644
index 0000000..f7667d6
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/util/NanoClockFactoryTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.util;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Tests the NanoClockFactory.
+ */
+public class NanoClockFactoryTest {
+
+    @Test
+    public void testDefaultModeIsDummy() {
+        assertEquals(NanoClockFactory.Mode.Dummy, NanoClockFactory.getMode());
+    }
+
+    @Test
+    public void testModeIsMutable() {
+        assertEquals(NanoClockFactory.Mode.Dummy, NanoClockFactory.getMode());
+        NanoClockFactory.setMode(NanoClockFactory.Mode.System);
+        assertEquals(NanoClockFactory.Mode.System, NanoClockFactory.getMode());
+
+        NanoClockFactory.setMode(NanoClockFactory.Mode.Dummy);
+        assertEquals(NanoClockFactory.Mode.Dummy, NanoClockFactory.getMode());
+    }
+
+    @Test
+    public void testModeDeterminesGeneratedClockType() {
+        NanoClockFactory.setMode(NanoClockFactory.Mode.Dummy);
+        assertEquals(NanoClockFactory.Mode.Dummy, NanoClockFactory.getMode());
+        assertTrue("dummy", NanoClockFactory.createNanoClock() instanceof DummyNanoClock);
+        
+        NanoClockFactory.setMode(NanoClockFactory.Mode.System);
+        assertEquals(NanoClockFactory.Mode.System, NanoClockFactory.getMode());
+        assertTrue("system", NanoClockFactory.createNanoClock() instanceof SystemNanoClock);
+        
+        NanoClockFactory.setMode(NanoClockFactory.Mode.Dummy);
+        assertEquals(NanoClockFactory.Mode.Dummy, NanoClockFactory.getMode());
+        assertTrue("dummy again", NanoClockFactory.createNanoClock() instanceof DummyNanoClock);
+        
+        NanoClockFactory.setMode(NanoClockFactory.Mode.System);
+        assertEquals(NanoClockFactory.Mode.System, NanoClockFactory.getMode());
+        assertTrue("system", NanoClockFactory.createNanoClock() instanceof SystemNanoClock);
+
+        NanoClockFactory.setMode(NanoClockFactory.Mode.Dummy);
+        assertTrue("dummy again2", NanoClockFactory.createNanoClock() instanceof DummyNanoClock);
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/test/java/org/apache/logging/log4j/core/util/SystemNanoClockTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/SystemNanoClockTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/util/SystemNanoClockTest.java
new file mode 100644
index 0000000..9adea85
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/util/SystemNanoClockTest.java
@@ -0,0 +1,39 @@
+/*
+ * 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.util;
+
+import java.util.concurrent.TimeUnit;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Tests the SystemNanoClock.
+ */
+public class SystemNanoClockTest {
+
+    @Test
+    public void testReturnsSystemNanoTime() {
+        final NanoClock clock = new SystemNanoClock();
+        final long expected = System.nanoTime();
+        final long actual = clock.nanoTime();
+        assertTrue("smal difference", actual - expected < TimeUnit.SECONDS.toNanos(1));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/test/resources/NanoTimeToFileTest.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/NanoTimeToFileTest.xml b/log4j-core/src/test/resources/NanoTimeToFileTest.xml
new file mode 100644
index 0000000..3ce3b3c
--- /dev/null
+++ b/log4j-core/src/test/resources/NanoTimeToFileTest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration status="ERROR">
+  <Appenders>
+    <RandomAccessFile name="RandomAccessFile" fileName="target/NanoTimeToFileTest.log" 
+	    		immediateFlush="true" append="false">
+      <PatternLayout>
+        <Pattern>%N AND %nano AND %m%n</Pattern>
+      </PatternLayout>
+    </RandomAccessFile>
+  </Appenders>
+  
+  <Loggers>
+    <Root level="info" includeLocation="false">
+      <AppenderRef ref="RandomAccessFile"/>
+    </Root>
+  </Loggers>
+</Configuration>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/test/resources/log4j2-config.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/log4j2-config.xml b/log4j-core/src/test/resources/log4j2-config.xml
index e45158c..06b257d 100644
--- a/log4j-core/src/test/resources/log4j2-config.xml
+++ b/log4j-core/src/test/resources/log4j2-config.xml
@@ -22,7 +22,7 @@
       <PatternLayout pattern="%m%n"/>
     </Console>
     <List name="List2">
-      <PatternLayout pattern="${env:PATH} %m%n"/>
+      <PatternLayout pattern="%m%n"/>
     </List>
     <List name="List">
     </List>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeEvent.java
----------------------------------------------------------------------
diff --git a/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeEvent.java b/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeEvent.java
index b8d6e73..611f23f 100644
--- a/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeEvent.java
+++ b/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeEvent.java
@@ -266,6 +266,16 @@ public class FlumeEvent extends SimpleEvent implements LogEvent {
     }
 
     /**
+     * Returns the value of the running Java Virtual Machine's high-resolution time source when this event was created,
+     * or a dummy value if it is known that this value will not be used downstream.
+     * @return the event nanosecond timestamp.
+     */
+    @Override
+    public long getNanoTime() {
+        return event.getNanoTime();
+    }
+
+    /**
      * Returns the Throwable associated with the event, if any.
      * @return the Throwable.
      */

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 96542d6..6114e94 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -24,6 +24,9 @@
   </properties>
   <body>
     <release version="2.4" date="2015-MM-DD" description="GA Release 2.4">
+      <action issue="LOG4J2-1076" dev="rpopma" type="add">
+        Added support for system nanosecond time in pattern layout.
+      </action>
       <action issue="LOG4J2-1075" dev="rpopma" type="add">
         Added support for compressing to bzip2 format on file rollover.
       </action>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/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 1ef6121..a04921d 100644
--- a/src/site/xdoc/manual/layouts.xml.vm
+++ b/src/site/xdoc/manual/layouts.xml.vm
@@ -818,6 +818,15 @@ WARN  [main]: Message 2</pre>
             </tr>
             <tr>
               <td align="center">
+              <a name="NanoTime" />
+                <b>N</b><br />
+                <b>nano</b>
+              </td>
+              <td><p>Outputs the result of <code>System.nanoTime()</code> at the time the log event was created.</p>
+              </td>
+            </tr>
+            <tr>
+              <td align="center">
                 <b>p</b>|<b>level</b>{<em>level</em>=<em>label</em>, <em>level</em>=<em>label</em>, ...}
                 <b>p</b>|<b>level</b>{length=<em>n</em>}
                 <b>p</b>|<b>level</b>{lowerCase=<em>true</em>|<em>false</em>}


[2/2] logging-log4j2 git commit: LOG4J2-1076 Added support for system nanosecond time in pattern layout

Posted by rp...@apache.org.
LOG4J2-1076 Added support for system nanosecond time in pattern layout


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/7f075a71
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/7f075a71
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/7f075a71

Branch: refs/heads/master
Commit: 7f075a710230484cd7f9f3850b57d4cb7ee4ec9f
Parents: 8901ffc
Author: rpopma <rp...@apache.org>
Authored: Sun Jul 19 00:05:37 2015 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sun Jul 19 00:05:37 2015 +0900

----------------------------------------------------------------------
 .../logging/log4j/core/AbstractLogEvent.java    |   4 +
 .../org/apache/logging/log4j/core/LogEvent.java |   7 +
 .../logging/log4j/core/LoggerContext.java       |  12 +-
 .../db/jpa/AbstractLogEventWrapperEntity.java   |  10 +
 .../appender/db/jpa/BasicLogEventEntity.java    |  19 +-
 .../logging/log4j/core/async/AsyncLogger.java   |  28 ++-
 .../log4j/core/async/RingBufferLogEvent.java    |  35 +++-
 .../async/RingBufferLogEventTranslator.java     |  10 +-
 .../logging/log4j/core/impl/Log4jLogEvent.java  | 104 ++++++++--
 .../log4j/core/jackson/JsonConstants.java       |   1 +
 .../log4j/core/layout/JacksonFactory.java       |  13 ++
 .../core/pattern/NanoTimePatternConverter.java  |  57 +++++
 .../log4j/core/pattern/PatternParser.java       |  21 +-
 .../logging/log4j/core/util/DummyNanoClock.java |  48 +++++
 .../logging/log4j/core/util/NanoClock.java      |  30 +++
 .../log4j/core/util/NanoClockFactory.java       |  80 +++++++
 .../log4j/core/util/SystemNanoClock.java        |  33 +++
 log4j-core/src/main/resources/Log4j-events.xsd  |   1 +
 .../apache/logging/log4j/core/LogEventTest.java |  48 +++++
 .../core/appender/db/jpa/JpaH2AppenderTest.java |   2 +-
 .../db/jpa/JpaHyperSqlAppenderTest.java         |   2 +-
 .../core/appender/db/jpa/TestBaseEntity.java    |   7 +-
 .../log4j/core/async/AsyncLoggerTest.java       |   6 +
 .../core/async/AsyncLoggerTestNanoTime.java     |  92 ++++++++
 .../core/async/RingBufferLogEventTest.java      |  15 +-
 .../core/impl/Log4jLogEventNanoTimeTest.java    |  90 ++++++++
 .../log4j/core/impl/Log4jLogEventTest.java      | 208 +++++++++++++++++++
 .../pattern/NanoTimePatternConverterTest.java   |  39 ++++
 .../log4j/core/pattern/PatternParserTest.java   |  36 +++-
 .../log4j/core/util/DummyNanoClockTest.java     |  39 ++++
 .../log4j/core/util/NanoClockFactoryTest.java   |  65 ++++++
 .../log4j/core/util/SystemNanoClockTest.java    |  39 ++++
 .../src/test/resources/NanoTimeToFileTest.xml   |  17 ++
 log4j-core/src/test/resources/log4j2-config.xml |   2 +-
 .../log4j/flume/appender/FlumeEvent.java        |  10 +
 src/changes/changes.xml                         |   3 +
 src/site/xdoc/manual/layouts.xml.vm             |   9 +
 37 files changed, 1195 insertions(+), 47 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/main/java/org/apache/logging/log4j/core/AbstractLogEvent.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/AbstractLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/AbstractLogEvent.java
index ef5374a..cd1b4e9 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/AbstractLogEvent.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/AbstractLogEvent.java
@@ -117,4 +117,8 @@ public abstract class AbstractLogEvent implements LogEvent {
         // do nothing
     }
 
+    @Override
+    public long getNanoTime() {
+        return 0;
+    }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/main/java/org/apache/logging/log4j/core/LogEvent.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/LogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/LogEvent.java
index ca05766..e89f6e5 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/LogEvent.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/LogEvent.java
@@ -170,4 +170,11 @@ public interface LogEvent extends Serializable {
      */
     void setIncludeLocation(boolean locationRequired);
 
+    /**
+     * Returns the value of the running Java Virtual Machine's high-resolution time source when this event was created,
+     * or a dummy value if it is known that this value will not be used downstream.
+     * @return The value of the running Java Virtual Machine's high-resolution time source when this event was created.
+     * @since Log4J 2.4
+     */
+    long getNanoTime();
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
index 9072717..c61c764 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
@@ -29,6 +29,7 @@ import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 
 import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.core.async.AsyncLogger;
 import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.ConfigurationFactory;
 import org.apache.logging.log4j.core.config.ConfigurationListener;
@@ -36,15 +37,17 @@ import org.apache.logging.log4j.core.config.ConfigurationSource;
 import org.apache.logging.log4j.core.config.DefaultConfiguration;
 import org.apache.logging.log4j.core.config.NullConfiguration;
 import org.apache.logging.log4j.core.config.Reconfigurable;
+import org.apache.logging.log4j.core.impl.Log4jLogEvent;
 import org.apache.logging.log4j.core.jmx.Server;
 import org.apache.logging.log4j.core.util.Cancellable;
+import org.apache.logging.log4j.core.util.NanoClockFactory;
 import org.apache.logging.log4j.core.util.NetUtils;
 import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry;
 import org.apache.logging.log4j.message.MessageFactory;
 import org.apache.logging.log4j.spi.AbstractLogger;
 import org.apache.logging.log4j.spi.LoggerContextFactory;
 
-import static org.apache.logging.log4j.core.util.ShutdownCallbackRegistry.SHUTDOWN_HOOK_MARKER;
+import static org.apache.logging.log4j.core.util.ShutdownCallbackRegistry.*;
 
 /**
  * The LoggerContext is the anchor for the logging system. It maintains a list
@@ -374,6 +377,13 @@ public class LoggerContext extends AbstractLifeCycle implements org.apache.loggi
                 // LOG4J2-716: Android has no java.lang.management
                 LOGGER.error("Could not reconfigure JMX", t);
             }
+            Log4jLogEvent.setNanoClock(NanoClockFactory.createNanoClock());
+            try {
+                AsyncLogger.setNanoClock(NanoClockFactory.createNanoClock());
+            } catch (Throwable ignored) {
+                // LMAX Disruptor jar may not be in the classpath. Ignore this.
+                LOGGER.debug("Could not set AsyncLogger NanoClock. Ignoring: ", ignored);
+            }
             return prev;
         } finally {
             configLock.unlock();

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/AbstractLogEventWrapperEntity.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/AbstractLogEventWrapperEntity.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/AbstractLogEventWrapperEntity.java
index 9a84eee..07dec4e 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/AbstractLogEventWrapperEntity.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/AbstractLogEventWrapperEntity.java
@@ -172,6 +172,16 @@ public abstract class AbstractLogEventWrapperEntity implements LogEvent {
      * @param millis Ignored.
      */
     @SuppressWarnings("unused")
+    public void setNanoTime(final long nanoTime) {
+        // this entity is write-only
+    }
+
+    /**
+     * A no-op mutator to satisfy JPA requirements, as this entity is write-only.
+     *
+     * @param millis Ignored.
+     */
+    @SuppressWarnings("unused")
     public void setTimeMillis(final long millis) {
         // this entity is write-only
     }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/BasicLogEventEntity.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/BasicLogEventEntity.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/BasicLogEventEntity.java
index e7f46a2..a732e53 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/BasicLogEventEntity.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/BasicLogEventEntity.java
@@ -40,9 +40,9 @@ import org.apache.logging.log4j.message.Message;
 /**
  * Users of the JPA appender may want to extend this class instead of {@link AbstractLogEventWrapperEntity}. This class
  * implements all of the required mutator methods but does not implement a mutable entity ID property. In order to
- * create an entity based on this class, you need only create two constructors matching this class's
- * constructors, annotate the class {@link javax.persistence.Entity @Entity} and {@link javax.persistence.Table @Table},
- * and implement the fully mutable entity ID property annotated with {@link javax.persistence.Id @Id} and
+ * create an entity based on this class, you need only create two constructors matching this class's constructors,
+ * annotate the class {@link javax.persistence.Entity @Entity} and {@link javax.persistence.Table @Table}, and implement
+ * the fully mutable entity ID property annotated with {@link javax.persistence.Id @Id} and
  * {@link javax.persistence.GeneratedValue @GeneratedValue} to tell the JPA provider how to calculate an ID for new
  * events.<br>
  * <br>
@@ -73,7 +73,6 @@ public abstract class BasicLogEventEntity extends AbstractLogEventWrapperEntity
      * signature. The no-argument constructor is required for a standards-compliant JPA provider to accept this as an
      * entity.
      */
-    @SuppressWarnings("unused")
     public BasicLogEventEntity() {
         super();
     }
@@ -170,6 +169,18 @@ public abstract class BasicLogEventEntity extends AbstractLogEventWrapperEntity
     }
 
     /**
+     * Returns the value of the running Java Virtual Machine's high-resolution time source when this event was created,
+     * or a dummy value if it is known that this value will not be used downstream.
+     *
+     * @return the JVM nano time
+     */
+    @Override
+    @Basic
+    public long getNanoTime() {
+        return this.getWrappedEvent().getNanoTime();
+    }
+
+    /**
      * Gets the exception logged. Annotated with {@code @Convert(converter = ThrowableAttributeConverter.class)}.
      *
      * @return the exception logged.

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java
index 9230f5b..5518472 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java
@@ -17,6 +17,7 @@
 package org.apache.logging.log4j.core.async;
 
 import java.util.Map;
+import java.util.Objects;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
@@ -30,8 +31,10 @@ import org.apache.logging.log4j.core.impl.Log4jLogEvent;
 import org.apache.logging.log4j.core.jmx.RingBufferAdmin;
 import org.apache.logging.log4j.core.util.Clock;
 import org.apache.logging.log4j.core.util.ClockFactory;
+import org.apache.logging.log4j.core.util.DummyNanoClock;
 import org.apache.logging.log4j.core.util.Integers;
 import org.apache.logging.log4j.core.util.Loader;
+import org.apache.logging.log4j.core.util.NanoClock;
 import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.message.MessageFactory;
 import org.apache.logging.log4j.message.TimestampMessage;
@@ -112,6 +115,7 @@ public class AsyncLogger extends Logger {
     }
     private static volatile Disruptor<RingBufferLogEvent> disruptor;
     private static final Clock clock = ClockFactory.getClock();
+    private static volatile NanoClock nanoClock = new DummyNanoClock();
 
     private static final ExecutorService executor = Executors
             .newSingleThreadExecutor(new DaemonThreadFactory("AsyncLogger-"));
@@ -276,7 +280,9 @@ public class AsyncLogger extends Logger {
                 // CachedClock: 10% faster than system clock, smaller gaps
                 // LOG4J2-744 avoid calling clock altogether if message has the timestamp
                 message instanceof TimestampMessage ? ((TimestampMessage) message).getTimestamp() :
-                        clock.currentTimeMillis());
+                        clock.currentTimeMillis(), //
+                nanoClock.nanoTime() //
+        );
 
         // LOG4J2-639: catch NPE if disruptor field was set to null after our check above
         try {
@@ -346,4 +352,24 @@ public class AsyncLogger extends Logger {
     public static RingBufferAdmin createRingBufferAdmin(final String contextName) {
         return RingBufferAdmin.forAsyncLogger(disruptor.getRingBuffer(), contextName);
     }
+    
+    /**
+     * Returns the {@code NanoClock} to use for creating the nanoTime timestamp of log events.
+     * @return the {@code NanoClock} to use for creating the nanoTime timestamp of log events
+     */
+    public static NanoClock getNanoClock() {
+        return nanoClock;
+    }
+    
+    /**
+     * Sets the {@code NanoClock} to use for creating the nanoTime timestamp of log events.
+     * <p>
+     * FOR INTERNAL USE. This method may be called with a different {@code NanoClock} implementation when the
+     * configuration changes.
+     * 
+     * @param nanoClock the {@code NanoClock} to use for creating the nanoTime timestamp of log events
+     */
+    public static void setNanoClock(NanoClock nanoClock) {
+        AsyncLogger.nanoClock = Objects.requireNonNull(nanoClock, "NanoClock must be non-null");
+    }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
index 9644cfb..74feb32 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
@@ -70,11 +70,12 @@ public class RingBufferLogEvent implements LogEvent {
     private long currentTimeMillis;
     private boolean endOfBatch;
     private boolean includeLocation;
+    private long nanoTime;
 
     public void setValues(final AsyncLogger asyncLogger, final String loggerName, final Marker marker,
             final String fqcn, final Level level, final Message data, final Throwable throwable,
             final Map<String, String> map, final ContextStack contextStack, final String threadName,
-            final StackTraceElement location, final long currentTimeMillis) {
+            final StackTraceElement location, final long currentTimeMillis, final long nanoTime) {
         this.asyncLogger = asyncLogger;
         this.loggerName = loggerName;
         this.marker = marker;
@@ -88,6 +89,7 @@ public class RingBufferLogEvent implements LogEvent {
         this.threadName = threadName;
         this.location = location;
         this.currentTimeMillis = currentTimeMillis;
+        this.nanoTime = nanoTime;
     }
 
     /**
@@ -202,6 +204,11 @@ public class RingBufferLogEvent implements LogEvent {
     public long getTimeMillis() {
         return currentTimeMillis;
     }
+    
+    @Override
+    public long getNanoTime() {
+        return nanoTime;
+    }
 
     /**
      * Merges the contents of the specified map into the contextMap, after replacing any variables in the property
@@ -246,7 +253,8 @@ public class RingBufferLogEvent implements LogEvent {
                 null, // contextStack
                 null, // threadName
                 null, // location
-                0 // currentTimeMillis
+                0, // currentTimeMillis
+                0 // nanoTime
         );
     }
 
@@ -264,4 +272,27 @@ public class RingBufferLogEvent implements LogEvent {
         final LogEvent result = new Log4jLogEvent.Builder(this).build();
         return result;
     }
+
+    /**
+     * Initializes the specified {@code Log4jLogEvent.Builder} from this {@code RingBufferLogEvent}.
+     * @param builder the builder whose fields to populate
+     */
+    public void initializeBuilder(Log4jLogEvent.Builder builder) {
+        builder.setContextMap(contextMap) //
+                .setContextStack(contextStack) //
+                .setEndOfBatch(endOfBatch) //
+                .setIncludeLocation(includeLocation) //
+                .setLevel(getLevel()) // ensure non-null
+                .setLoggerFqcn(fqcn) //
+                .setLoggerName(loggerName) //
+                .setMarker(marker) //
+                .setMessage(getMessage()) // ensure non-null
+                .setNanoTime(nanoTime) //
+                .setSource(location) //
+                .setThreadName(threadName) //
+                .setThrown(getThrown()) // may deserialize from thrownProxy
+                .setThrownProxy(thrownProxy) // avoid unnecessarily creating thrownProxy
+                .setTimeMillis(currentTimeMillis) //
+                ;        
+    }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventTranslator.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventTranslator.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventTranslator.java
index 20e89b0..d82bd5d 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventTranslator.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventTranslator.java
@@ -46,13 +46,14 @@ public class RingBufferLogEventTranslator implements
     private String threadName;
     private StackTraceElement location;
     private long currentTimeMillis;
+    private long nanoTime;
 
     // @Override
     @Override
     public void translateTo(final RingBufferLogEvent event, final long sequence) {
         event.setValues(asyncLogger, loggerName, marker, fqcn, level, message,
                 thrown, contextMap, contextStack, threadName, location,
-                currentTimeMillis);
+                currentTimeMillis, nanoTime);
         clear();
     }
 
@@ -72,7 +73,8 @@ public class RingBufferLogEventTranslator implements
                 null, // contextStack
                 null, // threadName
                 null, // location
-                0 // currentTimeMillis
+                0, // currentTimeMillis
+                0 // nanoTime
         );
     }
 
@@ -80,7 +82,7 @@ public class RingBufferLogEventTranslator implements
             final Marker marker, final String fqcn, final Level level, final Message message,
             final Throwable thrown, final Map<String, String> contextMap,
             final ContextStack contextStack, final String threadName,
-            final StackTraceElement location, final long currentTimeMillis) {
+            final StackTraceElement location, final long currentTimeMillis, final long nanoTime) {
         this.asyncLogger = asyncLogger;
         this.loggerName = loggerName;
         this.marker = marker;
@@ -93,6 +95,6 @@ public class RingBufferLogEventTranslator implements
         this.threadName = threadName;
         this.location = location;
         this.currentTimeMillis = currentTimeMillis;
+        this.nanoTime = nanoTime;
     }
-
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
index 00b8b2d..c5dd320 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
@@ -29,9 +29,12 @@ import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.ThreadContext;
 import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.async.RingBufferLogEvent;
 import org.apache.logging.log4j.core.config.Property;
 import org.apache.logging.log4j.core.util.Clock;
 import org.apache.logging.log4j.core.util.ClockFactory;
+import org.apache.logging.log4j.core.util.DummyNanoClock;
+import org.apache.logging.log4j.core.util.NanoClock;
 import org.apache.logging.log4j.message.LoggerNameAwareMessage;
 import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.message.TimestampMessage;
@@ -44,6 +47,7 @@ public class Log4jLogEvent implements LogEvent {
 
     private static final long serialVersionUID = -1351367343806656055L;
     private static final Clock clock = ClockFactory.getClock();
+    private static volatile NanoClock nanoClock = new DummyNanoClock();
     private final String loggerFqcn;
     private final Marker marker;
     private final Level level;
@@ -58,6 +62,8 @@ public class Log4jLogEvent implements LogEvent {
     private StackTraceElement source;
     private boolean includeLocation;
     private boolean endOfBatch = false;
+    /** @since Log4J 2.4 */
+    private transient final long nanoTime;
 
     public static class Builder implements org.apache.logging.log4j.core.util.Builder<LogEvent> {
 
@@ -75,12 +81,18 @@ public class Log4jLogEvent implements LogEvent {
         private StackTraceElement source;
         private boolean includeLocation;
         private boolean endOfBatch = false;
+        private long nanoTime;
         
         public Builder() {
         }
         
         public Builder(LogEvent other) {
             Objects.requireNonNull(other);
+            if (other instanceof RingBufferLogEvent) {
+                RingBufferLogEvent evt = (RingBufferLogEvent) other;
+                evt.initializeBuilder(this);
+                return;
+            }
             this.loggerFqcn = other.getLoggerFqcn();
             this.marker = other.getMarker();
             this.level = other.getLevel();
@@ -88,15 +100,23 @@ public class Log4jLogEvent implements LogEvent {
             this.message = other.getMessage();
             this.timeMillis = other.getTimeMillis();
             this.thrown = other.getThrown();
-            // avoid creating thrownProxy until necessary
-            this.thrownProxy = other instanceof Log4jLogEvent ? ((Log4jLogEvent) other).thrownProxy 
-                    : other.getThrownProxy();
             this.contextMap = other.getContextMap();
             this.contextStack = other.getContextStack();
-            this.source = other.getSource();
-            this.threadName = other.getThreadName();
             this.includeLocation = other.isIncludeLocation();
             this.endOfBatch = other.isEndOfBatch();
+            this.nanoTime = other.getNanoTime();
+            
+            // Avoid unnecessarily initializing thrownProxy, threadName and source if possible
+            if (other instanceof Log4jLogEvent) {
+                Log4jLogEvent evt = (Log4jLogEvent) other;
+                this.thrownProxy = evt.thrownProxy;
+                this.source = evt.source;
+                this.threadName = evt.threadName;
+            } else {
+                this.thrownProxy = other.getThrownProxy();
+                this.source = other.getSource();
+                this.threadName = other.getThreadName();
+            }
         }
 
         public Builder setLevel(final Level level) {
@@ -169,10 +189,21 @@ public class Log4jLogEvent implements LogEvent {
             return this;
         }
 
+        /**
+         * Sets the nano time for the event.
+         * @param nanoTime The value of the running Java Virtual Machine's high-resolution time source when the event
+         *          was created.
+         * @return this builder
+         */
+        public Builder setNanoTime(long nanoTime) {
+            this.nanoTime = nanoTime;
+            return this;
+        }
+
         @Override
         public Log4jLogEvent build() {
             final Log4jLogEvent result = new Log4jLogEvent(loggerName, marker, loggerFqcn, level, message, thrown, 
-                    thrownProxy, contextMap, contextStack, threadName, source, timeMillis);
+                    thrownProxy, contextMap, contextStack, threadName, source, timeMillis, nanoTime);
             result.setIncludeLocation(includeLocation);
             result.setEndOfBatch(endOfBatch);
             return result;
@@ -196,7 +227,8 @@ public class Log4jLogEvent implements LogEvent {
     }
 
     public Log4jLogEvent() {
-        this(clock.currentTimeMillis());
+        this(Strings.EMPTY, null, Strings.EMPTY, null, null, (Throwable) null, null, null, null, null, null, 
+                clock.currentTimeMillis(), nanoClock.nanoTime());
     }
 
     /**
@@ -204,7 +236,8 @@ public class Log4jLogEvent implements LogEvent {
     * @deprecated use {@link Log4jLogEvent.Builder} instead. This constructor will be removed in an upcoming release.
     */
    public Log4jLogEvent(final long timestamp) {
-       this(Strings.EMPTY, null, Strings.EMPTY, null, null, (Throwable) null, null, null, null, null, null, timestamp);
+       this(Strings.EMPTY, null, Strings.EMPTY, null, null, (Throwable) null, null, null, null, null, null, timestamp,
+               nanoClock.nanoTime());
    }
 
    /**
@@ -232,8 +265,7 @@ public class Log4jLogEvent implements LogEvent {
     * @param properties properties to add to the event.
     * @param t A Throwable or null.
     */
-   // This constructor is called from DefaultLogEventFactory and is in the hot path.
-   // Do not replace this constructor with a Builder.
+   // This constructor is called from LogEventFactories.
    public Log4jLogEvent(final String loggerName, final Marker marker, final String loggerFQCN, final Level level,
                         final Message message, final List<Property> properties, final Throwable t) {
        this(loggerName, marker, loggerFQCN, level, message, t, null,
@@ -243,7 +275,8 @@ public class Log4jLogEvent implements LogEvent {
            // LOG4J2-628 use log4j.Clock for timestamps
            // LOG4J2-744 unless TimestampMessage already has one
            message instanceof TimestampMessage ? ((TimestampMessage) message).getTimestamp() :
-               clock.currentTimeMillis());
+               clock.currentTimeMillis(),
+           nanoClock.nanoTime());
    }
 
    /**
@@ -266,7 +299,7 @@ public class Log4jLogEvent implements LogEvent {
                         final ThreadContext.ContextStack ndc, final String threadName,
                         final StackTraceElement location, final long timestampMillis) {
        this(loggerName, marker, loggerFQCN, level, message, t, null, mdc, ndc, threadName,
-               location, timestampMillis);
+               location, timestampMillis, nanoClock.nanoTime());
    }
 
    /**
@@ -292,7 +325,7 @@ public class Log4jLogEvent implements LogEvent {
                                             final String threadName, final StackTraceElement location,
                                             final long timestamp) {
         final Log4jLogEvent result = new Log4jLogEvent(loggerName, marker, loggerFQCN, level, message, thrown, 
-                thrownProxy, mdc, ndc, threadName, location, timestamp);
+                thrownProxy, mdc, ndc, threadName, location, timestamp, nanoClock.nanoTime());
         return result;
     }
 
@@ -310,11 +343,13 @@ public class Log4jLogEvent implements LogEvent {
      * @param threadName The name of the thread.
      * @param source The locations of the caller.
      * @param timestamp The timestamp of the event.
+     * @param nanoTime The value of the running Java Virtual Machine's high-resolution time source when the event was
+     *          created.
      */
     private Log4jLogEvent(final String loggerName, final Marker marker, final String loggerFQCN, final Level level,
             final Message message, final Throwable thrown, final ThrowableProxy thrownProxy, 
             final Map<String, String> contextMap, final ThreadContext.ContextStack contextStack, 
-            final String threadName, final StackTraceElement source, final long timestamp) {
+            final String threadName, final StackTraceElement source, final long timestampMillis, final long nanoTime) {
         this.loggerName = loggerName;
         this.marker = marker;
         this.loggerFqcn = loggerFQCN;
@@ -324,12 +359,15 @@ public class Log4jLogEvent implements LogEvent {
         this.thrownProxy = thrownProxy;
         this.contextMap = contextMap == null ? ThreadContext.EMPTY_MAP : contextMap;
         this.contextStack = contextStack == null ? ThreadContext.EMPTY_STACK : contextStack;
-        this.timeMillis = message instanceof TimestampMessage ? ((TimestampMessage) message).getTimestamp() : timestamp;
+        this.timeMillis = message instanceof TimestampMessage
+                ? ((TimestampMessage) message).getTimestamp()
+                : timestampMillis;
         this.threadName = threadName;
         this.source = source;
         if (message != null && message instanceof LoggerNameAwareMessage) {
             ((LoggerNameAwareMessage) message).setLoggerName(loggerName);
         }
+        this.nanoTime = nanoTime;
     }
 
     private static Map<String, String> createMap(final List<Property> properties) {
@@ -349,6 +387,26 @@ public class Log4jLogEvent implements LogEvent {
         }
         return Collections.unmodifiableMap(map);
     }
+    
+    /**
+     * Returns the {@code NanoClock} to use for creating the nanoTime timestamp of log events.
+     * @return the {@code NanoClock} to use for creating the nanoTime timestamp of log events
+     */
+    public static NanoClock getNanoClock() {
+        return nanoClock;
+    }
+    
+    /**
+     * Sets the {@code NanoClock} to use for creating the nanoTime timestamp of log events.
+     * <p>
+     * FOR INTERNAL USE. This method may be called with a different {@code NanoClock} implementation when the
+     * configuration changes.
+     * 
+     * @param nanoClock the {@code NanoClock} to use for creating the nanoTime timestamp of log events
+     */
+    public static void setNanoClock(NanoClock nanoClock) {
+        Log4jLogEvent.nanoClock = Objects.requireNonNull(nanoClock, "NanoClock must be non-null");
+    }
 
     /**
      * Returns the logging Level.
@@ -509,6 +567,11 @@ public class Log4jLogEvent implements LogEvent {
         this.endOfBatch = endOfBatch;
     }
 
+    @Override
+    public long getNanoTime() {
+        return nanoTime;
+    }
+
     /**
      * Creates a LogEventProxy that can be serialized.
      * @return a LogEventProxy.
@@ -535,7 +598,7 @@ public class Log4jLogEvent implements LogEvent {
             final Log4jLogEvent result = new Log4jLogEvent(proxy.loggerName, proxy.marker,
                     proxy.loggerFQCN, proxy.level, proxy.message,
                     proxy.thrown, proxy.thrownProxy, proxy.contextMap, proxy.contextStack, proxy.threadName,
-                    proxy.source, proxy.timeMillis);
+                    proxy.source, proxy.timeMillis, proxy.nanoTime);
             result.setEndOfBatch(proxy.isEndOfBatch);
             result.setIncludeLocation(proxy.isLocationRequired);
             return result;
@@ -577,6 +640,9 @@ public class Log4jLogEvent implements LogEvent {
         if (timeMillis != that.timeMillis) {
             return false;
         }
+        if (nanoTime != that.nanoTime) {
+            return false;
+        }
         if (loggerFqcn != null ? !loggerFqcn.equals(that.loggerFqcn) : that.loggerFqcn != null) {
             return false;
         }
@@ -622,6 +688,7 @@ public class Log4jLogEvent implements LogEvent {
         result = 31 * result + loggerName.hashCode();
         result = 31 * result + message.hashCode();
         result = 31 * result + (int) (timeMillis ^ (timeMillis >>> 32));
+        result = 31 * result + (int) (nanoTime ^ (nanoTime >>> 32));
         result = 31 * result + (thrown != null ? thrown.hashCode() : 0);
         result = 31 * result + (thrownProxy != null ? thrownProxy.hashCode() : 0);
         result = 31 * result + (contextMap != null ? contextMap.hashCode() : 0);
@@ -653,6 +720,8 @@ public class Log4jLogEvent implements LogEvent {
         private final StackTraceElement source;
         private final boolean isLocationRequired;
         private final boolean isEndOfBatch;
+        /** @since Log4J 2.4 */
+        private final transient long nanoTime;
 
         public LogEventProxy(final Log4jLogEvent event, final boolean includeLocation) {
             this.loggerFQCN = event.loggerFqcn;
@@ -669,6 +738,7 @@ public class Log4jLogEvent implements LogEvent {
             this.threadName = event.getThreadName();
             this.isLocationRequired = includeLocation;
             this.isEndOfBatch = event.endOfBatch;
+            this.nanoTime = event.nanoTime;
         }
 
         /**
@@ -677,7 +747,7 @@ public class Log4jLogEvent implements LogEvent {
          */
         protected Object readResolve() {
             final Log4jLogEvent result = new Log4jLogEvent(loggerName, marker, loggerFQCN, level, message, thrown,
-                    thrownProxy, contextMap, contextStack, threadName, source, timeMillis);
+                    thrownProxy, contextMap, contextStack, threadName, source, timeMillis, nanoTime);
             result.setEndOfBatch(isEndOfBatch);
             result.setIncludeLocation(isLocationRequired);
             return result;

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/JsonConstants.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/JsonConstants.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/JsonConstants.java
index d307f7f..8e9ed2c 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/JsonConstants.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/JsonConstants.java
@@ -30,4 +30,5 @@ public final class JsonConstants {
     public static final String ELT_THROWN = "thrown";
     public static final String ELT_MESSAGE = "message";
     public static final String ELT_EXTENDED_STACK_TRACE = "extendedStackTrace";
+    public static final String ELT_NANO_TIME = "nanoTime";
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/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 8ee4aae..537b634 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
@@ -49,6 +49,11 @@ abstract class JacksonFactory {
         }
 
         @Override
+        protected String getPropertNameForNanoTime() {
+            return JsonConstants.ELT_NANO_TIME;
+        }
+
+        @Override
         protected PrettyPrinter newCompactPrinter() {
             return new MinimalPrettyPrinter();
         }
@@ -77,6 +82,11 @@ abstract class JacksonFactory {
         }
 
         @Override
+        protected String getPropertNameForNanoTime() {
+            return JsonConstants.ELT_NANO_TIME;
+        }
+
+        @Override
         protected PrettyPrinter newCompactPrinter() {
             // Yes, null is the proper answer.
             return null;
@@ -96,6 +106,8 @@ abstract class JacksonFactory {
     abstract protected String getPropertNameForContextMap();
 
     abstract protected String getPropertNameForSource();
+    
+    abstract protected String getPropertNameForNanoTime();
 
     abstract protected PrettyPrinter newCompactPrinter();
 
@@ -112,6 +124,7 @@ abstract class JacksonFactory {
         if (!properties) {
             except.add(this.getPropertNameForContextMap());
         }
+        except.add(this.getPropertNameForNanoTime());
         filters.addFilter(Log4jLogEvent.class.getName(), SimpleBeanPropertyFilter.serializeAllExcept(except));
         final ObjectWriter writer = this.newObjectMapper().writer(compact ? this.newCompactPrinter() : this.newPrettyPrinter());
         return writer.with(filters);

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/NanoTimePatternConverter.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/NanoTimePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/NanoTimePatternConverter.java
new file mode 100644
index 0000000..2bee187
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/NanoTimePatternConverter.java
@@ -0,0 +1,57 @@
+/*
+ * 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.pattern;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+
+/**
+ * Converts and formats the event's nanoTime in a StringBuilder.
+ */
+@Plugin(name = "NanoTimePatternConverter", category = PatternConverter.CATEGORY)
+@ConverterKeys({ "N", "nano" })
+public final class NanoTimePatternConverter extends LogEventPatternConverter {
+
+    /**
+     * Obtains an instance of pattern converter.
+     *
+     * @param options
+     *            options, may be null.
+     * @return instance of pattern converter.
+     */
+    public static NanoTimePatternConverter newInstance(final String[] options) {
+        return new NanoTimePatternConverter(options);
+    }
+
+    /**
+     * Private constructor.
+     *
+     * @param options
+     *            options, may be null.
+     */
+    private NanoTimePatternConverter(final String[] options) {
+        super("Nanotime", "nanotime");
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void format(final LogEvent event, final StringBuilder output) {
+        output.append(event.getNanoTime());
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/PatternParser.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/PatternParser.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/PatternParser.java
index 28d4180..08b66db 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/PatternParser.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/PatternParser.java
@@ -16,13 +16,6 @@
  */
 package org.apache.logging.log4j.core.pattern;
 
-import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
-import org.apache.logging.log4j.core.config.plugins.util.PluginType;
-import org.apache.logging.log4j.status.StatusLogger;
-import org.apache.logging.log4j.util.Strings;
-
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
@@ -32,6 +25,14 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
+import org.apache.logging.log4j.core.config.plugins.util.PluginType;
+import org.apache.logging.log4j.core.util.NanoClockFactory;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.Strings;
+
 /**
  * Most of the work of the {@link org.apache.logging.log4j.core.layout.PatternLayout} class is delegated to the
  * PatternParser class.
@@ -172,7 +173,13 @@ public final class PatternParser {
         final Iterator<FormattingInfo> fieldIter = fields.iterator();
         boolean handlesThrowable = false;
 
+        NanoClockFactory.setMode(NanoClockFactory.Mode.Dummy); // LOG4J2-1074 use dummy clock by default
         for (final PatternConverter converter : converters) {
+            if (converter instanceof NanoTimePatternConverter) {
+                // LOG4J2-1074 Switch to actual clock if nanosecond timestamps are required in config.
+                // LoggerContext will notify known NanoClockFactory users that the configuration has changed.
+                NanoClockFactory.setMode(NanoClockFactory.Mode.System);
+            }
             LogEventPatternConverter pc;
             if (converter instanceof LogEventPatternConverter) {
                 pc = (LogEventPatternConverter) converter;

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/main/java/org/apache/logging/log4j/core/util/DummyNanoClock.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/DummyNanoClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/DummyNanoClock.java
new file mode 100644
index 0000000..8200c38
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/DummyNanoClock.java
@@ -0,0 +1,48 @@
+/*
+ * 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.util;
+
+/**
+ * Implementation of the {@code NanoClock} interface that always returns a fixed value.
+ */
+public final class DummyNanoClock implements NanoClock {
+
+    private final long fixedNanoTime;
+
+    public DummyNanoClock() {
+        this(0L);
+    }
+
+    /**
+     * Constructs a new DummyNanoClock with the specified value to return.
+     * @param fixedNanoTime the value to return from {@link #nanoTime()}.
+     */
+    public DummyNanoClock(long fixedNanoTime) {
+        this.fixedNanoTime = fixedNanoTime;
+    }
+
+    /**
+     * Returns the constructor value.
+     * 
+     * @return the constructor value
+     */
+    @Override
+    public long nanoTime() {
+        return fixedNanoTime;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/main/java/org/apache/logging/log4j/core/util/NanoClock.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/NanoClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/NanoClock.java
new file mode 100644
index 0000000..8fe8bf8
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/NanoClock.java
@@ -0,0 +1,30 @@
+/*
+ * 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.util;
+
+/**
+ * Provides the high-resolution time stamp used in log events.
+ */
+public interface NanoClock {
+    /**
+     * Returns the current value of the running Java Virtual Machine's high-resolution time source, in nanoseconds.
+     *
+     * @return the current value of the running Java Virtual Machine's high-resolution time source, in nanoseconds
+     */
+    long nanoTime();
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/main/java/org/apache/logging/log4j/core/util/NanoClockFactory.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/NanoClockFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/NanoClockFactory.java
new file mode 100644
index 0000000..73e3be8
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/NanoClockFactory.java
@@ -0,0 +1,80 @@
+/*
+ * 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.util;
+
+import java.util.Objects;
+
+/**
+ * Creates the appropriate {@link NanoClock} instance for the current configuration.
+ */
+public class NanoClockFactory {
+
+    /**
+     * Enum over the different kinds of nano clocks this factory can create.
+     */
+    public static enum Mode {
+        /**
+         * Creates dummy nano clocks that always return a fixed value.
+         */
+        Dummy {
+            public NanoClock createNanoClock() {
+                return new DummyNanoClock();
+            }
+        },
+        /**
+         * Creates real nano clocks which call {{System.nanoTime()}}.
+         */
+        System  {
+            public NanoClock createNanoClock() {
+                return new SystemNanoClock();
+            }
+        },
+        ;
+        
+        public abstract NanoClock createNanoClock();
+    }
+    
+    private static volatile Mode mode = Mode.Dummy;
+    
+    /**
+     * Returns a new {@code NanoClock} determined by the mode of this factory.
+     * 
+     * @return the appropriate {@code NanoClock} for the factory mode
+     */
+    public static NanoClock createNanoClock() {
+        return mode.createNanoClock();
+    }
+    
+    /**
+     * Returns the factory mode.
+     * 
+     * @return the factory mode that determines which kind of nano clocks this factory creates
+     */
+    public static Mode getMode() {
+        return mode;
+    }
+    
+    /**
+     * Sets the factory mode.
+     * 
+     * @param mode the factory mode that determines which kind of nano clocks this factory creates
+     */
+    public static void setMode(Mode mode) {
+        NanoClockFactory.mode = Objects.requireNonNull(mode, "mode must be non-null");
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/main/java/org/apache/logging/log4j/core/util/SystemNanoClock.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/SystemNanoClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/SystemNanoClock.java
new file mode 100644
index 0000000..9310e6c
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/SystemNanoClock.java
@@ -0,0 +1,33 @@
+/*
+ * 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.util;
+
+/**
+ * Implementation of the {@code NanoClock} interface that returns the system nano time.
+ */
+public final class SystemNanoClock implements NanoClock {
+
+    /**
+     * Returns the system high-resolution time.
+     * @return the result of calling {@code System.nanoTime()}
+     */
+    @Override
+    public long nanoTime() {
+        return System.nanoTime();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/main/resources/Log4j-events.xsd
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/resources/Log4j-events.xsd b/log4j-core/src/main/resources/Log4j-events.xsd
index 6e18154..153302a 100644
--- a/log4j-core/src/main/resources/Log4j-events.xsd
+++ b/log4j-core/src/main/resources/Log4j-events.xsd
@@ -56,6 +56,7 @@
                         </xs:sequence>
                         <xs:attribute name="logger" type="xs:string" use="required"/>
                         <xs:attribute name="timestamp" type="xs:long" use="required"/>
+                        <xs:attribute name="nanoTime" type="xs:long" use="optional"/>
                         <xs:attribute name="level" type="log4j:LevelEnum" use="required"/>
                         <xs:attribute name="thread" type="xs:string" use="required"/>
                     </xs:complexType>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/test/java/org/apache/logging/log4j/core/LogEventTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/LogEventTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/LogEventTest.java
index 8ba225b..4c0b85b 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/LogEventTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/LogEventTest.java
@@ -72,6 +72,54 @@ public class LogEventTest {
         }
     }
 
+    @Test
+    public void testNanoTimeIsNotSerialized1() throws Exception {
+        final LogEvent event1 = Log4jLogEvent.newBuilder() //
+                .setLoggerName(this.getClass().getName()) //
+                .setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
+                .setLevel(Level.INFO) //
+                .setMessage(new SimpleMessage("Hello, world!")) //
+                .setThreadName("this must be initialized or the test fails") //
+                .setNanoTime(12345678L) //
+                .build();
+        final LogEvent copy = new Log4jLogEvent.Builder(event1).build();
+
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        final ObjectOutputStream oos = new ObjectOutputStream(baos);
+        oos.writeObject(event1);
+
+        final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+        final ObjectInputStream ois = new ObjectInputStream(bais);
+        
+        LogEvent actual = (LogEvent) ois.readObject();
+        assertNotEquals("Different event: nanoTime", copy, actual);
+        assertNotEquals("Different nanoTime", copy.getNanoTime(), actual.getNanoTime());
+        assertEquals("deserialized nanoTime is zero", 0, actual.getNanoTime());
+    }
+
+    @Test
+    public void testNanoTimeIsNotSerialized2() throws Exception {
+        final LogEvent event1 = Log4jLogEvent.newBuilder() //
+                .setLoggerName(this.getClass().getName()) //
+                .setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
+                .setLevel(Level.INFO) //
+                .setMessage(new SimpleMessage("Hello, world!")) //
+                .setThreadName("this must be initialized or the test fails") //
+                .setNanoTime(0) //
+                .build();
+        final LogEvent event2 = new Log4jLogEvent.Builder(event1).build();
+
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        final ObjectOutputStream oos = new ObjectOutputStream(baos);
+        oos.writeObject(event1);
+
+        final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+        final ObjectInputStream ois = new ObjectInputStream(bais);
+        
+        LogEvent actual = (LogEvent) ois.readObject();
+        assertEquals("both zero nanoTime", event2, actual);
+    }
+
     public void testEquals() {
         final LogEvent event1 = Log4jLogEvent.newBuilder() //
                 .setLoggerName(this.getClass().getName()) //

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/JpaH2AppenderTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/JpaH2AppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/JpaH2AppenderTest.java
index f71fdc6..c4b9ae7 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/JpaH2AppenderTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/JpaH2AppenderTest.java
@@ -44,7 +44,7 @@ public class JpaH2AppenderTest extends AbstractJpaAppenderTest {
 
         statement = connection.createStatement();
         statement.executeUpdate("CREATE TABLE jpaBasicLogEntry ( " +
-                "id INTEGER IDENTITY, timemillis BIGINT, level NVARCHAR(10), loggerName NVARCHAR(255), " +
+                "id INTEGER IDENTITY, timemillis BIGINT, nanoTime BIGINT, level NVARCHAR(10), loggerName NVARCHAR(255), " +
                 "message NVARCHAR(1024), thrown NVARCHAR(1048576), contextMapJson NVARCHAR(1048576)," +
                 "loggerFQCN NVARCHAR(1024), contextStack NVARCHAR(1048576), marker NVARCHAR(255), source NVARCHAR(2048)," +
                 "threadName NVARCHAR(255)" +

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/JpaHyperSqlAppenderTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/JpaHyperSqlAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/JpaHyperSqlAppenderTest.java
index 39c407c..7ef8a24 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/JpaHyperSqlAppenderTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/JpaHyperSqlAppenderTest.java
@@ -48,7 +48,7 @@ public class JpaHyperSqlAppenderTest extends AbstractJpaAppenderTest {
 
         statement = connection.createStatement();
         statement.executeUpdate("CREATE TABLE jpaBasicLogEntry ( " +
-                "id INTEGER IDENTITY, timemillis BIGINT, level VARCHAR(10), loggerName VARCHAR(255), " +
+                "id INTEGER IDENTITY, timemillis BIGINT, nanoTime BIGINT, level VARCHAR(10), loggerName VARCHAR(255), " +
                 "message VARCHAR(1024), thrown VARCHAR(1048576), contextMapJson VARCHAR(1048576)," +
                 "loggerFQCN VARCHAR(1024), contextStack VARCHAR(1048576), marker VARCHAR(255), source VARCHAR(2048)," +
                 "threadName VARCHAR(255)" +

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/TestBaseEntity.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/TestBaseEntity.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/TestBaseEntity.java
index 51ee918..e70cdb9 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/TestBaseEntity.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/TestBaseEntity.java
@@ -43,7 +43,6 @@ import org.apache.logging.log4j.message.Message;
 
 @Entity
 @Table(name = "jpaBaseLogEntry")
-@SuppressWarnings("unused")
 public class TestBaseEntity extends AbstractLogEventWrapperEntity {
     private static final long serialVersionUID = 1L;
 
@@ -124,6 +123,12 @@ public class TestBaseEntity extends AbstractLogEventWrapperEntity {
     }
 
     @Override
+    @Transient
+    public long getNanoTime() {
+        return this.getWrappedEvent().getNanoTime();
+    }
+
+    @Override
     @Convert(converter = ThrowableAttributeConverter.class)
     @Column(name = "exception")
     public Throwable getThrown() {

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTest.java
index b7f1842..ad60edb 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTest.java
@@ -25,6 +25,7 @@ import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.CoreLoggerContexts;
 import org.apache.logging.log4j.core.config.ConfigurationFactory;
 import org.apache.logging.log4j.core.util.Constants;
+import org.apache.logging.log4j.core.util.DummyNanoClock;
 import org.apache.logging.log4j.util.Strings;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
@@ -67,5 +68,10 @@ public class AsyncLoggerTest {
         final String location = "testAsyncLogWritesToLog";
         assertTrue("no location", !line1.contains(location));
     }
+    
+    @Test
+    public void testNanoClockInitiallyDummy() {
+        assertTrue(AsyncLogger.getNanoClock() instanceof DummyNanoClock);
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTestNanoTime.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTestNanoTime.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTestNanoTime.java
new file mode 100644
index 0000000..0288f85
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTestNanoTime.java
@@ -0,0 +1,92 @@
+/*
+ * 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.async;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.CoreLoggerContexts;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.util.Constants;
+import org.apache.logging.log4j.core.util.DummyNanoClock;
+import org.apache.logging.log4j.core.util.SystemNanoClock;
+import org.apache.logging.log4j.util.Strings;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class AsyncLoggerTestNanoTime {
+
+    @BeforeClass
+    public static void beforeClass() {
+        System.setProperty(Constants.LOG4J_CONTEXT_SELECTOR,
+                AsyncLoggerContextSelector.class.getName());
+        System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY,
+                "NanoTimeToFileTest.xml");
+    }
+
+    @AfterClass
+    public static void afterClass() {
+        System.setProperty(Constants.LOG4J_CONTEXT_SELECTOR, Strings.EMPTY);
+    }
+
+    @Test
+    public void testAsyncLogUsesNanoTimeClock() throws Exception {
+        final File file = new File("target", "NanoTimeToFileTest.log");
+        // System.out.println(f.getAbsolutePath());
+        file.delete();
+        final Logger log = LogManager.getLogger("com.foo.Bar");
+        final long before = System.nanoTime();
+        log.info("Use actual System.nanoTime()");
+        assertTrue("using SystemNanoClock", AsyncLogger.getNanoClock() instanceof SystemNanoClock);
+
+        final long DUMMYNANOTIME = 123;
+        AsyncLogger.setNanoClock(new DummyNanoClock(DUMMYNANOTIME));
+        log.info("Use dummy nano clock");
+        assertTrue("using SystemNanoClock", AsyncLogger.getNanoClock() instanceof DummyNanoClock);
+        
+        CoreLoggerContexts.stopLoggerContext(file); // stop async thread
+
+        final BufferedReader reader = new BufferedReader(new FileReader(file));
+        final String line1 = reader.readLine();
+        final String line2 = reader.readLine();
+        // System.out.println(line1);
+        // System.out.println(line2);
+        reader.close();
+        file.delete();
+
+        assertNotNull("line1", line1);
+        assertNotNull("line2", line2);
+        final String[] line1Parts = line1.split(" AND ");
+        assertEquals("Use actual System.nanoTime()", line1Parts[2]);
+        assertEquals(line1Parts[0], line1Parts[1]);
+        long loggedNanoTime = Long.parseLong(line1Parts[0]);
+        assertTrue("used system nano time", loggedNanoTime - before < TimeUnit.SECONDS.toNanos(1));
+        
+        final String[] line2Parts = line2.split(" AND ");
+        assertEquals("Use dummy nano clock", line2Parts[2]);
+        assertEquals(String.valueOf(DUMMYNANOTIME), line2Parts[0]);
+        assertEquals(String.valueOf(DUMMYNANOTIME), line2Parts[1]);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java
index 64eb873..2da7b11 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java
@@ -58,8 +58,9 @@ public class RingBufferLogEventTest {
         final String threadName = null;
         final StackTraceElement location = null;
         final long currentTimeMillis = 0;
+        final long nanoTime = 1;
         evt.setValues(null, loggerName, marker, fqcn, level, data, t, map,
-                contextStack, threadName, location, currentTimeMillis);
+                contextStack, threadName, location, currentTimeMillis, nanoTime);
         assertEquals(Level.OFF, evt.getLevel());
     }
 
@@ -77,8 +78,9 @@ public class RingBufferLogEventTest {
         final String threadName = null;
         final StackTraceElement location = null;
         final long currentTimeMillis = 0;
+        final long nanoTime = 1;
         evt.setValues(null, loggerName, marker, fqcn, level, data, t, map,
-                contextStack, threadName, location, currentTimeMillis);
+                contextStack, threadName, location, currentTimeMillis, nanoTime);
         assertNotNull(evt.getMessage());
     }
 
@@ -96,8 +98,9 @@ public class RingBufferLogEventTest {
         final String threadName = null;
         final StackTraceElement location = null;
         final long currentTimeMillis = 123;
+        final long nanoTime = 1;
         evt.setValues(null, loggerName, marker, fqcn, level, data, t, map,
-                contextStack, threadName, location, currentTimeMillis);
+                contextStack, threadName, location, currentTimeMillis, nanoTime);
         assertEquals(123, evt.getTimeMillis());
     }
 
@@ -115,8 +118,9 @@ public class RingBufferLogEventTest {
         final String threadName = "main";
         final StackTraceElement location = null;
         final long currentTimeMillis = 12345;
+        final long nanoTime = 1;
         evt.setValues(null, loggerName, marker, fqcn, level, data, t, map,
-                contextStack, threadName, location, currentTimeMillis);
+                contextStack, threadName, location, currentTimeMillis, nanoTime);
         
         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
         final ObjectOutputStream out = new ObjectOutputStream(baos);
@@ -153,8 +157,9 @@ public class RingBufferLogEventTest {
         final String threadName = "main";
         final StackTraceElement location = null;
         final long currentTimeMillis = 12345;
+        final long nanoTime = 1;
         evt.setValues(null, loggerName, marker, fqcn, level, data, t, map,
-                contextStack, threadName, location, currentTimeMillis);
+                contextStack, threadName, location, currentTimeMillis, nanoTime);
         
         final LogEvent actual = evt.createMemento();
         assertEquals(evt.getLoggerName(), actual.getLoggerName());

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventNanoTimeTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventNanoTimeTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventNanoTimeTest.java
new file mode 100644
index 0000000..b159feb
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventNanoTimeTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.impl;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.CoreLoggerContexts;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.util.Constants;
+import org.apache.logging.log4j.core.util.DummyNanoClock;
+import org.apache.logging.log4j.core.util.SystemNanoClock;
+import org.apache.logging.log4j.util.Strings;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Log4jLogEventNanoTimeTest {
+
+    @BeforeClass
+    public static void beforeClass() {
+        System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY,
+                "NanoTimeToFileTest.xml");
+    }
+
+    @AfterClass
+    public static void afterClass() {
+        System.setProperty(Constants.LOG4J_CONTEXT_SELECTOR, Strings.EMPTY);
+    }
+
+    @Test
+    public void testLog4jLogEventUsesNanoTimeClock() throws Exception {
+        final File file = new File("target", "NanoTimeToFileTest.log");
+        // System.out.println(f.getAbsolutePath());
+        file.delete();
+        final Logger log = LogManager.getLogger("com.foo.Bar");
+        final long before = System.nanoTime();
+        log.info("Use actual System.nanoTime()");
+        assertTrue("using SystemNanoClock", Log4jLogEvent.getNanoClock() instanceof SystemNanoClock);
+
+        final long DUMMYNANOTIME = 123;
+        Log4jLogEvent.setNanoClock(new DummyNanoClock(DUMMYNANOTIME));
+        log.info("Use dummy nano clock");
+        assertTrue("using SystemNanoClock", Log4jLogEvent.getNanoClock() instanceof DummyNanoClock);
+        
+        CoreLoggerContexts.stopLoggerContext(file); // stop async thread
+
+        final BufferedReader reader = new BufferedReader(new FileReader(file));
+        final String line1 = reader.readLine();
+        final String line2 = reader.readLine();
+        // System.out.println(line1);
+        // System.out.println(line2);
+        reader.close();
+        file.delete();
+
+        assertNotNull("line1", line1);
+        assertNotNull("line2", line2);
+        final String[] line1Parts = line1.split(" AND ");
+        assertEquals("Use actual System.nanoTime()", line1Parts[2]);
+        assertEquals(line1Parts[0], line1Parts[1]);
+        long loggedNanoTime = Long.parseLong(line1Parts[0]);
+        assertTrue("used system nano time", loggedNanoTime - before < TimeUnit.SECONDS.toNanos(1));
+        
+        final String[] line2Parts = line2.split(" AND ");
+        assertEquals("Use dummy nano clock", line2Parts[2]);
+        assertEquals(String.valueOf(DUMMYNANOTIME), line2Parts[0]);
+        assertEquals(String.valueOf(DUMMYNANOTIME), line2Parts[1]);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java
index 540bfeb..516c9ec 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java
@@ -21,16 +21,24 @@ import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
 
 import javax.xml.bind.DatatypeConverter;
 
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.MarkerManager;
+import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.ThreadContext.ContextStack;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.util.Clock;
 import org.apache.logging.log4j.core.util.ClockFactory;
 import org.apache.logging.log4j.core.util.ClockFactoryTest;
+import org.apache.logging.log4j.core.util.DummyNanoClock;
 import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.message.ObjectMessage;
 import org.apache.logging.log4j.message.SimpleMessage;
 import org.apache.logging.log4j.util.Strings;
 import org.junit.AfterClass;
@@ -193,6 +201,206 @@ public class Log4jLogEventTest {
     public void testTimestampGeneratedByClock() {
         final LogEvent evt = Log4jLogEvent.newBuilder().build();
         assertEquals(FixedTimeClock.FIXED_TIME, evt.getTimeMillis());
+    }
+    
+    @Test
+    public void testInitiallyDummyNanoClock() {
+        assertTrue(Log4jLogEvent.getNanoClock() instanceof DummyNanoClock);
+        assertEquals("initial dummy nanotime", 0, Log4jLogEvent.getNanoClock().nanoTime());
+    }
+    
+    @Test
+    public void testNanoTimeGeneratedByNanoClock() {
+        Log4jLogEvent.setNanoClock(new DummyNanoClock(123));
+        verifyNanoTimeWithAllConstructors(123);
+        Log4jLogEvent.setNanoClock(new DummyNanoClock(87654));
+        verifyNanoTimeWithAllConstructors(87654);
+    }
 
+    @SuppressWarnings("deprecation")
+    private void verifyNanoTimeWithAllConstructors(long expected) {
+        assertEquals(expected, Log4jLogEvent.getNanoClock().nanoTime());
+
+        assertEquals("No-arg constructor", expected, new Log4jLogEvent().getNanoTime());
+        assertEquals("1-arg constructor", expected, new Log4jLogEvent(98).getNanoTime());
+        assertEquals("6-arg constructor", expected, new Log4jLogEvent("l", null, "a", null, null, null).getNanoTime());
+        assertEquals("7-arg constructor", expected, new Log4jLogEvent("l", null, "a", null, null, null, null)
+                .getNanoTime());
+        assertEquals("11-arg constructor", expected, new Log4jLogEvent("l", null, "a", null, null, null, null, null,
+                null, null, 0).getNanoTime());
+        assertEquals("12-arg factory method", expected, Log4jLogEvent.createEvent("l", null, "a", null, null, null,
+                null, null, null, null, null, 0).getNanoTime());
+    }
+    
+    @Test
+    public void testBuilderCorrectlyCopiesAllEventAttributes() {
+        final Map<String, String> contextMap = new HashMap<String, String>();
+        contextMap.put("A", "B");
+        final ContextStack contextStack = ThreadContext.getImmutableStack();
+        final Exception exception = new Exception("test");
+        final Marker marker = MarkerManager.getMarker("EVENTTEST");
+        final Message message = new SimpleMessage("foo");
+        final StackTraceElement stackTraceElement = new StackTraceElement("A", "B", "file", 123);
+        final String fqcn = "qualified";
+        final String name = "Ceci n'est pas une pipe";
+        final String threadName = "threadName";
+        final Log4jLogEvent event = Log4jLogEvent.newBuilder() //
+                .setContextMap(contextMap) //
+                .setContextStack(contextStack) //
+                .setEndOfBatch(true) //
+                .setIncludeLocation(true) //
+                .setLevel(Level.FATAL) //
+                .setLoggerFqcn(fqcn) //
+                .setLoggerName(name) //
+                .setMarker(marker) //
+                .setMessage(message) //
+                .setNanoTime(1234567890L) //
+                .setSource(stackTraceElement) //
+                .setThreadName(threadName) //
+                .setThrown(exception) //
+                .setTimeMillis(987654321L)
+                .build();
+        
+        assertSame(contextMap, event.getContextMap());
+        assertSame(contextStack, event.getContextStack());
+        assertEquals(true, event.isEndOfBatch());
+        assertEquals(true, event.isIncludeLocation());
+        assertSame(Level.FATAL, event.getLevel());
+        assertSame(fqcn, event.getLoggerFqcn());
+        assertSame(name, event.getLoggerName());
+        assertSame(marker, event.getMarker());
+        assertSame(message, event.getMessage());
+        assertEquals(1234567890L, event.getNanoTime());
+        assertSame(stackTraceElement, event.getSource());
+        assertSame(threadName, event.getThreadName());
+        assertSame(exception, event.getThrown());
+        assertEquals(987654321L, event.getTimeMillis());
+        
+        LogEvent event2 = new Log4jLogEvent.Builder(event).build();
+        assertEquals("copy constructor builder", event2, event);
+        assertEquals("same hashCode", event2.hashCode(), event.hashCode());
+    }
+    
+    @Test
+    public void testEquals() {
+        final Map<String, String> contextMap = new HashMap<String, String>();
+        contextMap.put("A", "B");
+        ThreadContext.push("first");
+        final ContextStack contextStack = ThreadContext.getImmutableStack();
+        final Exception exception = new Exception("test");
+        final Marker marker = MarkerManager.getMarker("EVENTTEST");
+        final Message message = new SimpleMessage("foo");
+        final StackTraceElement stackTraceElement = new StackTraceElement("A", "B", "file", 123);
+        final String fqcn = "qualified";
+        final String name = "Ceci n'est pas une pipe";
+        final String threadName = "threadName";
+        final Log4jLogEvent event = Log4jLogEvent.newBuilder() //
+                .setContextMap(contextMap) //
+                .setContextStack(contextStack) //
+                .setEndOfBatch(true) //
+                .setIncludeLocation(true) //
+                .setLevel(Level.FATAL) //
+                .setLoggerFqcn(fqcn) //
+                .setLoggerName(name) //
+                .setMarker(marker) //
+                .setMessage(message) //
+                .setNanoTime(1234567890L) //
+                .setSource(stackTraceElement) //
+                .setThreadName(threadName) //
+                .setThrown(exception) //
+                .setTimeMillis(987654321L)
+                .build();
+        
+        assertSame(contextMap, event.getContextMap());
+        assertSame(contextStack, event.getContextStack());
+        assertEquals(true, event.isEndOfBatch());
+        assertEquals(true, event.isIncludeLocation());
+        assertSame(Level.FATAL, event.getLevel());
+        assertSame(fqcn, event.getLoggerFqcn());
+        assertSame(name, event.getLoggerName());
+        assertSame(marker, event.getMarker());
+        assertSame(message, event.getMessage());
+        assertEquals(1234567890L, event.getNanoTime());
+        assertSame(stackTraceElement, event.getSource());
+        assertSame(threadName, event.getThreadName());
+        assertSame(exception, event.getThrown());
+        assertEquals(987654321L, event.getTimeMillis());
+        
+        final LogEvent event2 = builder(event).build();
+        assertEquals("copy constructor builder", event2, event);
+        assertEquals("same hashCode", event2.hashCode(), event.hashCode());
+        
+        assertSame(contextMap, event2.getContextMap());
+        assertSame(contextStack, event2.getContextStack());
+        assertEquals(true, event2.isEndOfBatch());
+        assertEquals(true, event2.isIncludeLocation());
+        assertSame(Level.FATAL, event2.getLevel());
+        assertSame(fqcn, event2.getLoggerFqcn());
+        assertSame(name, event2.getLoggerName());
+        assertSame(marker, event2.getMarker());
+        assertSame(message, event2.getMessage());
+        assertEquals(1234567890L, event2.getNanoTime());
+        assertSame(stackTraceElement, event2.getSource());
+        assertSame(threadName, event2.getThreadName());
+        assertSame(exception, event2.getThrown());
+        assertEquals(987654321L, event2.getTimeMillis());
+        
+        final Map<String, String> differentMap = Collections.emptyMap();
+        different("different contextMap", builder(event).setContextMap(differentMap), event);
+        different("null contextMap", builder(event).setContextMap(null), event);
+
+        ThreadContext.push("abc");
+        final ContextStack contextStack2 = ThreadContext.getImmutableStack();
+        different("different contextStack", builder(event).setContextStack(contextStack2), event);
+        different("null contextStack", builder(event).setContextStack(null), event);
+
+        different("different EndOfBatch", builder(event).setEndOfBatch(false), event);
+        different("different IncludeLocation", builder(event).setIncludeLocation(false), event);
+
+        different("different level", builder(event).setLevel(Level.INFO), event);
+        different("null level", builder(event).setLevel(null), event);
+
+        different("different fqcn", builder(event).setLoggerFqcn("different"), event);
+        different("null fqcn", builder(event).setLoggerFqcn(null), event);
+
+        different("different name", builder(event).setLoggerName("different"), event);
+        try { // TODO null logger name throws NPE in equals. Use Objects.requireNonNull in constructor?
+            different("null name", builder(event).setLoggerName(null), event);
+            fail("Expected NullPointerException");
+        } catch (NullPointerException ok) {
+        }
+
+        different("different marker", builder(event).setMarker(MarkerManager.getMarker("different")), event);
+        different("null marker", builder(event).setMarker(null), event);
+
+        different("different message", builder(event).setMessage(new ObjectMessage("different")), event);
+        try { // TODO null message throws NPE in equals(). Use Objects.requireNonNull in constructor?
+            different("null message", builder(event).setMessage(null), event);
+            fail("Expected NullPointerException");
+        } catch (NullPointerException ok) {
+        }
+
+        different("different nanoTime", builder(event).setNanoTime(135), event);
+        different("different milliTime", builder(event).setTimeMillis(137), event);
+
+        final StackTraceElement stack2 = new StackTraceElement("XXX", "YYY", "file", 123);
+        different("different source", builder(event).setSource(stack2), event);
+        different("null source", builder(event).setSource(null), event);
+        
+        different("different threadname", builder(event).setThreadName("different"), event);
+        different("null threadname", builder(event).setThreadName(null), event);
+        
+        different("different exception", builder(event).setThrown(new Error("Boo!")), event);
+        different("null exception", builder(event).setThrown(null), event);
+    }
+    
+    private static Log4jLogEvent.Builder builder(LogEvent event) {
+        return new Log4jLogEvent.Builder(event);
+    }
+    
+    private void different(String reason, Log4jLogEvent.Builder builder, LogEvent event) {
+        final LogEvent other = builder.build();
+        assertNotEquals(reason, other, event);
+        assertNotEquals(reason + " hashCode", other.hashCode(), event.hashCode());
     }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7f075a71/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/NanoTimePatternConverterTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/NanoTimePatternConverterTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/NanoTimePatternConverterTest.java
new file mode 100644
index 0000000..f9598d2
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/NanoTimePatternConverterTest.java
@@ -0,0 +1,39 @@
+/*
+ * 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.pattern;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.impl.Log4jLogEvent;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ *
+ */
+public class NanoTimePatternConverterTest {
+
+    @Test
+    public void testConverterAppendsLogEventNanoTimeToStringBuilder() {
+        final LogEvent event = Log4jLogEvent.newBuilder() //
+                .setNanoTime(1234567).build();
+        final StringBuilder sb = new StringBuilder();
+        final NanoTimePatternConverter converter = NanoTimePatternConverter.newInstance(null);
+        converter.format(event, sb);
+        assertEquals("1234567", sb.toString());
+    }
+}