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 2018/01/21 13:31:15 UTC
[1/3] logging-log4j2 git commit: LOG4J2-1883 replace timeMillis with
Instant/MutableInstant in LogEvent;
support formatting date times in higher precision than milliseconds;
add Java 9 precise time source; update docs
Repository: logging-log4j2
Updated Branches:
refs/heads/LOG4J2-1883-instant-field [created] a07d6ba48
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/test/java/org/apache/logging/log4j/core/util/datetime/FixedDateFormatTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/datetime/FixedDateFormatTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/util/datetime/FixedDateFormatTest.java
index 55e5d59..e41c4e1 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/datetime/FixedDateFormatTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/util/datetime/FixedDateFormatTest.java
@@ -156,6 +156,9 @@ public class FixedDateFormatTest {
final long start = now - TimeUnit.HOURS.toMillis(25);
final long end = now + TimeUnit.HOURS.toMillis(25);
for (final FixedFormat format : FixedFormat.values()) {
+ if (format.getPattern().endsWith("n")) {
+ continue; // cannot compile precise timestamp formats with SimpleDateFormat
+ }
final SimpleDateFormat simpleDF = new SimpleDateFormat(format.getPattern(), Locale.getDefault());
final FixedDateFormat customTF = new FixedDateFormat(format, TimeZone.getDefault());
for (long time = start; time < end; time += 12345) {
@@ -172,6 +175,9 @@ public class FixedDateFormatTest {
final long start = now - TimeUnit.HOURS.toMillis(25);
final long end = now + TimeUnit.HOURS.toMillis(25);
for (final FixedFormat format : FixedFormat.values()) {
+ if (format.getPattern().endsWith("n")) {
+ continue; // cannot compile precise timestamp formats with SimpleDateFormat
+ }
final SimpleDateFormat simpleDF = new SimpleDateFormat(format.getPattern(), Locale.getDefault());
final FixedDateFormat customTF = new FixedDateFormat(format, TimeZone.getDefault());
for (long time = end; time > start; time -= 12345) {
@@ -189,6 +195,9 @@ public class FixedDateFormatTest {
final long end = now + TimeUnit.HOURS.toMillis(25);
final char[] buffer = new char[128];
for (final FixedFormat format : FixedFormat.values()) {
+ if (format.getPattern().endsWith("n")) {
+ continue; // cannot compile precise timestamp formats with SimpleDateFormat
+ }
final SimpleDateFormat simpleDF = new SimpleDateFormat(format.getPattern(), Locale.getDefault());
final FixedDateFormat customTF = new FixedDateFormat(format, TimeZone.getDefault());
for (long time = start; time < end; time += 12345) {
@@ -207,6 +216,9 @@ public class FixedDateFormatTest {
final long end = now + TimeUnit.HOURS.toMillis(25);
final char[] buffer = new char[128];
for (final FixedFormat format : FixedFormat.values()) {
+ if (format.getPattern().endsWith("n")) {
+ continue; // cannot compile precise timestamp formats with SimpleDateFormat
+ }
final SimpleDateFormat simpleDF = new SimpleDateFormat(format.getPattern(), Locale.getDefault());
final FixedDateFormat customTF = new FixedDateFormat(format, TimeZone.getDefault());
for (long time = end; time > start; time -= 12345) {
@@ -362,6 +374,9 @@ public class FixedDateFormatTest {
final long end = now + TimeUnit.HOURS.toMillis(1);
for (final FixedFormat format : FixedFormat.values()) {
+ if (format.getPattern().endsWith("n")) {
+ continue; // cannot compile precise timestamp formats with SimpleDateFormat
+ }
final SimpleDateFormat simpleDF = new SimpleDateFormat(format.getPattern(), Locale.getDefault());
final FixedDateFormat customTF = new FixedDateFormat(format, TimeZone.getDefault());
for (long time = end; time > start; time -= 12345) {
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/test/resources/META-INF/persistence.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/META-INF/persistence.xml b/log4j-core/src/test/resources/META-INF/persistence.xml
index c174abc..d800739 100644
--- a/log4j-core/src/test/resources/META-INF/persistence.xml
+++ b/log4j-core/src/test/resources/META-INF/persistence.xml
@@ -28,6 +28,7 @@
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapJsonAttributeConverter</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackAttributeConverter</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackJsonAttributeConverter</class>
+ <class>org.apache.logging.log4j.core.appender.db.jpa.converter.InstantAttributeConverter</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.LevelAttributeConverter</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.MarkerAttributeConverter</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.MessageAttributeConverter</class>
@@ -52,6 +53,7 @@
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapJsonAttributeConverter</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackAttributeConverter</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackJsonAttributeConverter</class>
+ <class>org.apache.logging.log4j.core.appender.db.jpa.converter.InstantAttributeConverter</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.LevelAttributeConverter</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.MarkerAttributeConverter</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.MessageAttributeConverter</class>
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/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 7a2b962..73cd43e 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
@@ -32,6 +32,7 @@ import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.core.impl.ThrowableProxy;
+import org.apache.logging.log4j.core.util.Instant;
import org.apache.logging.log4j.core.util.Patterns;
import org.apache.logging.log4j.core.util.UuidUtil;
import org.apache.logging.log4j.message.MapMessage;
@@ -294,6 +295,15 @@ public class FlumeEvent extends SimpleEvent implements LogEvent {
}
/**
+ * {@inheritDoc}
+ * @since 2.11
+ */
+ @Override
+ public Instant getInstant() {
+ return event.getInstant();
+ }
+
+ /**
* 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.
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-perf/src/main/resources/META-INF/persistence.xml
----------------------------------------------------------------------
diff --git a/log4j-perf/src/main/resources/META-INF/persistence.xml b/log4j-perf/src/main/resources/META-INF/persistence.xml
index c174abc..d800739 100644
--- a/log4j-perf/src/main/resources/META-INF/persistence.xml
+++ b/log4j-perf/src/main/resources/META-INF/persistence.xml
@@ -28,6 +28,7 @@
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapJsonAttributeConverter</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackAttributeConverter</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackJsonAttributeConverter</class>
+ <class>org.apache.logging.log4j.core.appender.db.jpa.converter.InstantAttributeConverter</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.LevelAttributeConverter</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.MarkerAttributeConverter</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.MessageAttributeConverter</class>
@@ -52,6 +53,7 @@
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapJsonAttributeConverter</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackAttributeConverter</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackJsonAttributeConverter</class>
+ <class>org.apache.logging.log4j.core.appender.db.jpa.converter.InstantAttributeConverter</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.LevelAttributeConverter</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.MarkerAttributeConverter</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.MessageAttributeConverter</class>
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/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 c406aaa..6d5bece 100644
--- a/src/site/xdoc/manual/layouts.xml.vm
+++ b/src/site/xdoc/manual/layouts.xml.vm
@@ -346,6 +346,10 @@ logger.debug("one={}, two={}, three={}", 1, 2, 3);
</p>
<pre class="prettyprint linenums">{
"timeMillis" : 1493121664118,
+ "instant" : {
+ "epochSecond" : 1493121664,
+ "nanoOfSecond" : 118000000
+ },
"thread" : "main",
"level" : "INFO",
"loggerName" : "HelloWorld",
@@ -736,7 +740,15 @@ WARN [main]: Message 2</pre>
</tr>
<tr>
<td>%d{DEFAULT}</td>
- <td>2012-11-02 14:34:02,781</td>
+ <td>2012-11-02 14:34:02,123</td>
+ </tr>
+ <tr>
+ <td>%d{DEFAULT_MICROS}</td>
+ <td>2012-11-02 14:34:02,123456</td>
+ </tr>
+ <tr>
+ <td>%d{DEFAULT_NANOS}</td>
+ <td>2012-11-02 14:34:02,123456789</td>
</tr>
<tr>
<td>%d{ISO8601}</td>
@@ -751,6 +763,14 @@ WARN [main]: Message 2</pre>
<td>14:34:02,781</td>
</tr>
<tr>
+ <td>%d{ABSOLUTE_MICROS}</td>
+ <td>14:34:02,123456</td>
+ </tr>
+ <tr>
+ <td>%d{ABSOLUTE_NANOS}</td>
+ <td>14:34:02,123456789</td>
+ </tr>
+ <tr>
<td>%d{DATE}</td>
<td>02 Nov 2012 14:34:02,781</td>
</tr>
@@ -760,11 +780,19 @@ WARN [main]: Message 2</pre>
</tr>
<tr>
<td>%d{HH:mm:ss,SSS}</td>
- <td>14:34:02,781</td>
+ <td>14:34:02,123</td>
+ </tr>
+ <tr>
+ <td>%d{HH:mm:ss,nnnn} to %d{HH:mm:ss,nnnnnnnnn}</td>
+ <td>14:34:02,1234 to 14:34:02,123456789</td>
</tr>
<tr>
<td>%d{dd MMM yyyy HH:mm:ss,SSS}</td>
- <td>02 Nov 2012 14:34:02,781</td>
+ <td>02 Nov 2012 14:34:02,123</td>
+ </tr>
+ <tr>
+ <td>%d{dd MMM yyyy HH:mm:ss,nnnn} to %d{dd MMM yyyy HH:mm:ss,nnnnnnnnn}</td>
+ <td>02 Nov 2012 14:34:02,1234 to 02 Nov 2012 14:34:02,123456789</td>
</tr>
<tr>
<td>%d{HH:mm:ss}{GMT+0}</td>
@@ -789,6 +817,18 @@ WARN [main]: Message 2</pre>
This is an efficient way to output the event time because only a conversion from long to String
takes place, there is no Date formatting involved.
</p>
+ <p>
+ Log4j 2.11 adds limited support for timestamps more precise than milliseconds when running on Java 9.
+ Note that not all
+ <a href="https://docs.oracle.com/javase/9/docs/api/java/time/format/DateTimeFormatter.html">DateTimeFormatter</a>
+ formats are supported.
+ Only timestamps in the formats mentioned in the table above may use the "nano-of-second"
+ pattern letter <code>n</code> instead of the "fraction-of-second" pattern letter <code>S</code>.
+ </p>
+ <p>
+ Users may revert back to a millisecond-precision clock when running on Java 9 by setting system property
+ <code>log4j2.Clock</code> to <code>org.apache.logging.log4j.core.util.SystemMillisClock</code>.
+ </p>
</td>
</tr>
<tr>
@@ -2165,6 +2205,7 @@ at org.apache.logging.log4j.core.pattern.ExtendedThrowableTest.testException(Ext
loggerFqcn="org.apache.logging.log4j.spi.AbstractLogger"
threadId="1"
threadPriority="5">
+ <Instant epochSecond="1493121664" nanoOfSecond="118000000"/>
<Marker name="child">
<Parents>
<Marker name="parent">
@@ -2297,6 +2338,9 @@ at org.apache.logging.log4j.core.pattern.ExtendedThrowableTest.testException(Ext
</p>
<pre class="prettyprint linenums">---
timeMillis: 1493122307075
+instant:
+ epochSecond: 1493121664
+ nanoOfSecond: 118000000
thread: "main"
level: "INFO"
loggerName: "HelloWorld"
[2/3] logging-log4j2 git commit: LOG4J2-1883 replace timeMillis with
Instant/MutableInstant in LogEvent;
support formatting date times in higher precision than milliseconds;
add Java 9 precise time source; update docs
Posted by rp...@apache.org.
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ClockFactory.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ClockFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ClockFactory.java
index 129f281..bd5e840 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ClockFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ClockFactory.java
@@ -18,6 +18,10 @@ package org.apache.logging.log4j.core.util;
import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.PropertiesUtil;
+import org.apache.logging.log4j.util.Supplier;
+
+import java.util.HashMap;
+import java.util.Map;
/**
* Factory for {@code Clock} objects.
@@ -62,21 +66,24 @@ public final class ClockFactory {
return createClock();
}
+ private static Map<String, Supplier<Clock>> aliases() {
+ Map<String, Supplier<Clock>> result = new HashMap<>();
+ result.put("SystemClock", new Supplier<Clock>() { @Override public Clock get() { return new SystemClock(); } });
+ result.put("CachedClock", new Supplier<Clock>() { @Override public Clock get() { return CachedClock.instance(); } });
+ result.put("CoarseCachedClock", new Supplier<Clock>() { @Override public Clock get() { return CoarseCachedClock.instance(); } });
+ return result;
+ }
+
private static Clock createClock() {
final String userRequest = PropertiesUtil.getProperties().getStringProperty(PROPERTY_NAME);
- if (userRequest == null || "SystemClock".equals(userRequest)) {
+ if (userRequest == null) {
LOGGER.trace("Using default SystemClock for timestamps.");
return new SystemClock();
}
- if (CachedClock.class.getName().equals(userRequest)
- || "CachedClock".equals(userRequest)) {
- LOGGER.trace("Using specified CachedClock for timestamps.");
- return CachedClock.instance();
- }
- if (CoarseCachedClock.class.getName().equals(userRequest)
- || "CoarseCachedClock".equals(userRequest)) {
- LOGGER.trace("Using specified CoarseCachedClock for timestamps.");
- return CoarseCachedClock.instance();
+ Supplier<Clock> specified = aliases().get(userRequest);
+ if (specified != null) {
+ LOGGER.trace("Using specified {} for timestamps.", userRequest);
+ return specified.get();
}
try {
final Clock result = Loader.newCheckedInstanceOf(userRequest, Clock.class);
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/main/java/org/apache/logging/log4j/core/util/DummyPreciseClock.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/DummyPreciseClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/DummyPreciseClock.java
new file mode 100644
index 0000000..2c88640
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/DummyPreciseClock.java
@@ -0,0 +1,49 @@
+/*
+ * 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 PreciseClock} interface that always returns a fixed value.
+ * @since 2.11
+ */
+public class DummyPreciseClock implements PreciseClock {
+ private final long currentTimeMillis;
+ private final int nanosOfMillisecond;
+
+ public DummyPreciseClock() {
+ this(0);
+ }
+
+ public DummyPreciseClock(final long currentTimeMillis) {
+ this(currentTimeMillis, 0);
+ }
+
+ public DummyPreciseClock(final long currentTimeMillis, final int nanosOfMillisecond) {
+ this.currentTimeMillis = currentTimeMillis;
+ this.nanosOfMillisecond = nanosOfMillisecond;
+ }
+
+ @Override
+ public void init(final MutableInstant instant) {
+ instant.initFromEpochMilli(currentTimeMillis, nanosOfMillisecond);
+ }
+
+ @Override
+ public long currentTimeMillis() {
+ return currentTimeMillis;
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Instant.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Instant.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Instant.java
new file mode 100644
index 0000000..a798021
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Instant.java
@@ -0,0 +1,72 @@
+/*
+ * 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;
+
+/**
+ * Models a point in time, suitable for event timestamps.
+ * <p>
+ * Provides methods for obtaining high precision time information similar to the
+ * <a href="https://docs.oracle.com/javase/9/docs/api/java/time/Instant.html">Instant</a> class introduced in Java 8,
+ * while also supporting the legacy millisecond precision API.
+ * </p><p>
+ * Depending on the platform, time sources ({@link Clock} implementations) may produce high precision or millisecond
+ * precision time values. At the same time, some time value consumers (for example timestamp formatters) may only be
+ * able to consume time values of millisecond precision, while some others may require a high precision time value.
+ * </p><p>
+ * This class bridges these two time APIs.
+ * </p>
+ * @since 2.11
+ */
+public interface Instant {
+ /**
+ * Gets the number of seconds from the Java epoch of 1970-01-01T00:00:00Z.
+ * <p>
+ * The epoch second count is a simple incrementing count of seconds where second 0 is 1970-01-01T00:00:00Z.
+ * The nanosecond part of the day is returned by {@link #getNanoOfSecond()}.
+ * </p>
+ * @return the seconds from the epoch of 1970-01-01T00:00:00Z
+ */
+ long getEpochSecond();
+
+ /**
+ * Gets the number of nanoseconds, later along the time-line, from the start of the second.
+ * <p>
+ * The nanosecond-of-second value measures the total number of nanoseconds from the second returned by {@link #getEpochSecond()}.
+ * </p>
+ * @return the nanoseconds within the second, always positive, never exceeds {@code 999,999,999}
+ */
+ int getNanoOfSecond();
+
+ /**
+ * Gets the number of milliseconds from the Java epoch of 1970-01-01T00:00:00Z.
+ * <p>
+ * The epoch millisecond count is a simple incrementing count of milliseconds where millisecond 0 is 1970-01-01T00:00:00Z.
+ * The nanosecond part of the day is returned by {@link #getNanoOfMillisecond()}.
+ * </p>
+ * @return the milliseconds from the epoch of 1970-01-01T00:00:00Z
+ */
+ long getEpochMillisecond();
+
+ /**
+ * Gets the number of nanoseconds, later along the time-line, from the start of the millisecond.
+ * <p>
+ * The nanosecond-of-millisecond value measures the total number of nanoseconds from the millisecond returned by {@link #getEpochMillisecond()}.
+ * </p>
+ * @return the nanoseconds within the millisecond, always positive, never exceeds {@code 999,999}
+ */
+ int getNanoOfMillisecond();
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/main/java/org/apache/logging/log4j/core/util/MutableInstant.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/MutableInstant.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/MutableInstant.java
new file mode 100644
index 0000000..1c64525
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/MutableInstant.java
@@ -0,0 +1,152 @@
+/*
+ * 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.apache.logging.log4j.util.PerformanceSensitive;
+
+import java.io.Serializable;
+
+/**
+ * An instantaneous point on the time line, used for high-precision log event timestamps.
+ * Modelled on <a href="https://docs.oracle.com/javase/9/docs/api/index.html?java/time/class-use/Instant.html">java.time.Instant</a>,
+ * except that this version is mutable to prevent allocating temporary objects that need to be garbage-collected later.
+ * <p>
+ * Instances of this class are <em>not</em> thread-safe and should not be shared between threads.
+ * </p>
+ *
+ * @since 2.11
+ */
+@PerformanceSensitive("allocation")
+public class MutableInstant implements Instant, Serializable {
+
+ private static final int MILLIS_PER_SECOND = 1000;
+ private static final int NANOS_PER_MILLI = 1000_000;
+ private static final int NANOS_PER_SECOND = MILLIS_PER_SECOND * NANOS_PER_MILLI;
+
+ private long epochSecond;
+ private int nanoOfSecond;
+
+ @Override
+ public long getEpochSecond() {
+ return epochSecond;
+ }
+
+ @Override
+ public int getNanoOfSecond() {
+ return nanoOfSecond;
+ }
+
+ @Override
+ public long getEpochMillisecond() {
+ final int millis = nanoOfSecond / NANOS_PER_MILLI;
+ long epochMillisecond = epochSecond * MILLIS_PER_SECOND + millis;
+ return epochMillisecond;
+ }
+
+ @Override
+ public int getNanoOfMillisecond() {
+ final int millis = nanoOfSecond / NANOS_PER_MILLI;
+ int nanoOfMillisecond = nanoOfSecond - (millis * NANOS_PER_MILLI); // cheaper than nanoOfSecond % NANOS_PER_MILLI
+ return nanoOfMillisecond;
+ }
+
+ public void initFrom(final Instant other) {
+ this.epochSecond = other.getEpochSecond();
+ this.nanoOfSecond = other.getNanoOfSecond();
+ }
+
+ /**
+ * Updates the fields of this {@code MutableInstant} from the specified epoch millis.
+ * @param epochMilli the number of milliseconds from the Java epoch of 1970-01-01T00:00:00Z
+ * @param nanoOfMillisecond the number of nanoseconds, later along the time-line, from the start of the millisecond
+ */
+ public void initFromEpochMilli(final long epochMilli, final int nanoOfMillisecond) {
+ validateNanoOfMillisecond(nanoOfMillisecond);
+ this.epochSecond = epochMilli / MILLIS_PER_SECOND;
+ this.nanoOfSecond = (int) (epochMilli - (epochSecond * MILLIS_PER_SECOND)) * NANOS_PER_MILLI + nanoOfMillisecond;
+ }
+
+ private void validateNanoOfMillisecond(final int nanoOfMillisecond) {
+ if (nanoOfMillisecond < 0 || nanoOfMillisecond >= NANOS_PER_MILLI) {
+ throw new IllegalArgumentException("Invalid nanoOfMillisecond " + nanoOfMillisecond);
+ }
+ }
+
+ public void initFrom(final Clock clock) {
+ if (clock instanceof PreciseClock) {
+ ((PreciseClock) clock).init(this);
+ } else {
+ initFromEpochMilli(clock.currentTimeMillis(), 0);
+ }
+ }
+
+ /**
+ * Updates the fields of this {@code MutableInstant} from the specified instant components.
+ * @param epochSecond the number of seconds from the Java epoch of 1970-01-01T00:00:00Z
+ * @param nano the number of nanoseconds, later along the time-line, from the start of the second
+ */
+ public void initFromEpochSecond(final long epochSecond, final int nano) {
+ validateNanoOfSecond(nano);
+ this.epochSecond = epochSecond;
+ this.nanoOfSecond = nano;
+ }
+
+ private void validateNanoOfSecond(final int nano) {
+ if (nano < 0 || nano >= NANOS_PER_SECOND) {
+ throw new IllegalArgumentException("Invalid nanoOfSecond " + nano);
+ }
+ }
+
+ /**
+ * Updates the elements of the specified {@code long[]} result array from the specified instant components.
+ * @param epochSecond (input) the number of seconds from the Java epoch of 1970-01-01T00:00:00Z
+ * @param nano (input) the number of nanoseconds, later along the time-line, from the start of the second
+ * @param result (output) a two-element array to store the result: the first element is the number of milliseconds
+ * from the Java epoch of 1970-01-01T00:00:00Z,
+ * the second element is the number of nanoseconds, later along the time-line, from the start of the millisecond
+ */
+ public static void instantToMillisAndNanos(final long epochSecond, final int nano, final long[] result) {
+ int millis = nano / NANOS_PER_MILLI;
+ result[0] = epochSecond * MILLIS_PER_SECOND + millis;
+ result[1] = nano - (millis * NANOS_PER_MILLI); // cheaper than nanoOfSecond % NANOS_PER_MILLI
+ }
+
+ @Override
+ public boolean equals(final Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (!(object instanceof MutableInstant)) {
+ return false;
+ }
+ MutableInstant other = (MutableInstant) object;
+ return epochSecond == other.epochSecond && nanoOfSecond == other.nanoOfSecond;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + (int) (epochSecond ^ (epochSecond >>> 32));
+ result = 31 * result + nanoOfSecond;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "MutableInstant[epochSecond=" + epochSecond + ", nano=" + nanoOfSecond + "]";
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/main/java/org/apache/logging/log4j/core/util/PreciseClock.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/PreciseClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/PreciseClock.java
new file mode 100644
index 0000000..366c1c4
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/PreciseClock.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;
+
+/**
+ * Extension of the {@link Clock} interface that is able to provide more accurate time information than milliseconds
+ * since the epoch. {@code PreciseClock} implementations are free to return millisecond-precision time
+ * if that is the most accurate time information available on this platform.
+ * @since 2.11
+ */
+public interface PreciseClock extends Clock {
+
+ /**
+ * Initializes the specified instant with time information as accurate as available on this platform.
+ * @param mutableInstant the container to be initialized with the accurate time information
+ * @since 2.11
+ */
+ void init(final MutableInstant mutableInstant);
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FixedDateFormat.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FixedDateFormat.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FixedDateFormat.java
index 671725d..b9b6af3 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FixedDateFormat.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FixedDateFormat.java
@@ -17,6 +17,8 @@
package org.apache.logging.log4j.core.util.datetime;
+import org.apache.logging.log4j.core.util.Instant;
+
import java.util.Arrays;
import java.util.Calendar;
import java.util.Objects;
@@ -31,6 +33,7 @@ import java.util.concurrent.TimeUnit;
* /log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadsafeDateFormatBenchmark.java
*/
public class FixedDateFormat {
+
/**
* Enumeration over the supported date/time format patterns.
* <p>
@@ -41,6 +44,14 @@ public class FixedDateFormat {
* ABSOLUTE time format: {@code "HH:mm:ss,SSS"}.
*/
ABSOLUTE("HH:mm:ss,SSS", null, 0, ':', 1, ',', 1),
+ /**
+ * ABSOLUTE time format with microsecond precision: {@code "HH:mm:ss,nnnnnn"}.
+ */
+ ABSOLUTE_MICROS("HH:mm:ss,nnnnnn", null, 0, ':', 1, ',', 1),
+ /**
+ * ABSOLUTE time format with nanosecond precision: {@code "HH:mm:ss,nnnnnnnnn"}.
+ */
+ ABSOLUTE_NANOS("HH:mm:ss,nnnnnnnnn", null, 0, ':', 1, ',', 1),
/**
* ABSOLUTE time format variation with period separator: {@code "HH:mm:ss.SSS"}.
@@ -66,6 +77,14 @@ public class FixedDateFormat {
* DEFAULT time format: {@code "yyyy-MM-dd HH:mm:ss,SSS"}.
*/
DEFAULT("yyyy-MM-dd HH:mm:ss,SSS", "yyyy-MM-dd ", 0, ':', 1, ',', 1),
+ /**
+ * DEFAULT time format with microsecond precision: {@code "yyyy-MM-dd HH:mm:ss,nnnnnn"}.
+ */
+ DEFAULT_MICROS("yyyy-MM-dd HH:mm:ss,nnnnnn", "yyyy-MM-dd ", 0, ':', 1, ',', 1),
+ /**
+ * DEFAULT time format with nanosecond precision: {@code "yyyy-MM-dd HH:mm:ss,nnnnnnnnn"}.
+ */
+ DEFAULT_NANOS("yyyy-MM-dd HH:mm:ss,nnnnnnnnn", "yyyy-MM-dd ", 0, ':', 1, ',', 1),
/**
* DEFAULT time format variation with period separator: {@code "yyyy-MM-dd HH:mm:ss.SSS"}.
@@ -92,6 +111,10 @@ public class FixedDateFormat {
*/
ISO8601_PERIOD("yyyy-MM-dd'T'HH:mm:ss.SSS", "yyyy-MM-dd'T'", 2, ':', 1, '.', 1);
+ private static final String DEFAULT_SECOND_FRACTION_PATTERN = "SSS";
+ private static final int MILLI_FRACTION_DIGITS = DEFAULT_SECOND_FRACTION_PATTERN.length();
+ private static final char SECOND_FRACTION_PATTERN = 'n';
+
private final String pattern;
private final String datePattern;
private final int escapeCount;
@@ -144,6 +167,31 @@ public class FixedDateFormat {
return null;
}
+ static FixedFormat lookupIgnoringNanos(final String pattern) {
+ final int nanoStart = nanoStart(pattern);
+ if (nanoStart > 0) {
+ final String subPattern = pattern.substring(0, nanoStart) + DEFAULT_SECOND_FRACTION_PATTERN;
+ for (final FixedFormat type : FixedFormat.values()) {
+ if (type.getPattern().equals(subPattern)) {
+ return type;
+ }
+ }
+ }
+ return null;
+ }
+
+ private static int nanoStart(final String pattern) {
+ final int index = pattern.indexOf(SECOND_FRACTION_PATTERN);
+ if (index >= 0) {
+ for (int i = index + 1; i < pattern.length(); i++) {
+ if (pattern.charAt(i) != SECOND_FRACTION_PATTERN) {
+ return -1;
+ }
+ }
+ }
+ return index;
+ }
+
/**
* Returns the length of the resulting formatted date and time strings.
*
@@ -187,6 +235,7 @@ public class FixedDateFormat {
private final FixedFormat fixedFormat;
private final TimeZone timeZone;
private final int length;
+ private final int secondFractionDigits;
private final FastDateFormat fastDateFormat; // may be null
private final char timeSeparatorChar;
private final char millisSeparatorChar;
@@ -212,8 +261,22 @@ public class FixedDateFormat {
* Package protected for unit tests.
*
* @param fixedFormat the fixed format
+ * @param tz time zone
*/
FixedDateFormat(final FixedFormat fixedFormat, final TimeZone tz) {
+ this(fixedFormat, tz, FixedFormat.DEFAULT_SECOND_FRACTION_PATTERN.length());
+ }
+
+ /**
+ * Constructs a FixedDateFormat for the specified fixed format.
+ * <p>
+ * Package protected for unit tests.
+ *
+ * @param fixedFormat the fixed format
+ * @param tz time zone
+ * @param secondFractionDigits the number of digits specifying the fraction of the second to show
+ */
+ FixedDateFormat(final FixedFormat fixedFormat, final TimeZone tz, final int secondFractionDigits) {
this.fixedFormat = Objects.requireNonNull(fixedFormat);
this.timeZone = Objects.requireNonNull(tz);
this.timeSeparatorChar = fixedFormat.timeSeparatorChar;
@@ -221,6 +284,7 @@ public class FixedDateFormat {
this.millisSeparatorChar = fixedFormat.millisSeparatorChar;
this.millisSeparatorLength = fixedFormat.millisSeparatorLength;
this.length = fixedFormat.getLength();
+ this.secondFractionDigits = Math.max(1, Math.min(9, secondFractionDigits));
this.fastDateFormat = fixedFormat.getFastDateFormat(tz);
}
@@ -230,17 +294,20 @@ public class FixedDateFormat {
}
final TimeZone tz;
if (options.length > 1) {
- if (options[1] != null){
+ if (options[1] != null) {
tz = TimeZone.getTimeZone(options[1]);
} else {
tz = TimeZone.getDefault();
}
- } else if (options.length > 2) {
- return null;
} else {
tz = TimeZone.getDefault();
}
+ final FixedFormat withNanos = FixedFormat.lookupIgnoringNanos(options[0]);
+ if (withNanos != null) {
+ final int secondFractionDigits = options[0].length() - FixedFormat.nanoStart(options[0]);
+ return new FixedDateFormat(withNanos, tz, secondFractionDigits);
+ }
final FixedFormat type = FixedFormat.lookup(options[0]);
return type == null ? null : new FixedDateFormat(type, tz);
}
@@ -351,23 +418,44 @@ public class FixedDateFormat {
}
}
+ public String formatInstant(final Instant instant) {
+ final char[] result = new char[length << 1]; // double size for locales with lengthy DateFormatSymbols
+ final int written = formatInstant(instant, result, 0);
+ return new String(result, 0, written);
+ }
+
+ public int formatInstant(final Instant instant, final char[] buffer, final int startPos) {
+ int result = format(instant.getEpochMillisecond(), buffer, startPos);
+ result -= digitsLessThanThree();
+ formatNanoOfMillisecond(instant.getNanoOfMillisecond(), buffer, startPos + result);
+ return result + digitsMorePreciseThanMillis();
+ }
+
+ private int digitsLessThanThree() { // in case user specified only 1 or 2 'n' format characters
+ return Math.max(0, FixedFormat.MILLI_FRACTION_DIGITS - secondFractionDigits);
+ }
+
+ private int digitsMorePreciseThanMillis() {
+ return Math.max(0, secondFractionDigits - FixedFormat.MILLI_FRACTION_DIGITS);
+ }
+
// Profiling showed this method is important to log4j performance. Modify with care!
// 28 bytes (allows immediate JVM inlining: <= -XX:MaxInlineSize=35 bytes)
- public String format(final long time) {
+ public String format(final long epochMillis) {
final char[] result = new char[length << 1]; // double size for locales with lengthy DateFormatSymbols
- final int written = format(time, result, 0);
+ final int written = format(epochMillis, result, 0);
return new String(result, 0, written);
}
// Profiling showed this method is important to log4j performance. Modify with care!
// 31 bytes (allows immediate JVM inlining: <= -XX:MaxInlineSize=35 bytes)
- public int format(final long time, final char[] buffer, final int startPos) {
+ public int format(final long epochMillis, final char[] buffer, final int startPos) {
// Calculate values by getting the ms values first and do then
// calculate the hour minute and second values divisions.
// Get daytime in ms: this does fit into an int
// int ms = (int) (time % 86400000);
- final int ms = (int) (millisSinceMidnight(time));
+ final int ms = (int) (millisSinceMidnight(epochMillis));
writeDate(buffer, startPos);
return writeTime(ms, buffer, startPos + dateLength) - startPos;
}
@@ -431,6 +519,26 @@ public class FixedDateFormat {
return pos;
}
+ static int[] TABLE = {
+ 100000, // 0
+ 10000, // 1
+ 1000, // 2
+ 100, // 3
+ 10, // 4
+ 1, // 5
+ };
+
+ private void formatNanoOfMillisecond(int nanoOfMillisecond, final char[] buffer, int pos) {
+ int temp;
+ int remain = nanoOfMillisecond;
+ for (int i = 0; i < secondFractionDigits - FixedFormat.MILLI_FRACTION_DIGITS; i++) {
+ int divisor = TABLE[i];
+ temp = remain / divisor;
+ buffer[pos++] = ((char) (temp + '0'));
+ remain -= divisor * temp; // equivalent of remain % 10
+ }
+ }
+
private int daylightSavingTime(final int hourOfDay) {
return hourOfDay > 23 ? dstOffsets[23] : dstOffsets[hourOfDay];
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java
index e6dbdb6..323ca13 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java
@@ -19,13 +19,21 @@ package org.apache.logging.log4j.core.appender;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.util.List;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.categories.Layouts;
+import org.apache.logging.log4j.core.filter.TimeFilterTest;
+import org.apache.logging.log4j.core.impl.Log4jLogEventTest;
import org.apache.logging.log4j.core.selector.ContextSelector;
import org.apache.logging.log4j.core.selector.CoreContextSelectors;
+import org.apache.logging.log4j.core.util.ClockFactory;
import org.apache.logging.log4j.junit.CleanFiles;
import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
@@ -49,6 +57,16 @@ public class JsonCompleteFileAppenderTest {
this.ruleChain = RuleChain.outerRule(cleanFiles).around(loggerContextRule);
}
+ @BeforeClass
+ public static void beforeClass() {
+ System.setProperty(ClockFactory.PROPERTY_NAME, Log4jLogEventTest.FixedTimeClock.class.getName());
+ }
+
+ @AfterClass
+ public static void afterClass() {
+ System.clearProperty(ClockFactory.PROPERTY_NAME);
+ }
+
@Parameters(name = "{0}")
public static Class<?>[] getParameters() {
return CoreContextSelectors.CLASSES;
@@ -68,45 +86,28 @@ public class JsonCompleteFileAppenderTest {
logger.info(logMsg);
logger.error(logMsg, new IllegalArgumentException("badarg"));
this.loggerContextRule.getLoggerContext().stop(); // stops async thread
- String line1;
- String line2;
- String line3;
- String line4;
- String line5;
- String line6;
- try (final BufferedReader reader = new BufferedReader(new FileReader(this.logFile))) {
- line1 = reader.readLine();
- line2 = reader.readLine();
- line3 = reader.readLine();
- line4 = reader.readLine();
- line5 = reader.readLine();
- line6 = reader.readLine();
- }
- assertNotNull("line1", line1);
- final String msg1 = "[";
- assertTrue("line1 incorrect: [" + line1 + "], does not contain: [" + msg1 + ']', line1.equals(msg1));
- assertNotNull("line2", line2);
- final String msg2 = "{";
- assertTrue("line2 incorrect: [" + line2 + "], does not contain: [" + msg2 + ']', line2.equals(msg2));
-
- assertNotNull("line3", line3);
- final String msg3 = " \"timeMillis\" : ";
- assertTrue("line3 incorrect: [" + line3 + "], does not contain: [" + msg3 + ']', line3.contains(msg3));
-
- assertNotNull("line4", line4);
- final String msg4 = " \"thread\" : \"main\",";
- assertTrue("line4 incorrect: [" + line4 + "], does not contain: [" + msg4 + ']', line4.contains(msg4));
-
- assertNotNull("line5", line5);
- final String msg5 = " \"level\" : \"INFO\",";
- assertTrue("line5 incorrect: [" + line5 + "], does not contain: [" + msg5 + ']', line5.contains(msg5));
-
- assertNotNull("line6", line6);
- final String msg6 = " \"loggerName\" : \"com.foo.Bar\",";
- assertTrue("line5 incorrect: [" + line6 + "], does not contain: [" + msg6 + ']', line6.contains(msg6));
+ List<String> lines = Files.readAllLines(logFile.toPath(), Charset.forName("UTF8"));
+ String[] expected = {
+ "[", // equals
+ "{", // equals
+ " \"thread\" : \"main\",", //
+ " \"level\" : \"INFO\",", //
+ " \"loggerName\" : \"com.foo.Bar\",", //
+ " \"message\" : \"Message flushed with immediate flush=true\",", //
+ " \"endOfBatch\" : false,", //
+ " \"loggerFqcn\" : \"org.apache.logging.log4j.spi.AbstractLogger\",", //
+ " \"instant\" : {", //
+ " \"epochSecond\" : 1234567,", //
+ " \"nanoOfSecond\" : 890000000", //
+ " },", //
+ };
+ for (int i = 0; i < expected.length; i++) {
+ String line = lines.get(i);
+ assertTrue("line " + i + " incorrect: [" + line + "], does not contain: [" + expected[i] + ']', line.contains(expected[i]));
+ }
final String location = "testFlushAtEndOfBatch";
- assertTrue("no location", !line1.contains(location));
+ assertTrue("no location", !lines.get(0).contains(location));
}
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/XmlCompleteFileAppenderTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/XmlCompleteFileAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/XmlCompleteFileAppenderTest.java
index 35e01a1..c77b464 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/XmlCompleteFileAppenderTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/XmlCompleteFileAppenderTest.java
@@ -16,13 +16,13 @@
*/
package org.apache.logging.log4j.core.appender;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.List;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.categories.Layouts;
@@ -39,6 +39,8 @@ import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
+import static org.junit.Assert.*;
+
/**
* Tests a "complete" XML file a.k.a. a well-formed XML file.
*/
@@ -75,12 +77,14 @@ public class XmlCompleteFileAppenderTest {
String line2;
String line3;
String line4;
+ String line5;
try (final BufferedReader reader = new BufferedReader(new FileReader(logFile))) {
line1 = reader.readLine();
line2 = reader.readLine();
reader.readLine(); // ignore the empty line after the <Events> root
line3 = reader.readLine();
line4 = reader.readLine();
+ line5 = reader.readLine();
} finally {
logFile.delete();
}
@@ -97,9 +101,13 @@ public class XmlCompleteFileAppenderTest {
assertTrue("line3 incorrect: [" + line3 + "], does not contain: [" + msg3 + ']', line3.contains(msg3));
assertNotNull("line4", line4);
- final String msg4 = logMsg;
+ final String msg4 = "<Instant epochSecond=";
assertTrue("line4 incorrect: [" + line4 + "], does not contain: [" + msg4 + ']', line4.contains(msg4));
+ assertNotNull("line5", line5);
+ final String msg5 = logMsg;
+ assertTrue("line5 incorrect: [" + line5 + "], does not contain: [" + msg5 + ']', line5.contains(msg5));
+
final String location = "testFlushAtEndOfBatch";
assertTrue("no location", !line1.contains(location));
}
@@ -108,17 +116,19 @@ public class XmlCompleteFileAppenderTest {
* Test the indentation of the Events XML.
* <p>Expected Events XML is as below.</p>
* <pre>
-<?xml version="1.0" encoding="UTF-8"?>
-<Events xmlns="http://logging.apache.org/log4j/2.0/events">
-
- <Event xmlns="http://logging.apache.org/log4j/2.0/events" timeMillis="1460974522088" thread="main" level="INFO" loggerName="com.foo.Bar" endOfBatch="false" loggerFqcn="org.apache.logging.log4j.spi.AbstractLogger" threadId="11" threadPriority="5">
- <Message>First Msg tag must be in level 2 after correct indentation</Message>
- </Event>
-
- <Event xmlns="http://logging.apache.org/log4j/2.0/events" timeMillis="1460974522089" thread="main" level="INFO" loggerName="com.foo.Bar" endOfBatch="true" loggerFqcn="org.apache.logging.log4j.spi.AbstractLogger" threadId="11" threadPriority="5">
- <Message>Second Msg tag must also be in level 2 after correct indentation</Message>
- </Event>
-</Events>
+<?xml version="1.0" encoding="UTF-8"?>
+<Events xmlns="http://logging.apache.org/log4j/2.0/events">
+
+ <Event xmlns="http://logging.apache.org/log4j/2.0/events" thread="main" level="INFO" loggerName="com.foo.Bar" endOfBatch="true" loggerFqcn="org.apache.logging.log4j.spi.AbstractLogger" threadId="12" threadPriority="5">
+ <Instant epochSecond="1515889414" nanoOfSecond="144000000" epochMillisecond="1515889414144" nanoOfMillisecond="0"/>
+ <Message>First Msg tag must be in level 2 after correct indentation</Message>
+ </Event>
+
+ <Event xmlns="http://logging.apache.org/log4j/2.0/events" thread="main" level="INFO" loggerName="com.foo.Bar" endOfBatch="true" loggerFqcn="org.apache.logging.log4j.spi.AbstractLogger" threadId="12" threadPriority="5">
+ <Instant epochSecond="1515889414" nanoOfSecond="144000000" epochMillisecond="1515889414144" nanoOfMillisecond="0"/>
+ <Message>Second Msg tag must also be in level 2 after correct indentation</Message>
+ </Event>
+</Events>
* </pre>
* @throws Exception
*/
@@ -131,55 +141,32 @@ public class XmlCompleteFileAppenderTest {
logger.info(secondLogMsg);
CoreLoggerContexts.stopLoggerContext(false, logFile); // stop async thread
- final String[] lines = new String[9];
-
- try (final BufferedReader reader = new BufferedReader(new FileReader(logFile))) {
-
- int usefulLinesIndex = 0;
- String readLine;
- while((readLine = reader.readLine()) != null) {
-
- if (!"".equals(readLine.trim())) {
- lines[usefulLinesIndex] = readLine;
- usefulLinesIndex++;
- }
+ int[] indentations = {
+ 0, //"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ 0, //"<Events xmlns=\"http://logging.apache.org/log4j/2.0/events\">\n"
+ -1, // empty
+ 2, //" <Event xmlns=\"http://logging.apache.org/log4j/2.0/events\" thread=\"main\" level=\"INFO\" loggerName=\"com.foo.Bar\" endOfBatch=\"true\" loggerFqcn=\"org.apache.logging.log4j.spi.AbstractLogger\" threadId=\"12\" threadPriority=\"5\">\n"
+ 4, //" <Instant epochSecond=\"1515889414\" nanoOfSecond=\"144000000\" epochMillisecond=\"1515889414144\" nanoOfMillisecond=\"0\"/>\n"
+ 4, //" <Message>First Msg tag must be in level 2 after correct indentation</Message>\n" +
+ 2, //" </Event>\n"
+ -1, // empty
+ 2, //" <Event xmlns=\"http://logging.apache.org/log4j/2.0/events\" thread=\"main\" level=\"INFO\" loggerName=\"com.foo.Bar\" endOfBatch=\"true\" loggerFqcn=\"org.apache.logging.log4j.spi.AbstractLogger\" threadId=\"12\" threadPriority=\"5\">\n" +
+ 4, //" <Instant epochSecond=\"1515889414\" nanoOfSecond=\"144000000\" epochMillisecond=\"1515889414144\" nanoOfMillisecond=\"0\"/>\n" +
+ 4, //" <Message>Second Msg tag must also be in level 2 after correct indentation</Message>\n" +
+ 2, //" </Event>\n" +
+ 0, //"</Events>\n";
+ };
+ List<String> lines1 = Files.readAllLines(logFile.toPath(), Charset.forName("UTF-8"));
+
+ assertEquals("number of lines", indentations.length, lines1.size());
+ for (int i = 0; i < indentations.length; i++) {
+ String line = lines1.get(i);
+ if (line.trim().isEmpty()) {
+ assertEquals(-1, indentations[i]);
+ } else {
+ String padding = " ".substring(0, indentations[i]);
+ assertTrue("Expected " + indentations[i] + " leading spaces but got: " + line, line.startsWith(padding));
}
- } finally {
- logFile.delete();
}
-
- String currentLine = lines[0];
- assertFalse("line1 incorrect: [" + currentLine + "], must have no indentation", currentLine.startsWith(" "));
- // <EVENTS
- currentLine = lines[1];
- assertFalse("line2 incorrect: [" + currentLine + "], must have no indentation", currentLine.startsWith(" "));
- // <EVENT
- currentLine = lines[2];
- assertTrue("line3 incorrect: [" + currentLine + "], must have two-space indentation", currentLine.startsWith(" "));
- assertFalse("line3 incorrect: [" + currentLine + "], must not have more than two-space indentation", currentLine.startsWith(" "));
- // <MSG
- currentLine = lines[3];
- assertTrue("line4 incorrect: [" + currentLine + "], must have four-space indentation", currentLine.startsWith(" "));
- assertFalse("line4 incorrect: [" + currentLine + "], must not have more than four-space indentation", currentLine.startsWith(" "));
- // </EVENT
- currentLine = lines[4];
- assertTrue("line5 incorrect: [" + currentLine + "], must have two-space indentation", currentLine.startsWith(" "));
- assertFalse("line5 incorrect: [" + currentLine + "], must not have more than two-space indentation", currentLine.startsWith(" "));
-
- // <EVENT
- currentLine = lines[5];
- assertTrue("line6 incorrect: [" + currentLine + "], must have two-space indentation", currentLine.startsWith(" "));
- assertFalse("line6 incorrect: [" + currentLine + "], must not have more than two-space indentation", currentLine.startsWith(" "));
- // <MSG
- currentLine = lines[6];
- assertTrue("line7 incorrect: [" + currentLine + "], must have four-space indentation", currentLine.startsWith(" "));
- assertFalse("line7 incorrect: [" + currentLine + "], must not have more than four-space indentation", currentLine.startsWith(" "));
- // </EVENT
- currentLine = lines[7];
- assertTrue("line8 incorrect: [" + currentLine + "], must have two-space indentation", currentLine.startsWith(" "));
- assertFalse("line8 incorrect: [" + currentLine + "], must not have more than two-space indentation", currentLine.startsWith(" "));
- // </EVENTS
- currentLine = lines[8];
- assertFalse("line9 incorrect: [" + currentLine + "], must have no indentation", currentLine.startsWith(" "));
}
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/XmlFileAppenderTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/XmlFileAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/XmlFileAppenderTest.java
index 98a9fab..f9cdff3 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/XmlFileAppenderTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/XmlFileAppenderTest.java
@@ -19,6 +19,9 @@ package org.apache.logging.log4j.core.appender;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -53,32 +56,23 @@ public class XmlFileAppenderTest {
log.info(logMsg);
CoreLoggerContexts.stopLoggerContext(false, file); // stop async thread
- String line1;
- String line2;
- String line3;
- try (final BufferedReader reader = new BufferedReader(new FileReader(file))) {
- reader.readLine(); // first line is empty, so ignore it
- line1 = reader.readLine();
- line2 = reader.readLine();
- line3 = reader.readLine();
- } finally {
- file.delete();
- }
- assertNotNull("line1", line1);
-
- assertNotNull("line1", line1);
- final String msg1 = "<Event ";
- assertTrue("line1 incorrect: [" + line1 + "], does not contain: [" + msg1 + ']', line1.contains(msg1));
+ List<String> lines = Files.readAllLines(file.toPath(), Charset.forName("UTF8"));
+ file.delete();
- assertNotNull("line2", line2);
- final String msg2 = logMsg;
- assertTrue("line2 incorrect: [" + line2 + "], does not contain: [" + msg2 + ']', line2.contains(msg2));
+ String[] expect = {
+ "", // ? unsure why initial empty line...
+ "<Event ", //
+ "<Instant epochSecond=", //
+ logMsg, //
+ "</Event>", //
+ };
- assertNotNull("line3", line3);
- final String msg3 = "</Event>";
- assertTrue("line3 incorrect: [" + line3 + "], does not contain: [" + msg3 + ']', line3.contains(msg3));
+ for (int i = 0; i < expect.length; i++) {
+ assertTrue("Expected line " + i + " to contain " + expect[i] + " but got: " + lines.get(i),
+ lines.get(i).contains(expect[i]));
+ }
final String location = "testFlushAtEndOfBatch";
- assertTrue("no location", !line1.contains(location));
+ assertTrue("no location", !lines.get(0).contains(location));
}
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/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 055dd03..9b299b9 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
@@ -40,15 +40,16 @@ public class JpaH2AppenderTest extends AbstractJpaAppenderTest {
try (Statement statement = connection.createStatement()) {
statement.executeUpdate("CREATE TABLE jpaBaseLogEntry ( "
- + "id INTEGER IDENTITY, eventDate DATETIME, level NVARCHAR(10), logger NVARCHAR(255), "
- + "message NVARCHAR(1024), exception NVARCHAR(1048576)" + " )");
+ + "id INTEGER IDENTITY, eventDate DATETIME, instant NVARCHAR(64), level NVARCHAR(10), "
+ + "logger NVARCHAR(255), message NVARCHAR(1024), exception NVARCHAR(1048576)" + " )");
}
try (Statement statement = connection.createStatement()) {
statement.executeUpdate("CREATE TABLE jpaBasicLogEntry ( "
- + "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),"
+ + "id INTEGER IDENTITY, timemillis BIGINT, instant NVARCHAR(64), 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),"
+ "threadId BIGINT, threadName NVARCHAR(255), threadPriority INTEGER" + " )");
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/JpaHsqldbAppenderTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/JpaHsqldbAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/JpaHsqldbAppenderTest.java
index 3e22d96..b91734d 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/JpaHsqldbAppenderTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/JpaHsqldbAppenderTest.java
@@ -44,15 +44,16 @@ public class JpaHsqldbAppenderTest extends AbstractJpaAppenderTest {
try (Statement statement = connection.createStatement()) {
statement.executeUpdate("CREATE TABLE jpaBaseLogEntry ( "
- + "id INTEGER IDENTITY, eventDate DATETIME, level VARCHAR(10), logger VARCHAR(255), "
- + "message VARCHAR(1024), exception VARCHAR(1048576)" + " )");
+ + "id INTEGER IDENTITY, eventDate DATETIME, instant NVARCHAR(64), level VARCHAR(10), "
+ + "logger VARCHAR(255), message VARCHAR(1024), exception VARCHAR(1048576)" + " )");
}
try (Statement statement = connection.createStatement()) {
statement.executeUpdate("CREATE TABLE jpaBasicLogEntry ( "
- + "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),"
+ + "id INTEGER IDENTITY, timemillis BIGINT, instant NVARCHAR(64), 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),"
+ "threadId BIGINT, threadName NVARCHAR(255), threadPriority INTEGER" + " )");
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/LogEventEntityTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/LogEventEntityTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/LogEventEntityTest.java
index ed59b53..823cee3 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/LogEventEntityTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/LogEventEntityTest.java
@@ -24,6 +24,8 @@ import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.ThreadContext.ContextStack;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.impl.ThrowableProxy;
+import org.apache.logging.log4j.core.util.Instant;
+import org.apache.logging.log4j.core.util.MutableInstant;
import org.apache.logging.log4j.message.Message;
import org.junit.Assert;
import org.junit.Test;
@@ -72,6 +74,11 @@ public class LogEventEntityTest {
}
@Override
+ public Instant getInstant() {
+ return new MutableInstant();
+ }
+
+ @Override
public long getNanoTime() {
return 0;
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/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 5d4473e..3739731 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
@@ -34,6 +34,8 @@ import javax.persistence.Transient;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.core.appender.db.jpa.converter.InstantAttributeConverter;
+import org.apache.logging.log4j.core.util.Instant;
import org.apache.logging.log4j.util.ReadOnlyStringMap;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.db.jpa.converter.LevelAttributeConverter;
@@ -136,6 +138,13 @@ public class TestBaseEntity extends AbstractLogEventWrapperEntity {
}
@Override
+ @Convert(converter = InstantAttributeConverter.class)
+ @Column(name = "instant")
+ public Instant getInstant() {
+ return this.getWrappedEvent().getInstant();
+ }
+
+ @Override
@Transient
public long getNanoTime() {
return this.getWrappedEvent().getNanoTime();
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/InstantAttributeConverterTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/InstantAttributeConverterTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/InstantAttributeConverterTest.java
new file mode 100644
index 0000000..ab2324f
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/InstantAttributeConverterTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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.appender.db.jpa.converter;
+
+import org.apache.logging.log4j.categories.Appenders;
+import org.apache.logging.log4j.core.util.Instant;
+import org.apache.logging.log4j.core.util.MutableInstant;
+import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import static org.junit.Assert.*;
+
+@Category(Appenders.Jpa.class)
+public class InstantAttributeConverterTest {
+ private static final StatusLogger LOGGER = StatusLogger.getLogger();
+
+ private InstantAttributeConverter converter;
+
+ @Before
+ public void setUp() {
+ this.converter = new InstantAttributeConverter();
+ }
+
+ @Test
+ public void testConvert01() {
+ final MutableInstant instant = new MutableInstant();
+ instant.initFromEpochSecond(1234567, 89012);
+
+ final String converted = this.converter.convertToDatabaseColumn(instant);
+
+ assertNotNull("The converted value should not be null.", converted);
+ assertEquals("The converted value is not correct.", "1234567,89012", converted);
+
+ final Instant reversed = this.converter.convertToEntityAttribute(converted);
+
+ assertNotNull("The reversed value should not be null.", reversed);
+ assertEquals("epoch sec", 1234567, reversed.getEpochSecond());
+ assertEquals("nanoOfSecond", 89012, reversed.getNanoOfSecond());
+ }
+
+ @Test
+ public void testConvertNullToDatabaseColumn() {
+ assertNull("The converted value should be null.", this.converter.convertToDatabaseColumn(null));
+ }
+
+ @Test
+ public void testConvertNullOrBlankToEntityAttribute() {
+ assertNull("The converted attribute should be null (1).", this.converter.convertToEntityAttribute(null));
+ assertNull("The converted attribute should be null (2).", this.converter.convertToEntityAttribute(""));
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTimestampMessageTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTimestampMessageTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTimestampMessageTest.java
index c177b8a..f797daf 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTimestampMessageTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTimestampMessageTest.java
@@ -74,7 +74,7 @@ public class AsyncLoggerTimestampMessageTest {
final Logger log = LogManager.getLogger("com.foo.Bar");
assertFalse(PoisonClock.called);
log.info((Message) new TimeMsg("Async logger msg with embedded timestamp", 123456789000L));
- assertTrue(PoisonClock.called);
+ assertFalse(PoisonClock.called);
CoreLoggerContexts.stopLoggerContext(false, file); // stop async thread
final BufferedReader reader = new BufferedReader(new FileReader(file));
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/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 355e668..4dea6a5 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
@@ -30,6 +30,8 @@ import org.apache.logging.log4j.MarkerManager;
import org.apache.logging.log4j.ThreadContext.ContextStack;
import org.apache.logging.log4j.categories.AsyncLoggers;
import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.util.DummyNanoClock;
+import org.apache.logging.log4j.core.util.DummyPreciseClock;
import org.apache.logging.log4j.util.FilteredObjectInputStream;
import org.apache.logging.log4j.util.StringMap;
import org.apache.logging.log4j.core.impl.ThrowableProxy;
@@ -66,10 +68,8 @@ public class RingBufferLogEventTest {
final ContextStack contextStack = null;
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, (StringMap) evt.getContextData(),
- contextStack, -1, threadName, -1, location, currentTimeMillis, nanoTime);
+ contextStack, -1, threadName, -1, location, new DummyPreciseClock(), new DummyNanoClock(1));
assertEquals(Level.OFF, evt.getLevel());
}
@@ -85,10 +85,8 @@ public class RingBufferLogEventTest {
final ContextStack contextStack = null;
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, (StringMap) evt.getContextData(),
- contextStack, -1, threadName, -1, location, currentTimeMillis, nanoTime);
+ contextStack, -1, threadName, -1, location, new DummyPreciseClock(), new DummyNanoClock(1));
assertNotNull(evt.getMessage());
}
@@ -104,11 +102,10 @@ public class RingBufferLogEventTest {
final ContextStack contextStack = null;
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, (StringMap) evt.getContextData(),
- contextStack, -1, threadName, -1, location, currentTimeMillis, nanoTime);
+ contextStack, -1, threadName, -1, location, new DummyPreciseClock(123, 456), new DummyNanoClock(1));
assertEquals(123, evt.getTimeMillis());
+ assertEquals(456, evt.getInstant().getNanoOfMillisecond());
}
@Test
@@ -123,10 +120,9 @@ public class RingBufferLogEventTest {
final ContextStack contextStack = null;
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, (StringMap) evt.getContextData(),
- contextStack, -1, threadName, -1, location, currentTimeMillis, nanoTime);
+ contextStack, -1, threadName, -1, location,
+ new DummyPreciseClock(12345, 678), new DummyNanoClock(1));
((StringMap) evt.getContextData()).putValue("key", "value");
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -146,7 +142,8 @@ public class RingBufferLogEventTest {
assertEquals(contextStack, other.getContextStack());
assertEquals(threadName, other.getThreadName());
assertEquals(location, other.getSource());
- assertEquals(currentTimeMillis, other.getTimeMillis());
+ assertEquals(12345, other.getTimeMillis());
+ assertEquals(678, other.getInstant().getNanoOfMillisecond());
}
@SuppressWarnings("deprecation")
@@ -162,10 +159,8 @@ public class RingBufferLogEventTest {
final ContextStack contextStack = new MutableThreadContextStack(Arrays.asList("a", "b"));
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, (StringMap) evt.getContextData(),
- contextStack, -1, threadName, -1, location, currentTimeMillis, nanoTime);
+ contextStack, -1, threadName, -1, location, new DummyPreciseClock(12345, 678), new DummyNanoClock(1));
((StringMap) evt.getContextData()).putValue("key", "value");
final LogEvent actual = evt.createMemento();
@@ -180,6 +175,7 @@ public class RingBufferLogEventTest {
assertEquals(evt.getContextStack(), actual.getContextStack());
assertEquals(evt.getThreadName(), actual.getThreadName());
assertEquals(evt.getTimeMillis(), actual.getTimeMillis());
+ assertEquals(evt.getInstant().getNanoOfMillisecond(), actual.getInstant().getNanoOfMillisecond());
assertEquals(evt.getSource(), actual.getSource());
assertEquals(evt.getThrownProxy(), actual.getThrownProxy());
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/ConcurrentLoggingWithJsonLayoutTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/ConcurrentLoggingWithJsonLayoutTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/ConcurrentLoggingWithJsonLayoutTest.java
index 3c1fa64..0e4ad52 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/ConcurrentLoggingWithJsonLayoutTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/ConcurrentLoggingWithJsonLayoutTest.java
@@ -85,7 +85,7 @@ public class ConcurrentLoggingWithJsonLayoutTest {
if (new File(PATH).exists()) {
final List<String> lines = Files.readAllLines(new File(PATH).toPath(), Charset.defaultCharset());
for (final String line : lines) {
- assertThat(line, startsWith("{\"timeMillis\":"));
+ assertThat(line, startsWith("{\"thread\":"));
assertThat(line, endsWith("\"threadPriority\":5}"));
}
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/JsonLayoutTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/JsonLayoutTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/JsonLayoutTest.java
index 2a5eafd..dba5cf3 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/JsonLayoutTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/JsonLayoutTest.java
@@ -154,7 +154,7 @@ public class JsonLayoutTest {
//
assertNull(actual.getThrown());
// make sure the names we want are used
- this.checkPropertyName("timeMillis", compact, str);
+ this.checkPropertyName("instant", compact, str);
this.checkPropertyName("thread", compact, str); // and not threadName
this.checkPropertyName("level", compact, str);
this.checkPropertyName("loggerName", compact, str);
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/XmlLayoutTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/XmlLayoutTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/XmlLayoutTest.java
index 95c9f6d..4ee8f1e 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/XmlLayoutTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/XmlLayoutTest.java
@@ -165,7 +165,10 @@ public class XmlLayoutTest {
}
//
// make sure the names we want are used
- this.checkAttributeName("timeMillis", compact, str);
+ //this.checkAttributeName("timeMillis", compact, str);
+ this.checkElementName("Instant", compact, str, true, false);
+ this.checkAttributeName("epochSecond", compact, str);
+ this.checkAttributeName("nanoOfSecond", compact, str);
this.checkAttributeName("thread", compact, str); // and not threadName
this.checkAttributeName("level", compact, str);
this.checkAttributeName("loggerName", compact, str);
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/YamlLayoutTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/YamlLayoutTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/YamlLayoutTest.java
index de19606..2fef8de 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/YamlLayoutTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/YamlLayoutTest.java
@@ -138,7 +138,7 @@ public class YamlLayoutTest {
//
assertNull(actual.getThrown());
// make sure the names we want are used
- this.checkPropertyName("timeMillis", compact, str, true);
+ this.checkPropertyName("instant", compact, str, false);
this.checkPropertyName("thread", compact, str, true); // and not threadName
this.checkPropertyName("level", compact, str, true);
this.checkPropertyName("loggerName", compact, str, true);
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/JsonLogEventParserTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/JsonLogEventParserTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/JsonLogEventParserTest.java
index 0dd0182..9683d63 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/JsonLogEventParserTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/JsonLogEventParserTest.java
@@ -28,6 +28,7 @@ public class JsonLogEventParserTest extends LogEventParserTest {
private static final String JSON = "{\n" +
" \"timeMillis\" : 1493121664118,\n" +
+ " \"instant\":{\"epochSecond\":1493121664,\"nanoOfSecond\":118000000},\n" +
" \"thread\" : \"main\",\n" +
" \"threadId\" : 1,\n" +
" \"threadPriority\" : 5,\n" +
@@ -105,7 +106,7 @@ public class JsonLogEventParserTest extends LogEventParserTest {
@Test(expected = ParseException.class)
public void testStringWrongPropertyType() throws ParseException {
- parser.parseFrom("{\"timeMillis\":\"foobar\"}");
+ parser.parseFrom("{\"threadId\":\"foobar\"}");
}
@Test
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/LogEventParserTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/LogEventParserTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/LogEventParserTest.java
index cd6475b..cdb3bef 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/LogEventParserTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/LogEventParserTest.java
@@ -30,7 +30,7 @@ import static org.junit.Assert.assertThat;
public abstract class LogEventParserTest {
protected void assertLogEvent(final LogEvent logEvent) {
assertThat(logEvent, is(notNullValue()));
- assertThat(logEvent.getTimeMillis(), equalTo(1493121664118L));
+ assertThat(logEvent.getInstant().getEpochMillisecond(), equalTo(1493121664118L));
assertThat(logEvent.getThreadName(), equalTo("main"));
assertThat(logEvent.getThreadId(), equalTo(1L));
assertThat(logEvent.getThreadPriority(), equalTo(5));
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/XmlLogEventParserTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/XmlLogEventParserTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/XmlLogEventParserTest.java
index b460075..72da8ff 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/XmlLogEventParserTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/XmlLogEventParserTest.java
@@ -35,6 +35,7 @@ public class XmlLogEventParserTest extends LogEventParserTest {
" loggerFqcn=\"org.apache.logging.log4j.spi.AbstractLogger\"\n" +
" threadId=\"1\"\n" +
" threadPriority=\"5\">\n" +
+ " <Instant epochSecond=\"1493121664\" nanoOfSecond=\"118000000\"/>\n" +
" <Marker name=\"child\">\n" +
" <Parents>\n" +
" <Marker name=\"parent\">\n" +
@@ -100,6 +101,11 @@ public class XmlLogEventParserTest extends LogEventParserTest {
@Test(expected = ParseException.class)
public void testStringWrongPropertyType() throws ParseException {
+ parser.parseFrom("<Event><Instant epochSecond=\"bar\">foobar</Instant></Event>");
+ }
+
+ @Test
+ public void testTimeMillisIgnored() throws ParseException {
parser.parseFrom("<Event><timeMillis>foobar</timeMillis></Event>");
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/YamlLogEventParserTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/YamlLogEventParserTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/YamlLogEventParserTest.java
index b48989c..16c77e7 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/YamlLogEventParserTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/YamlLogEventParserTest.java
@@ -28,6 +28,9 @@ public class YamlLogEventParserTest extends LogEventParserTest {
private static final String YAML = "---\n" +
"timeMillis: 1493121664118\n" +
+ "instant:\n" +
+ " epochSecond: 1493121664\n" +
+ " nanoOfSecond: 118000000\n" +
"thread: \"main\"\n" +
"level: \"INFO\"\n" +
"loggerName: \"HelloWorld\"\n" +
@@ -92,9 +95,14 @@ public class YamlLogEventParserTest extends LogEventParserTest {
parser.parseFrom("---\n");
}
+ @Test
+ public void testTimeMillisIgnored() throws ParseException {
+ parser.parseFrom("---\ntimeMillis: \"foobar\"\n");
+ }
+
@Test(expected = ParseException.class)
public void testStringWrongPropertyType() throws ParseException {
- parser.parseFrom("---\ntimeMillis: \"foobar\"\n");
+ parser.parseFrom("---\nthreadId: \"foobar\"\n");
}
@Test
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/DatePatternConverterTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/DatePatternConverterTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/DatePatternConverterTest.java
index 9f55165..e6be56a 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/DatePatternConverterTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/DatePatternConverterTest.java
@@ -28,6 +28,8 @@ import java.util.TimeZone;
import org.apache.logging.log4j.core.AbstractLogEvent;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.util.Constants;
+import org.apache.logging.log4j.core.util.Instant;
+import org.apache.logging.log4j.core.util.MutableInstant;
import org.apache.logging.log4j.core.util.datetime.FixedDateFormat;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -148,6 +150,71 @@ public class DatePatternConverterTest {
}
}
+ private String precisePattern(final String pattern, int precision) {
+ String seconds = pattern.substring(0, pattern.indexOf("SSS"));
+ return seconds + "nnnnnnnnn".substring(0, precision);
+ }
+
+ // test with all formats from one 'n' (100s of millis) to 'nnnnnnnnn' (nanosecond precision)
+ @Test
+ public void testPredefinedFormatWithAnyValidNanoPrecision() {
+ final StringBuilder precise = new StringBuilder();
+ final StringBuilder milli = new StringBuilder();
+ final LogEvent event = new MyLogEvent();
+
+ for (String timeZone : new String[]{"PDT", null}) { // Pacific Daylight Time=UTC-8:00
+ for (final FixedDateFormat.FixedFormat format : FixedDateFormat.FixedFormat.values()) {
+ for (int i = 1; i <= 9; i++) {
+ if (format.getPattern().endsWith("n")) {
+ continue; // ignore patterns that already have precise time formats
+ }
+ precise.setLength(0);
+ milli.setLength(0);
+
+ final String[] preciseOptions = {precisePattern(format.getPattern(), i), timeZone};
+ final DatePatternConverter preciseConverter = DatePatternConverter.newInstance(preciseOptions);
+ preciseConverter.format(event, precise);
+
+ final String[] milliOptions = {format.getPattern(), timeZone};
+ DatePatternConverter.newInstance(milliOptions).format(event, milli);
+ milli.setLength(milli.length() - 3); // truncate millis
+ String expected = milli.append("987123456".substring(0, i)).toString();
+
+ assertEquals(expected, precise.toString());
+ //System.out.println(preciseOptions[0] + ": " + precise);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void testInvalidLongPatternIgnoresExcessiveDigits() {
+ final StringBuilder precise = new StringBuilder();
+ final StringBuilder milli = new StringBuilder();
+ final LogEvent event = new MyLogEvent();
+
+ for (final FixedDateFormat.FixedFormat format : FixedDateFormat.FixedFormat.values()) {
+ if (format.getPattern().endsWith("n")) {
+ continue; // ignore patterns that already have precise time formats
+ }
+ precise.setLength(0);
+ milli.setLength(0);
+
+ final String pattern = format.getPattern().substring(0, format.getPattern().indexOf("SSS"));
+ final String[] preciseOptions = {pattern + "nnnnnnnnn" + "n"}; // too long
+ final DatePatternConverter preciseConverter = DatePatternConverter.newInstance(preciseOptions);
+ preciseConverter.format(event, precise);
+
+ final String[] milliOptions = {format.getPattern()};
+ DatePatternConverter.newInstance(milliOptions).format(event, milli);
+ milli.setLength(milli.length() - 3); // truncate millis
+ String expected = milli.append("987123456").toString();
+
+ assertEquals(expected, precise.toString());
+ //System.out.println(preciseOptions[0] + ": " + precise);
+ }
+ }
+
private class MyLogEvent extends AbstractLogEvent {
private static final long serialVersionUID = 0;
@@ -158,6 +225,13 @@ public class DatePatternConverterTest {
cal.set(Calendar.MILLISECOND, 987);
return cal.getTimeInMillis();
}
+
+ @Override
+ public Instant getInstant() {
+ MutableInstant result = new MutableInstant();
+ result.initFromEpochMilli(getTimeMillis(), 123456);
+ return result;
+ }
}
@Test
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/test/java/org/apache/logging/log4j/core/util/MutableInstantTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/MutableInstantTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/util/MutableInstantTest.java
new file mode 100644
index 0000000..1715fc6
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/util/MutableInstantTest.java
@@ -0,0 +1,230 @@
+/*
+ * 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.*;
+
+public class MutableInstantTest {
+
+ @Test
+ public void testGetEpochSecond() {
+ MutableInstant instant = new MutableInstant();
+ assertEquals("initial", 0, instant.getEpochSecond());
+
+ instant.initFromEpochSecond(123, 456);
+ assertEquals("returns directly set value", 123, instant.getEpochSecond());
+
+ instant.initFromEpochMilli(123456, 789012);
+ assertEquals("returns converted value when initialized from milllis", 123, instant.getEpochSecond());
+
+ MutableInstant other = new MutableInstant();
+ other.initFromEpochSecond(788, 456);
+ instant.initFrom(other);
+
+ assertEquals("returns ref value when initialized from instant", 788, instant.getEpochSecond());
+ }
+
+ @Test
+ public void testGetNanoOfSecond() {
+ MutableInstant instant = new MutableInstant();
+ assertEquals("initial", 0, instant.getNanoOfSecond());
+
+ instant.initFromEpochSecond(123, 456);
+ assertEquals("returns directly set value", 456, instant.getNanoOfSecond());
+
+ instant.initFromEpochMilli(123456, 789012);
+ assertEquals("returns converted value when initialized from milllis", 456789012, instant.getNanoOfSecond());
+
+ MutableInstant other = new MutableInstant();
+ other.initFromEpochSecond(788, 456);
+ instant.initFrom(other);
+
+ assertEquals("returns ref value when initialized from instant", 456, instant.getNanoOfSecond());
+ }
+
+ @Test
+ public void testGetEpochMillisecond() {
+ MutableInstant instant = new MutableInstant();
+ assertEquals("initial", 0, instant.getEpochMillisecond());
+
+ instant.initFromEpochMilli(123, 456);
+ assertEquals("returns directly set value", 123, instant.getEpochMillisecond());
+
+ instant.initFromEpochSecond(123, 456789012);
+ assertEquals("returns converted value when initialized from seconds", 123456, instant.getEpochMillisecond());
+
+ MutableInstant other = new MutableInstant();
+ other.initFromEpochMilli(788, 456);
+ instant.initFrom(other);
+
+ assertEquals("returns ref value when initialized from instant", 788, instant.getEpochMillisecond());
+ }
+
+ @Test
+ public void getGetNanoOfMillisecond() {
+ MutableInstant instant = new MutableInstant();
+ assertEquals("initial", 0, instant.getNanoOfMillisecond());
+
+ instant.initFromEpochMilli(123, 456);
+ assertEquals("returns directly set value", 456, instant.getNanoOfMillisecond());
+
+ instant.initFromEpochSecond(123, 456789012);
+ assertEquals("returns converted value when initialized from milllis", 789012, instant.getNanoOfMillisecond());
+
+ MutableInstant other = new MutableInstant();
+ other.initFromEpochMilli(788, 456);
+ instant.initFrom(other);
+
+ assertEquals("returns ref value when initialized from instant", 456, instant.getNanoOfMillisecond());
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testInitFromInstantRejectsNull() {
+ new MutableInstant().initFrom((Instant) null);
+ }
+
+ @Test
+ public void testInitFromInstantCopiesValues() {
+ MutableInstant other = new MutableInstant();
+ other.initFromEpochSecond(788, 456);
+ assertEquals("epochSec", 788, other.getEpochSecond());
+ assertEquals("NanosOfSec", 456, other.getNanoOfSecond());
+
+ MutableInstant instant = new MutableInstant();
+ instant.initFrom(other);
+
+ assertEquals("epochSec", 788, instant.getEpochSecond());
+ assertEquals("NanoOfSec", 456, instant.getNanoOfSecond());
+ }
+
+ @Test
+ public void testInitFromEpochMillis() {
+ MutableInstant instant = new MutableInstant();
+ instant.initFromEpochMilli(123456, 789012);
+ assertEquals("epochSec", 123, instant.getEpochSecond());
+ assertEquals("NanoOfSec", 456789012, instant.getNanoOfSecond());
+ assertEquals("epochMilli", 123456, instant.getEpochMillisecond());
+ assertEquals("NanoOfMilli", 789012, instant.getNanoOfMillisecond());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testInitFromEpochMillisRejectsNegativeNanoOfMilli() {
+ MutableInstant instant = new MutableInstant();
+ instant.initFromEpochMilli(123456, -1);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testInitFromEpochMillisRejectsTooLargeNanoOfMilli() {
+ MutableInstant instant = new MutableInstant();
+ instant.initFromEpochMilli(123456, 1000_000);
+ }
+
+ @Test
+ public void testInitFromEpochMillisAcceptsTooMaxNanoOfMilli() {
+ MutableInstant instant = new MutableInstant();
+ instant.initFromEpochMilli(123456, 999_999);
+ assertEquals("NanoOfMilli", 999_999, instant.getNanoOfMillisecond());
+ }
+
+ @Test
+ public void testInitFromEpochSecond() {
+ MutableInstant instant = new MutableInstant();
+ instant.initFromEpochSecond(123, 456789012);
+ assertEquals("epochSec", 123, instant.getEpochSecond());
+ assertEquals("NanoOfSec", 456789012, instant.getNanoOfSecond());
+ assertEquals("epochMilli", 123456, instant.getEpochMillisecond());
+ assertEquals("NanoOfMilli", 789012, instant.getNanoOfMillisecond());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testInitFromEpochSecondRejectsNegativeNanoOfMilli() {
+ MutableInstant instant = new MutableInstant();
+ instant.initFromEpochSecond(123456, -1);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testInitFromEpochSecondRejectsTooLargeNanoOfMilli() {
+ MutableInstant instant = new MutableInstant();
+ instant.initFromEpochSecond(123456, 1000_000_000);
+ }
+
+ @Test
+ public void testInitFromEpochSecondAcceptsTooMaxNanoOfMilli() {
+ MutableInstant instant = new MutableInstant();
+ instant.initFromEpochSecond(123456, 999_999_999);
+ assertEquals("NanoOfSec", 999_999_999, instant.getNanoOfSecond());
+ }
+
+ @Test
+ public void testInstantToMillisAndNanos() {
+ long[] values = new long[2];
+ MutableInstant.instantToMillisAndNanos(123456, 999_999_999, values);
+ assertEquals(123456_999, values[0]);
+ assertEquals(999_999, values[1]);
+ }
+
+ @Test
+ public void testInitFromClock() {
+ MutableInstant instant = new MutableInstant();
+
+ PreciseClock clock = new DummyPreciseClock(123456, 789012);
+ instant.initFrom(clock);
+
+ assertEquals(123456, instant.getEpochMillisecond());
+ assertEquals(789012, instant.getNanoOfMillisecond());
+ assertEquals(123, instant.getEpochSecond());
+ assertEquals(456789012, instant.getNanoOfSecond());
+ }
+
+ @Test
+ public void testEquals() {
+ MutableInstant instant = new MutableInstant();
+ instant.initFromEpochSecond(123, 456789012);
+
+ MutableInstant instant2 = new MutableInstant();
+ instant2.initFromEpochMilli(123456, 789012);
+
+ assertEquals(instant, instant2);
+ }
+
+ @Test
+ public void testHashCode() {
+ MutableInstant instant = new MutableInstant();
+ instant.initFromEpochSecond(123, 456789012);
+
+ MutableInstant instant2 = new MutableInstant();
+ instant2.initFromEpochMilli(123456, 789012);
+
+ assertEquals(instant.hashCode(), instant2.hashCode());
+
+
+ instant2.initFromEpochMilli(123456, 789013);
+ assertNotEquals(instant.hashCode(), instant2.hashCode());
+ }
+
+ @Test
+ public void testToString() {
+ MutableInstant instant = new MutableInstant();
+ instant.initFromEpochSecond(123, 456789012);
+ assertEquals("MutableInstant[epochSecond=123, nano=456789012]", instant.toString());
+
+ instant.initFromEpochMilli(123456, 789012);
+ assertEquals("MutableInstant[epochSecond=123, nano=456789012]", instant.toString());
+ }
+}
\ No newline at end of file
[3/3] logging-log4j2 git commit: LOG4J2-1883 replace timeMillis with
Instant/MutableInstant in LogEvent;
support formatting date times in higher precision than milliseconds;
add Java 9 precise time source; update docs
Posted by rp...@apache.org.
LOG4J2-1883 replace timeMillis with Instant/MutableInstant in LogEvent; support formatting date times in higher precision than milliseconds; add Java 9 precise time source; update docs
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/a07d6ba4
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/a07d6ba4
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/a07d6ba4
Branch: refs/heads/LOG4J2-1883-instant-field
Commit: a07d6ba489d3b8311b52614c885ea6403fe5815f
Parents: 7955724
Author: rpopma <rp...@apache.org>
Authored: Sun Jan 14 13:48:25 2018 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sun Jan 21 22:29:58 2018 +0900
----------------------------------------------------------------------
log4j-core-java9/pom.xml | 11 +-
log4j-core-java9/src/assembly/java9.xml | 8 +-
.../apache/logging/log4j/core/util/Clock.java | 32 +++
.../apache/logging/log4j/core/util/Dummy.java | 24 --
.../apache/logging/log4j/core/util/Instant.java | 75 ++++++
.../logging/log4j/core/util/MutableInstant.java | 155 +++++++++++++
.../logging/log4j/core/util/PreciseClock.java | 36 +++
.../logging/log4j/core/util/SystemClock.java | 44 ++++
.../log4j/core/util/SystemMillisClock.java | 34 +++
.../apache/logging/log4j/core/util/Temp.java | 24 --
.../logging/log4j/core/AbstractLogEvent.java | 9 +
.../org/apache/logging/log4j/core/LogEvent.java | 17 +-
.../db/jpa/AbstractLogEventWrapperEntity.java | 21 ++
.../appender/db/jpa/BasicLogEventEntity.java | 15 +-
.../converter/InstantAttributeConverter.java | 58 +++++
.../logging/log4j/core/async/AsyncLogger.java | 6 +-
.../log4j/core/async/RingBufferLogEvent.java | 34 ++-
.../async/RingBufferLogEventTranslator.java | 22 +-
.../logging/log4j/core/impl/Log4jLogEvent.java | 77 ++++---
.../log4j/core/impl/MutableLogEvent.java | 33 ++-
.../core/impl/ReusableLogEventFactory.java | 6 +-
.../log4j/core/jackson/Initializers.java | 3 +
.../log4j/core/jackson/InstantMixIn.java | 55 +++++
.../log4j/core/jackson/JsonConstants.java | 1 +
.../log4j/core/jackson/LogEventJsonMixIn.java | 13 +-
.../jackson/LogEventWithContextListMixIn.java | 13 +-
.../log4j/core/jackson/XmlConstants.java | 1 +
.../core/pattern/DatePatternConverter.java | 100 +++++---
.../logging/log4j/core/util/ClockFactory.java | 27 ++-
.../log4j/core/util/DummyPreciseClock.java | 49 ++++
.../apache/logging/log4j/core/util/Instant.java | 72 ++++++
.../logging/log4j/core/util/MutableInstant.java | 152 ++++++++++++
.../logging/log4j/core/util/PreciseClock.java | 33 +++
.../core/util/datetime/FixedDateFormat.java | 122 +++++++++-
.../appender/JsonCompleteFileAppenderTest.java | 75 +++---
.../appender/XmlCompleteFileAppenderTest.java | 115 ++++------
.../core/appender/XmlFileAppenderTest.java | 40 ++--
.../core/appender/db/jpa/JpaH2AppenderTest.java | 11 +-
.../appender/db/jpa/JpaHsqldbAppenderTest.java | 11 +-
.../appender/db/jpa/LogEventEntityTest.java | 7 +
.../core/appender/db/jpa/TestBaseEntity.java | 9 +
.../InstantAttributeConverterTest.java | 68 ++++++
.../async/AsyncLoggerTimestampMessageTest.java | 2 +-
.../core/async/RingBufferLogEventTest.java | 28 +--
.../ConcurrentLoggingWithJsonLayoutTest.java | 2 +-
.../log4j/core/layout/JsonLayoutTest.java | 2 +-
.../log4j/core/layout/XmlLayoutTest.java | 5 +-
.../log4j/core/layout/YamlLayoutTest.java | 2 +-
.../core/parser/JsonLogEventParserTest.java | 3 +-
.../log4j/core/parser/LogEventParserTest.java | 2 +-
.../core/parser/XmlLogEventParserTest.java | 6 +
.../core/parser/YamlLogEventParserTest.java | 10 +-
.../core/pattern/DatePatternConverterTest.java | 74 ++++++
.../log4j/core/util/MutableInstantTest.java | 230 +++++++++++++++++++
.../core/util/datetime/FixedDateFormatTest.java | 15 ++
.../src/test/resources/META-INF/persistence.xml | 2 +
.../log4j/flume/appender/FlumeEvent.java | 10 +
.../src/main/resources/META-INF/persistence.xml | 2 +
src/site/xdoc/manual/layouts.xml.vm | 50 +++-
59 files changed, 1816 insertions(+), 347 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core-java9/pom.xml
----------------------------------------------------------------------
diff --git a/log4j-core-java9/pom.xml b/log4j-core-java9/pom.xml
index e05f30e..b46f8c9 100644
--- a/log4j-core-java9/pom.xml
+++ b/log4j-core-java9/pom.xml
@@ -33,6 +33,11 @@
<projectDir>/core</projectDir>
</properties>
<dependencies>
+ <!-- Naturally, all implementations require the log4j-api JAR -->
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-api</artifactId>
+ </dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
@@ -84,12 +89,6 @@
</goals>
</execution>
</executions>
- <configuration>
- <source>9</source>
- <target>9</target>
- <release>9</release>
- <proc>none</proc>
- </configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core-java9/src/assembly/java9.xml
----------------------------------------------------------------------
diff --git a/log4j-core-java9/src/assembly/java9.xml b/log4j-core-java9/src/assembly/java9.xml
index 3e59561..f8f129d 100644
--- a/log4j-core-java9/src/assembly/java9.xml
+++ b/log4j-core-java9/src/assembly/java9.xml
@@ -34,10 +34,10 @@
<excludes>
<exclude>module-info.class</exclude>
<exclude>**/Dummy.class</exclude>
- <exclude>**/spi/Provider.class</exclude>
- <exclude>**/util/PropertySource.class</exclude>
- <exclude>**/message/ThreadDumpMessage.class</exclude>
- <exclude>**/message/ThreadDumpMessage$ThreadInfoFactory.class</exclude>
+ <exclude>**/util/Clock.class</exclude>
+ <exclude>**/util/Instant.class</exclude>
+ <exclude>**/util/MutableInstant.class</exclude>
+ <exclude>**/util/PreciseClock.class</exclude>
</excludes>
</fileSet>
<fileSet>
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Clock.java
----------------------------------------------------------------------
diff --git a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Clock.java b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Clock.java
new file mode 100644
index 0000000..8c961d4
--- /dev/null
+++ b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Clock.java
@@ -0,0 +1,32 @@
+/*
+ * 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;
+
+// This class is here to allow {@link SystemClock}, {@link SystemMillisClock}
+// to compile. It will not be copied into the log4j-core module.
+
+/**
+ * Provides the time stamp used in log events.
+ */
+public interface Clock {
+ /**
+ * Returns the time in milliseconds since the epoch.
+ *
+ * @return the time in milliseconds since the epoch
+ */
+ long currentTimeMillis();
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Dummy.java
----------------------------------------------------------------------
diff --git a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Dummy.java b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Dummy.java
deleted file mode 100644
index 6bffac6..0000000
--- a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Dummy.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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;
-
-/**
- * This is a dummy class and is only here to allow module-info.java to compile. It will not
- * be copied into the log4j-api module.
- */
-public class Dummy {
-}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Instant.java
----------------------------------------------------------------------
diff --git a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Instant.java b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Instant.java
new file mode 100644
index 0000000..cd4ac9d
--- /dev/null
+++ b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Instant.java
@@ -0,0 +1,75 @@
+/*
+ * 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;
+
+// This class is here to allow {@link SystemClock}, {@link SystemMillisClock}
+// to compile. It will not be copied into the log4j-core module.
+
+/**
+ * Models a point in time, suitable for event timestamps.
+ * <p>
+ * Provides methods for obtaining high precision time information similar to the
+ * <a href="https://docs.oracle.com/javase/9/docs/api/java/time/Instant.html">Instant</a> class introduced in Java 8,
+ * while also supporting the legacy millisecond precision API.
+ * </p><p>
+ * Depending on the platform, time sources ({@link Clock} implementations) may produce high precision or millisecond
+ * precision time values. At the same time, some time value consumers (for example timestamp formatters) may only be
+ * able to consume time values of millisecond precision, while some others may require a high precision time value.
+ * </p><p>
+ * This class bridges these two time APIs.
+ * </p>
+ * @since 2.11
+ */
+public interface Instant {
+ /**
+ * Gets the number of seconds from the Java epoch of 1970-01-01T00:00:00Z.
+ * <p>
+ * The epoch second count is a simple incrementing count of seconds where second 0 is 1970-01-01T00:00:00Z.
+ * The nanosecond part of the day is returned by {@link #getNanoOfSecond()}.
+ * </p>
+ * @return the seconds from the epoch of 1970-01-01T00:00:00Z
+ */
+ long getEpochSecond();
+
+ /**
+ * Gets the number of nanoseconds, later along the time-line, from the start of the second.
+ * <p>
+ * The nanosecond-of-second value measures the total number of nanoseconds from the second returned by {@link #getEpochSecond()}.
+ * </p>
+ * @return the nanoseconds within the second, always positive, never exceeds {@code 999,999,999}
+ */
+ int getNanoOfSecond();
+
+ /**
+ * Gets the number of milliseconds from the Java epoch of 1970-01-01T00:00:00Z.
+ * <p>
+ * The epoch millisecond count is a simple incrementing count of milliseconds where millisecond 0 is 1970-01-01T00:00:00Z.
+ * The nanosecond part of the day is returned by {@link #getNanoOfMillisecond()}.
+ * </p>
+ * @return the milliseconds from the epoch of 1970-01-01T00:00:00Z
+ */
+ long getEpochMillisecond();
+
+ /**
+ * Gets the number of nanoseconds, later along the time-line, from the start of the millisecond.
+ * <p>
+ * The nanosecond-of-millisecond value measures the total number of nanoseconds from the millisecond returned by {@link #getEpochMillisecond()}.
+ * </p>
+ * @return the nanoseconds within the millisecond, always positive, never exceeds {@code 999,999}
+ */
+ int getNanoOfMillisecond();
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/MutableInstant.java
----------------------------------------------------------------------
diff --git a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/MutableInstant.java b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/MutableInstant.java
new file mode 100644
index 0000000..8960fc5
--- /dev/null
+++ b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/MutableInstant.java
@@ -0,0 +1,155 @@
+/*
+ * 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.apache.logging.log4j.util.PerformanceSensitive;
+
+import java.io.Serializable;
+
+// This class is here to allow {@link SystemClock}, {@link SystemMillisClock}
+// to compile. It will not be copied into the log4j-core module.
+
+/**
+ * An instantaneous point on the time line, used for high-precision log event timestamps.
+ * Modelled on <a href="https://docs.oracle.com/javase/9/docs/api/index.html?java/time/class-use/Instant.html">java.time.Instant</a>,
+ * except that this version is mutable to prevent allocating temporary objects that need to be garbage-collected later.
+ * <p>
+ * Instances of this class are <em>not</em> thread-safe and should not be shared between threads.
+ * </p>
+ *
+ * @since 2.11
+ */
+@PerformanceSensitive("allocation")
+public class MutableInstant implements Instant, Serializable {
+
+ private static final int MILLIS_PER_SECOND = 1000;
+ private static final int NANOS_PER_MILLI = 1000_000;
+ static final int NANOS_PER_SECOND = MILLIS_PER_SECOND * NANOS_PER_MILLI;
+
+ private long epochSecond;
+ private int nanoOfSecond;
+
+ @Override
+ public long getEpochSecond() {
+ return epochSecond;
+ }
+
+ @Override
+ public int getNanoOfSecond() {
+ return nanoOfSecond;
+ }
+
+ @Override
+ public long getEpochMillisecond() {
+ final int millis = nanoOfSecond / NANOS_PER_MILLI;
+ long epochMillisecond = epochSecond * MILLIS_PER_SECOND + millis;
+ return epochMillisecond;
+ }
+
+ @Override
+ public int getNanoOfMillisecond() {
+ final int millis = nanoOfSecond / NANOS_PER_MILLI;
+ int nanoOfMillisecond = nanoOfSecond - (millis * NANOS_PER_MILLI); // cheaper than nanoOfSecond % NANOS_PER_MILLI
+ return nanoOfMillisecond;
+ }
+
+ public void initFrom(final Instant other) {
+ this.epochSecond = other.getEpochSecond();
+ this.nanoOfSecond = other.getNanoOfSecond();
+ }
+
+ /**
+ * Updates the fields of this {@code MutableInstant} from the specified epoch millis.
+ * @param epochMilli the number of milliseconds from the Java epoch of 1970-01-01T00:00:00Z
+ * @param nanoOfMillisecond the number of nanoseconds, later along the time-line, from the start of the millisecond
+ */
+ public void initFromEpochMilli(final long epochMilli, final int nanoOfMillisecond) {
+ validateNanoOfMillisecond(nanoOfMillisecond);
+ this.epochSecond = epochMilli / MILLIS_PER_SECOND;
+ this.nanoOfSecond = (int) (epochMilli - (epochSecond * MILLIS_PER_SECOND)) * NANOS_PER_MILLI + nanoOfMillisecond;
+ }
+
+ private void validateNanoOfMillisecond(final int nanoOfMillisecond) {
+ if (nanoOfMillisecond < 0 || nanoOfMillisecond >= NANOS_PER_MILLI) {
+ throw new IllegalArgumentException("Invalid nanoOfMillisecond " + nanoOfMillisecond);
+ }
+ }
+
+ public void initFrom(final Clock clock) {
+ if (clock instanceof PreciseClock) {
+ ((PreciseClock) clock).init(this);
+ } else {
+ initFromEpochMilli(clock.currentTimeMillis(), 0);
+ }
+ }
+
+ /**
+ * Updates the fields of this {@code MutableInstant} from the specified instant components.
+ * @param epochSecond the number of seconds from the Java epoch of 1970-01-01T00:00:00Z
+ * @param nano the number of nanoseconds, later along the time-line, from the start of the second
+ */
+ public void initFromEpochSecond(final long epochSecond, final int nano) {
+ validateNanoOfSecond(nano);
+ this.epochSecond = epochSecond;
+ this.nanoOfSecond = nano;
+ }
+
+ private void validateNanoOfSecond(final int nano) {
+ if (nano < 0 || nano >= NANOS_PER_SECOND) {
+ throw new IllegalArgumentException("Invalid nanoOfSecond " + nano);
+ }
+ }
+
+ /**
+ * Updates the elements of the specified {@code long[]} result array from the specified instant components.
+ * @param epochSecond (input) the number of seconds from the Java epoch of 1970-01-01T00:00:00Z
+ * @param nano (input) the number of nanoseconds, later along the time-line, from the start of the second
+ * @param result (output) a two-element array to store the result: the first element is the number of milliseconds
+ * from the Java epoch of 1970-01-01T00:00:00Z,
+ * the second element is the number of nanoseconds, later along the time-line, from the start of the millisecond
+ */
+ public static void instantToMillisAndNanos(final long epochSecond, final int nano, final long[] result) {
+ int millis = nano / NANOS_PER_MILLI;
+ result[0] = epochSecond * MILLIS_PER_SECOND + millis;
+ result[1] = nano - (millis * NANOS_PER_MILLI); // cheaper than nanoOfSecond % NANOS_PER_MILLI
+ }
+
+ @Override
+ public boolean equals(final Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (!(object instanceof MutableInstant)) {
+ return false;
+ }
+ MutableInstant other = (MutableInstant) object;
+ return epochSecond == other.epochSecond && nanoOfSecond == other.nanoOfSecond;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + (int) (epochSecond ^ (epochSecond >>> 32));
+ result = 31 * result + nanoOfSecond;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "MutableInstant[epochSecond=" + epochSecond + ", nano=" + nanoOfSecond + "]";
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/PreciseClock.java
----------------------------------------------------------------------
diff --git a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/PreciseClock.java b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/PreciseClock.java
new file mode 100644
index 0000000..3d1f314
--- /dev/null
+++ b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/PreciseClock.java
@@ -0,0 +1,36 @@
+/*
+ * 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;
+
+// This class is here to allow {@link SystemClock}, {@link SystemMillisClock}
+// to compile. It will not be copied into the log4j-core module.
+
+/**
+ * Extension of the {@link Clock} interface that is able to provide more accurate time information than milliseconds
+ * since the epoch. {@code PreciseClock} implementations are free to return millisecond-precision time
+ * if that is the most accurate time information available on this platform.
+ * @since 2.11
+ */
+public interface PreciseClock extends Clock {
+
+ /**
+ * Initializes the specified instant with time information as accurate as available on this platform.
+ * @param mutableInstant the container to be initialized with the accurate time information
+ * @since 2.11
+ */
+ void init(final MutableInstant mutableInstant);
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/SystemClock.java
----------------------------------------------------------------------
diff --git a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/SystemClock.java b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/SystemClock.java
new file mode 100644
index 0000000..a74a1fd
--- /dev/null
+++ b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/SystemClock.java
@@ -0,0 +1,44 @@
+/*
+ * 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.time.Instant;
+
+/**
+ * Implementation of the {@code Clock} interface that returns the system time.
+ * @since 2.11
+ */
+public final class SystemClock implements Clock, PreciseClock {
+
+ /**
+ * Returns the system time.
+ * @return the result of calling {@code System.currentTimeMillis()}
+ */
+ @Override
+ public long currentTimeMillis() {
+ return System.currentTimeMillis();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void init(MutableInstant mutableInstant) {
+ Instant instant = java.time.Clock.systemUTC().instant();
+ mutableInstant.initFromEpochSecond(instant.getEpochSecond(), instant.getNano());
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/SystemMillisClock.java
----------------------------------------------------------------------
diff --git a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/SystemMillisClock.java b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/SystemMillisClock.java
new file mode 100644
index 0000000..f267320
--- /dev/null
+++ b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/SystemMillisClock.java
@@ -0,0 +1,34 @@
+/*
+ * 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 Clock} interface that returns the system time in millisecond granularity.
+ * @since 2.11
+ */
+public final class SystemMillisClock implements Clock {
+
+ /**
+ * Returns the system time.
+ * @return the result of calling {@code System.currentTimeMillis()}
+ */
+ @Override
+ public long currentTimeMillis() {
+ return System.currentTimeMillis();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Temp.java
----------------------------------------------------------------------
diff --git a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Temp.java b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Temp.java
deleted file mode 100644
index edb6d47..0000000
--- a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Temp.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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;
-
-/**
- * Temporary class to ensure the log4j-core-java9 jar has at least one class (or Maven will refuse to proceed).
- * To be removed as soon as real classes are added to the log4j-core-java9 module.
- */
-public class Temp {
-}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/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 11cc071..bc7d1b4 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
@@ -24,6 +24,8 @@ import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.ThreadContext.ContextStack;
import org.apache.logging.log4j.core.impl.ThrowableProxy;
+import org.apache.logging.log4j.core.util.Instant;
+import org.apache.logging.log4j.core.util.MutableInstant;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.util.ReadOnlyStringMap;
@@ -35,6 +37,8 @@ public abstract class AbstractLogEvent implements LogEvent {
private static final long serialVersionUID = 1L;
+ private MutableInstant instant = new MutableInstant();
+
/**
* Subclasses should implement this method to provide an immutable version.
*/
@@ -122,6 +126,11 @@ public abstract class AbstractLogEvent implements LogEvent {
}
@Override
+ public Instant getInstant() {
+ return instant;
+ }
+
+ @Override
public boolean isEndOfBatch() {
return false;
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/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 41b20a7..0f72050 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
@@ -24,6 +24,7 @@ import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.core.impl.ThrowableProxy;
+import org.apache.logging.log4j.core.util.Instant;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.util.ReadOnlyStringMap;
@@ -124,13 +125,27 @@ public interface LogEvent extends Serializable {
/**
* Gets event time in milliseconds since midnight, January 1, 1970 UTC.
+ * Use {@link #getInstant()} to get higher precision timestamp information if available on this platform.
*
- * @return milliseconds since midnight, January 1, 1970 UTC.
+ * @return the milliseconds component of this log event's {@linkplain #getInstant() timestamp}
* @see java.lang.System#currentTimeMillis()
*/
long getTimeMillis();
/**
+ * Returns the timestamp when the message was logged.
+ * <p>
+ * <b>Caution</b>: if this {@code LogEvent} implementation is mutable and reused for multiple consecutive log messages,
+ * then the {@code Instant} object returned by this method is also mutable and reused.
+ * Client code should not keep a reference to the returned object but make a copy instead.
+ * </p>
+ *
+ * @return the {@code Instant} holding timestamp details for this log event
+ * @since 2.11
+ */
+ Instant getInstant();
+
+ /**
* Gets the source of logging request.
*
* @return source of logging request, may be null.
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/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 60ca692..6c736c6 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
@@ -26,6 +26,7 @@ import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.core.AbstractLogEvent;
+import org.apache.logging.log4j.core.util.Instant;
import org.apache.logging.log4j.util.ReadOnlyStringMap;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.db.jpa.converter.ContextDataAttributeConverter;
@@ -216,6 +217,26 @@ public abstract class AbstractLogEventWrapperEntity implements LogEvent {
/**
* A no-op mutator to satisfy JPA requirements, as this entity is write-only.
*
+ * @param instant Ignored.
+ */
+ @SuppressWarnings("unused")
+ public void setInstant(final Instant instant) {
+ // this entity is write-only
+ }
+
+ /**
+ * A no-op mutator to satisfy JPA requirements, as this entity is write-only.
+ *
+ * @param nanoOfMillisecond Ignored.
+ */
+ @SuppressWarnings("unused")
+ public void setNanoOfMillisecond(final int nanoOfMillisecond) {
+ // this entity is write-only
+ }
+
+ /**
+ * A no-op mutator to satisfy JPA requirements, as this entity is write-only.
+ *
* @param throwable Ignored.
*/
@SuppressWarnings("unused")
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/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 5c06316..492aa61 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
@@ -26,14 +26,9 @@ 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.appender.db.jpa.converter.ContextMapAttributeConverter;
-import org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackAttributeConverter;
-import org.apache.logging.log4j.core.appender.db.jpa.converter.LevelAttributeConverter;
-import org.apache.logging.log4j.core.appender.db.jpa.converter.MarkerAttributeConverter;
-import org.apache.logging.log4j.core.appender.db.jpa.converter.MessageAttributeConverter;
-import org.apache.logging.log4j.core.appender.db.jpa.converter.StackTraceElementAttributeConverter;
-import org.apache.logging.log4j.core.appender.db.jpa.converter.ThrowableAttributeConverter;
+import org.apache.logging.log4j.core.appender.db.jpa.converter.*;
import org.apache.logging.log4j.core.impl.ThrowableProxy;
+import org.apache.logging.log4j.core.util.Instant;
import org.apache.logging.log4j.message.Message;
/**
@@ -189,6 +184,12 @@ public abstract class BasicLogEventEntity extends AbstractLogEventWrapperEntity
return this.getWrappedEvent().getTimeMillis();
}
+ @Override
+ @Convert(converter = InstantAttributeConverter.class)
+ public Instant getInstant() {
+ return this.getWrappedEvent().getInstant();
+ }
+
/**
* 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.
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/InstantAttributeConverter.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/InstantAttributeConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/InstantAttributeConverter.java
new file mode 100644
index 0000000..408d972
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/InstantAttributeConverter.java
@@ -0,0 +1,58 @@
+/*
+ * 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.appender.db.jpa.converter;
+
+import org.apache.logging.log4j.core.util.Instant;
+import org.apache.logging.log4j.core.util.MutableInstant;
+import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.Strings;
+
+import javax.persistence.AttributeConverter;
+import javax.persistence.Converter;
+
+/**
+ * A JPA 2.1 attribute converter for {@link Instant}s in {@link org.apache.logging.log4j.core.LogEvent}s. This
+ * converter is capable of converting both to and from {@link String}s.
+ */
+@Converter(autoApply = false)
+public class InstantAttributeConverter implements AttributeConverter<Instant, String> {
+ private static final StatusLogger LOGGER = StatusLogger.getLogger();
+
+ @Override
+ public String convertToDatabaseColumn(final Instant instant) {
+ if (instant == null) {
+ return null;
+ }
+ return instant.getEpochSecond() + "," + instant.getNanoOfSecond();
+ }
+
+ @Override
+ public Instant convertToEntityAttribute(final String s) {
+ if (Strings.isEmpty(s)) {
+ return null;
+ }
+
+ int pos = s.indexOf(",");
+ long epochSecond = Long.parseLong(s.substring(0, pos));
+ int nanos = Integer.parseInt(s.substring(pos + 1, s.length()));
+
+ MutableInstant result = new MutableInstant();
+ result.initFromEpochSecond(epochSecond, nanos);
+ return result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/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 036a130..358422c 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
@@ -203,8 +203,8 @@ public class AsyncLogger extends Logger implements EventTranslatorVararg<RingBuf
// location (expensive to calculate)
calcLocationIfRequested(fqcn), //
- CLOCK.currentTimeMillis(), //
- nanoClock.nanoTime() //
+ CLOCK, //
+ nanoClock //
);
}
@@ -293,7 +293,7 @@ public class AsyncLogger extends Logger implements EventTranslatorVararg<RingBuf
// in the AsyncLogger#actualAsyncLog method
CONTEXT_DATA_INJECTOR.injectContextData(null, (StringMap) event.getContextData()),
contextStack, currentThread.getId(), threadName, currentThread.getPriority(), location,
- CLOCK.currentTimeMillis(), nanoClock.nanoTime());
+ CLOCK, nanoClock);
}
/**
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/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 b0b023b..af06e47 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
@@ -27,7 +27,7 @@ import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.impl.ContextDataFactory;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.core.impl.ThrowableProxy;
-import org.apache.logging.log4j.core.util.Constants;
+import org.apache.logging.log4j.core.util.*;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.message.ParameterizedMessage;
import org.apache.logging.log4j.message.ReusableMessage;
@@ -70,7 +70,7 @@ public class RingBufferLogEvent implements LogEvent, ReusableMessage, CharSequen
private int threadPriority;
private long threadId;
- private long currentTimeMillis;
+ private MutableInstant instant = new MutableInstant();
private long nanoTime;
private short parameterCount;
private boolean includeLocation;
@@ -92,18 +92,18 @@ public class RingBufferLogEvent implements LogEvent, ReusableMessage, CharSequen
private transient AsyncLogger asyncLogger;
public void setValues(final AsyncLogger anAsyncLogger, final String aLoggerName, final Marker aMarker,
- final String theFqcn, final Level aLevel, final Message msg, final Throwable aThrowable,
- final StringMap mutableContextData, final ContextStack aContextStack, final long threadId,
- final String threadName, final int threadPriority, final StackTraceElement aLocation,
- final long aCurrentTimeMillis, final long aNanoTime) {
+ final String theFqcn, final Level aLevel, final Message msg, final Throwable aThrowable,
+ final StringMap mutableContextData, final ContextStack aContextStack, final long threadId,
+ final String threadName, final int threadPriority, final StackTraceElement aLocation,
+ final Clock clock, final NanoClock nanoClock) {
this.threadPriority = threadPriority;
this.threadId = threadId;
- this.currentTimeMillis = aCurrentTimeMillis;
- this.nanoTime = aNanoTime;
this.level = aLevel;
this.threadName = threadName;
this.loggerName = aLoggerName;
setMessage(msg);
+ initTime(clock);
+ this.nanoTime = nanoClock.nanoTime();
this.thrown = aThrowable;
this.thrownProxy = null;
this.marker = aMarker;
@@ -114,6 +114,14 @@ public class RingBufferLogEvent implements LogEvent, ReusableMessage, CharSequen
this.asyncLogger = anAsyncLogger;
}
+ private void initTime(final Clock clock) {
+ if (message instanceof TimestampMessage) {
+ instant.initFromEpochMilli(((TimestampMessage) message).getTimestamp(), 0);
+ } else {
+ instant.initFrom(clock);
+ }
+ }
+
@Override
public LogEvent toImmutable() {
return createMemento();
@@ -367,7 +375,12 @@ public class RingBufferLogEvent implements LogEvent, ReusableMessage, CharSequen
@Override
public long getTimeMillis() {
- return message instanceof TimestampMessage ? ((TimestampMessage) message).getTimestamp() :currentTimeMillis;
+ return message instanceof TimestampMessage ? ((TimestampMessage) message).getTimestamp() : instant.getEpochMillisecond();
+ }
+
+ @Override
+ public Instant getInstant() {
+ return instant;
}
@Override
@@ -443,7 +456,8 @@ public class RingBufferLogEvent implements LogEvent, ReusableMessage, CharSequen
.setThreadPriority(threadPriority) //
.setThrown(getThrown()) // may deserialize from thrownProxy
.setThrownProxy(thrownProxy) // avoid unnecessarily creating thrownProxy
- .setTimeMillis(currentTimeMillis);
+ .setInstant(instant) //
+ ;
}
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/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 cb3e6ca..ec2ff1c 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
@@ -21,6 +21,8 @@ import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.ThreadContext.ContextStack;
import org.apache.logging.log4j.core.ContextDataInjector;
import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory;
+import org.apache.logging.log4j.core.util.Clock;
+import org.apache.logging.log4j.core.util.NanoClock;
import org.apache.logging.log4j.util.StringMap;
import org.apache.logging.log4j.message.Message;
@@ -48,8 +50,8 @@ public class RingBufferLogEventTranslator implements
private String threadName = Thread.currentThread().getName();
private int threadPriority = Thread.currentThread().getPriority();
private StackTraceElement location;
- private long currentTimeMillis;
- private long nanoTime;
+ private Clock clock;
+ private NanoClock nanoClock;
// @Override
@Override
@@ -59,7 +61,7 @@ public class RingBufferLogEventTranslator implements
// config properties are taken care of in the EventHandler thread
// in the AsyncLogger#actualAsyncLog method
injector.injectContextData(null, (StringMap) event.getContextData()), contextStack,
- threadId, threadName, threadPriority, location, currentTimeMillis, nanoTime);
+ threadId, threadName, threadPriority, location, clock, nanoClock);
clear(); // clear the translator
}
@@ -77,15 +79,15 @@ public class RingBufferLogEventTranslator implements
null, // t
null, // contextStack
null, // location
- 0, // currentTimeMillis
- 0 // nanoTime
+ null, // clock
+ null // nanoClock
);
}
public void setBasicValues(final AsyncLogger anAsyncLogger, final String aLoggerName, final Marker aMarker,
- final String theFqcn, final Level aLevel, final Message msg, final Throwable aThrowable,
- final ContextStack aContextStack, final StackTraceElement aLocation,
- final long aCurrentTimeMillis, final long aNanoTime) {
+ final String theFqcn, final Level aLevel, final Message msg, final Throwable aThrowable,
+ final ContextStack aContextStack, final StackTraceElement aLocation,
+ final Clock aClock, final NanoClock aNanoClock) {
this.asyncLogger = anAsyncLogger;
this.loggerName = aLoggerName;
this.marker = aMarker;
@@ -95,8 +97,8 @@ public class RingBufferLogEventTranslator implements
this.thrown = aThrowable;
this.contextStack = aContextStack;
this.location = aLocation;
- this.currentTimeMillis = aCurrentTimeMillis;
- this.nanoTime = aNanoTime;
+ this.clock = aClock;
+ this.nanoClock = aNanoClock;
}
public void updateThreadValues() {
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/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 74ddaf6..7332531 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,15 +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.ContextDataInjector;
+import org.apache.logging.log4j.core.util.*;
import org.apache.logging.log4j.util.ReadOnlyStringMap;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.async.RingBufferLogEvent;
import org.apache.logging.log4j.core.config.LoggerConfig;
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.ReusableMessage;
@@ -63,7 +60,7 @@ public class Log4jLogEvent implements LogEvent {
private final Level level;
private final String loggerName;
private Message message;
- private final long timeMillis;
+ private final MutableInstant instant = new MutableInstant();
private final transient Throwable thrown;
private ThrowableProxy thrownProxy;
private final StringMap contextData;
@@ -86,7 +83,7 @@ public class Log4jLogEvent implements LogEvent {
private String loggerName;
private Message message;
private Throwable thrown;
- private long timeMillis = CLOCK.currentTimeMillis();
+ private MutableInstant instant = new MutableInstant();
private ThrowableProxy thrownProxy;
private StringMap contextData = createContextData((List<Property>) null);
private ThreadContext.ContextStack contextStack = ThreadContext.getImmutableStack();
@@ -116,7 +113,7 @@ public class Log4jLogEvent implements LogEvent {
this.level = other.getLevel();
this.loggerName = other.getLoggerName();
this.message = other.getMessage();
- this.timeMillis = other.getTimeMillis();
+ this.instant.initFrom(other.getInstant());
this.thrown = other.getThrown();
this.contextStack = other.getContextStack();
this.includeLocation = other.isIncludeLocation();
@@ -183,7 +180,12 @@ public class Log4jLogEvent implements LogEvent {
}
public Builder setTimeMillis(final long timeMillis) {
- this.timeMillis = timeMillis;
+ this.instant.initFromEpochMilli(timeMillis, 0);
+ return this;
+ }
+
+ public Builder setInstant(final Instant instant) {
+ this.instant.initFrom(instant);
return this;
}
@@ -256,13 +258,20 @@ public class Log4jLogEvent implements LogEvent {
@Override
public Log4jLogEvent build() {
+ initTimeFields();
final Log4jLogEvent result = new Log4jLogEvent(loggerName, marker, loggerFqcn, level, message, thrown,
- thrownProxy, contextData, contextStack, threadId, threadName, threadPriority, source, timeMillis,
- nanoTime);
+ thrownProxy, contextData, contextStack, threadId, threadName, threadPriority, source,
+ instant.getEpochMillisecond(), instant.getNanoOfMillisecond(), nanoTime);
result.setIncludeLocation(includeLocation);
result.setEndOfBatch(endOfBatch);
return result;
}
+
+ private void initTimeFields() {
+ if (instant.getEpochMillisecond() == 0) {
+ instant.initFrom(CLOCK);
+ }
+ }
}
/**
@@ -275,7 +284,7 @@ public class Log4jLogEvent implements LogEvent {
public Log4jLogEvent() {
this(Strings.EMPTY, null, Strings.EMPTY, null, null, (Throwable) null, null, null, null, 0, null,
- 0, null, CLOCK.currentTimeMillis(), nanoClock.nanoTime());
+ 0, null, CLOCK.currentTimeMillis(), 0, nanoClock.nanoTime());
}
/**
@@ -285,7 +294,7 @@ public class Log4jLogEvent implements LogEvent {
@Deprecated
public Log4jLogEvent(final long timestamp) {
this(Strings.EMPTY, null, Strings.EMPTY, null, null, (Throwable) null, null, null, null, 0, null,
- 0, null, timestamp, nanoClock.nanoTime());
+ 0, null, timestamp, 0, nanoClock.nanoTime());
}
/**
@@ -325,7 +334,7 @@ public class Log4jLogEvent implements LogEvent {
null, // LOG4J2-628 use log4j.Clock for timestamps
// LOG4J2-744 unless TimestampMessage already has one
message instanceof TimestampMessage ? ((TimestampMessage) message).getTimestamp() :
- CLOCK.currentTimeMillis(), nanoClock.nanoTime());
+ CLOCK.currentTimeMillis(), 0, nanoClock.nanoTime());
}
/**
@@ -349,7 +358,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, createContextData(mdc), ndc, 0,
- threadName, 0, location, timestampMillis, nanoClock.nanoTime());
+ threadName, 0, location, timestampMillis, 0, nanoClock.nanoTime());
}
/**
@@ -377,7 +386,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, createContextData(mdc), ndc, 0, threadName, 0, location, timestamp, nanoClock.nanoTime());
+ thrownProxy, createContextData(mdc), ndc, 0, threadName, 0, location, timestamp, 0, nanoClock.nanoTime());
return result;
}
@@ -397,6 +406,7 @@ public class Log4jLogEvent implements LogEvent {
* @param threadPriority the thread priority
* @param source The locations of the caller.
* @param timestampMillis The timestamp of the event.
+ * @param nanoOfMillisecond the nanoseconds within the millisecond, always positive, never exceeds {@code 999,999}
* @param nanoTime The value of the running Java Virtual Machine's high-resolution time source when the event was
* created.
*/
@@ -404,7 +414,7 @@ public class Log4jLogEvent implements LogEvent {
final Message message, final Throwable thrown, final ThrowableProxy thrownProxy,
final StringMap contextData, final ThreadContext.ContextStack contextStack, final long threadId,
final String threadName, final int threadPriority, final StackTraceElement source,
- final long timestampMillis, final long nanoTime) {
+ final long timestampMillis, final int nanoOfMillisecond, final long nanoTime) {
this.loggerName = loggerName;
this.marker = marker;
this.loggerFqcn = loggerFQCN;
@@ -414,9 +424,10 @@ public class Log4jLogEvent implements LogEvent {
this.thrownProxy = thrownProxy;
this.contextData = contextData == null ? ContextDataFactory.createContextData() : contextData;
this.contextStack = contextStack == null ? ThreadContext.EMPTY_STACK : contextStack;
- this.timeMillis = message instanceof TimestampMessage
+ long millis = message instanceof TimestampMessage
? ((TimestampMessage) message).getTimestamp()
: timestampMillis;
+ this.instant.initFromEpochMilli(millis, nanoOfMillisecond);
this.threadId = threadId;
this.threadName = threadName;
this.threadPriority = threadPriority;
@@ -539,12 +550,20 @@ public class Log4jLogEvent implements LogEvent {
}
/**
- * Returns the time in milliseconds from the epoch when the event occurred.
- * @return The time the event occurred.
+ * {@inheritDoc}
*/
@Override
public long getTimeMillis() {
- return timeMillis;
+ return instant.getEpochMillisecond();
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 2.11
+ */
+ @Override
+ public Instant getInstant() {
+ return instant;
}
/**
@@ -707,7 +726,8 @@ 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.contextData, proxy.contextStack, proxy.threadId,
- proxy.threadName, proxy.threadPriority, proxy.source, proxy.timeMillis, proxy.nanoTime);
+ proxy.threadName, proxy.threadPriority, proxy.source, proxy.timeMillis, proxy.nanoOfMillisecond,
+ proxy.nanoTime);
result.setEndOfBatch(proxy.isEndOfBatch);
result.setIncludeLocation(proxy.isLocationRequired);
return result;
@@ -759,7 +779,7 @@ public class Log4jLogEvent implements LogEvent {
if (includeLocation != that.includeLocation) {
return false;
}
- if (timeMillis != that.timeMillis) {
+ if (!instant.equals(that.instant)) {
return false;
}
if (nanoTime != that.nanoTime) {
@@ -816,7 +836,7 @@ public class Log4jLogEvent implements LogEvent {
result = 31 * result + (level != null ? level.hashCode() : 0);
result = 31 * result + loggerName.hashCode();
result = 31 * result + message.hashCode();
- result = 31 * result + (int) (timeMillis ^ (timeMillis >>> 32));
+ result = 31 * result + instant.hashCode();
result = 31 * result + (int) (nanoTime ^ (nanoTime >>> 32));
result = 31 * result + (thrown != null ? thrown.hashCode() : 0);
result = 31 * result + (thrownProxy != null ? thrownProxy.hashCode() : 0);
@@ -849,6 +869,8 @@ public class Log4jLogEvent implements LogEvent {
/** since 2.8 */
private String messageString;
private final long timeMillis;
+ /** since 2.11 */
+ private final int nanoOfMillisecond;
private final transient Throwable thrown;
private final ThrowableProxy thrownProxy;
/** @since 2.7 */
@@ -873,7 +895,8 @@ public class Log4jLogEvent implements LogEvent {
this.message = event.message instanceof ReusableMessage
? memento((ReusableMessage) event.message)
: event.message;
- this.timeMillis = event.timeMillis;
+ this.timeMillis = event.instant.getEpochMillisecond();
+ this.nanoOfMillisecond = event.instant.getNanoOfMillisecond();
this.thrown = event.thrown;
this.thrownProxy = event.thrownProxy;
this.contextData = event.contextData;
@@ -897,7 +920,8 @@ public class Log4jLogEvent implements LogEvent {
message = temp instanceof ReusableMessage
? memento((ReusableMessage) temp)
: temp;
- this.timeMillis = event.getTimeMillis();
+ this.timeMillis = event.getInstant().getEpochMillisecond();
+ this.nanoOfMillisecond = event.getInstant().getNanoOfMillisecond();
this.thrown = event.getThrown();
this.thrownProxy = event.getThrownProxy();
this.contextData = memento(event.getContextData());
@@ -942,7 +966,7 @@ public class Log4jLogEvent implements LogEvent {
protected Object readResolve() {
final Log4jLogEvent result = new Log4jLogEvent(loggerName, marker, loggerFQCN, level, message(), thrown,
thrownProxy, contextData, contextStack, threadId, threadName, threadPriority, source, timeMillis,
- nanoTime);
+ nanoOfMillisecond, nanoTime);
result.setEndOfBatch(isEndOfBatch);
result.setIncludeLocation(isLocationRequired);
return result;
@@ -959,5 +983,4 @@ public class Log4jLogEvent implements LogEvent {
return new SimpleMessage(messageString);
}
}
-
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
index acc31b3..ec807d3 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
@@ -26,11 +26,8 @@ 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.InternalAsyncUtil;
-import org.apache.logging.log4j.core.util.Constants;
-import org.apache.logging.log4j.message.Message;
-import org.apache.logging.log4j.message.ParameterizedMessage;
-import org.apache.logging.log4j.message.ReusableMessage;
-import org.apache.logging.log4j.message.SimpleMessage;
+import org.apache.logging.log4j.core.util.*;
+import org.apache.logging.log4j.message.*;
import org.apache.logging.log4j.util.ReadOnlyStringMap;
import org.apache.logging.log4j.util.StackLocatorUtil;
import org.apache.logging.log4j.util.StringBuilders;
@@ -46,7 +43,7 @@ public class MutableLogEvent implements LogEvent, ReusableMessage {
private int threadPriority;
private long threadId;
- private long timeMillis;
+ private MutableInstant instant = new MutableInstant();
private long nanoTime;
private short parameterCount;
private boolean includeLocation;
@@ -95,10 +92,11 @@ public class MutableLogEvent implements LogEvent, ReusableMessage {
this.marker = event.getMarker();
this.level = event.getLevel();
this.loggerName = event.getLoggerName();
- this.timeMillis = event.getTimeMillis();
this.thrown = event.getThrown();
this.thrownProxy = event.getThrownProxy();
+ this.instant.initFrom(event.getInstant());
+
// NOTE: this ringbuffer event SHOULD NOT keep a reference to the specified
// thread-local MutableLogEvent's context data, because then two threads would call
// ReadOnlyStringMap.clear() on the same shared instance, resulting in data corruption.
@@ -307,13 +305,27 @@ public class MutableLogEvent implements LogEvent, ReusableMessage {
this.thrown = thrown;
}
+ void initTime(final Clock clock, final NanoClock nanoClock) {
+ if (message instanceof TimestampMessage) {
+ instant.initFromEpochMilli(((TimestampMessage) message).getTimestamp(), 0);
+ } else {
+ instant.initFrom(clock);
+ }
+ nanoTime = nanoClock.nanoTime();
+ }
+
@Override
public long getTimeMillis() {
- return timeMillis;
+ return instant.getEpochMillisecond();
}
public void setTimeMillis(final long timeMillis) {
- this.timeMillis = timeMillis;
+ this.instant.initFromEpochMilli(timeMillis, 0);
+ }
+
+ @Override
+ public Instant getInstant() {
+ return instant;
}
/**
@@ -468,7 +480,8 @@ public class MutableLogEvent implements LogEvent, ReusableMessage {
.setThreadPriority(threadPriority) //
.setThrown(getThrown()) // may deserialize from thrownProxy
.setThrownProxy(thrownProxy) // avoid unnecessarily creating thrownProxy
- .setTimeMillis(timeMillis);
+ .setInstant(instant) //
+ ;
}
private Message getNonNullImmutableMessage() {
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java
index bef1b8d..0ecefed 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java
@@ -28,7 +28,6 @@ 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.message.Message;
-import org.apache.logging.log4j.message.TimestampMessage;
import org.apache.logging.log4j.util.StringMap;
/**
@@ -79,13 +78,10 @@ public class ReusableLogEventFactory implements LogEventFactory {
result.setLoggerFqcn(fqcn);
result.setLevel(level == null ? Level.OFF : level);
result.setMessage(message);
+ result.initTime(CLOCK, Log4jLogEvent.getNanoClock());
result.setThrown(t);
result.setContextData(injector.injectContextData(properties, (StringMap) result.getContextData()));
result.setContextStack(ThreadContext.getDepth() == 0 ? ThreadContext.EMPTY_STACK : ThreadContext.cloneStack());// mutable copy
- result.setTimeMillis(message instanceof TimestampMessage
- ? ((TimestampMessage) message).getTimestamp()
- : CLOCK.currentTimeMillis());
- result.setNanoTime(Log4jLogEvent.getNanoClock().nanoTime());
if (THREAD_NAME_CACHING_STRATEGY == ThreadNameCachingStrategy.UNCACHED) {
result.setThreadName(Thread.currentThread().getName()); // Thread.getName() allocates Objects on each call
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Initializers.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Initializers.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Initializers.java
index 65c8438..18e30e2 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Initializers.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Initializers.java
@@ -27,6 +27,7 @@ import org.apache.logging.log4j.message.ObjectMessage;
import com.fasterxml.jackson.databind.Module.SetupContext;
import com.fasterxml.jackson.databind.module.SimpleModule;
+import org.apache.logging.log4j.core.util.Instant;
/**
* Initialization utils.
@@ -47,6 +48,7 @@ class Initializers {
// Log4j API classes: we do not want to edit those with Jackson annotations because the API module should not depend on Jackson.
context.setMixInAnnotations(Marker.class, MarkerMixIn.class);
context.setMixInAnnotations(Level.class, LevelMixIn.class);
+ context.setMixInAnnotations(Instant.class, InstantMixIn.class);
context.setMixInAnnotations(LogEvent.class, LogEventWithContextListMixIn.class);
// Log4j Core classes: we do not want to bring in Jackson at runtime if we do not have to.
context.setMixInAnnotations(ExtendedStackTraceElement.class, ExtendedStackTraceElementMixIn.class);
@@ -68,6 +70,7 @@ class Initializers {
// Log4j API classes: we do not want to edit those with Jackson annotations because the API module should not depend on Jackson.
context.setMixInAnnotations(Marker.class, MarkerMixIn.class);
context.setMixInAnnotations(Level.class, LevelMixIn.class);
+ context.setMixInAnnotations(Instant.class, InstantMixIn.class);
context.setMixInAnnotations(LogEvent.class, LogEventJsonMixIn.class); // different ThreadContext handling
// Log4j Core classes: we do not want to bring in Jackson at runtime if we do not have to.
context.setMixInAnnotations(ExtendedStackTraceElement.class, ExtendedStackTraceElementMixIn.class);
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/InstantMixIn.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/InstantMixIn.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/InstantMixIn.java
new file mode 100644
index 0000000..44b9a6d
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/InstantMixIn.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.jackson;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonValue;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.core.util.Instant;
+
+/**
+ * Jackson mix-in for {@link Instant}.
+ * <p>
+ * <em>Consider this class private.</em>
+ * </p>
+ * @see Marker
+ */
+@JsonIgnoreProperties({ "epochMillisecond", "nanoOfMillisecond" })
+abstract class InstantMixIn {
+
+ @JsonCreator
+ InstantMixIn(
+ // @formatter:off
+ @JsonProperty("epochSecond") final long epochSecond,
+ @JsonProperty("nanoOfSecond") final int nanoOfSecond)
+ // @formatter:on
+ {
+ // empty
+ }
+
+ @JsonProperty("epochSecond")
+ @JacksonXmlProperty(localName = "epochSecond", isAttribute = true)
+ abstract long getEpochSecond();
+
+ @JsonProperty("nanoOfSecond")
+ @JacksonXmlProperty(localName = "nanoOfSecond", isAttribute = true)
+ abstract int getNanoOfSecond();
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/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 8e9ed2c..bb9898d 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
@@ -31,4 +31,5 @@ public final class JsonConstants {
public static final String ELT_MESSAGE = "message";
public static final String ELT_EXTENDED_STACK_TRACE = "extendedStackTrace";
public static final String ELT_NANO_TIME = "nanoTime";
+ public static final String ELT_INSTANT = "instant";
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventJsonMixIn.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventJsonMixIn.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventJsonMixIn.java
index b659e9b..6c27295 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventJsonMixIn.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventJsonMixIn.java
@@ -21,6 +21,7 @@ import java.util.Map;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.ThreadContext.ContextStack;
+import org.apache.logging.log4j.core.util.Instant;
import org.apache.logging.log4j.util.ReadOnlyStringMap;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.impl.ThrowableProxy;
@@ -40,7 +41,7 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
@JsonRootName(XmlConstants.ELT_EVENT)
@JacksonXmlRootElement(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_EVENT)
@JsonFilter("org.apache.logging.log4j.core.impl.Log4jLogEvent")
-@JsonPropertyOrder({ "timeMillis", "threadName", "level", "loggerName", "marker", "message", "thrown", XmlConstants.ELT_CONTEXT_MAP,
+@JsonPropertyOrder({ "timeMillis", XmlConstants.ELT_INSTANT, "threadName", "level", "loggerName", "marker", "message", "thrown", XmlConstants.ELT_CONTEXT_MAP,
JsonConstants.ELT_CONTEXT_STACK, "loggerFQCN", "Source", "endOfBatch" })
abstract class LogEventJsonMixIn implements LogEvent {
@@ -126,11 +127,17 @@ abstract class LogEventJsonMixIn implements LogEvent {
@Override
public abstract ThrowableProxy getThrownProxy();
- @JsonProperty()
- @JacksonXmlProperty(isAttribute = true)
+ @JsonIgnore // ignore from 2.11
+// @JsonProperty()
+// @JacksonXmlProperty(isAttribute = true)
@Override
public abstract long getTimeMillis();
+ @JsonProperty(JsonConstants.ELT_INSTANT)
+ @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_INSTANT)
+ @Override
+ public abstract Instant getInstant();
+
@JsonProperty()
@JacksonXmlProperty(isAttribute = true)
@Override
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventWithContextListMixIn.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventWithContextListMixIn.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventWithContextListMixIn.java
index 176d82d..b71fcfc 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventWithContextListMixIn.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventWithContextListMixIn.java
@@ -21,6 +21,7 @@ import java.util.Map;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.ThreadContext.ContextStack;
+import org.apache.logging.log4j.core.util.Instant;
import org.apache.logging.log4j.util.ReadOnlyStringMap;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.impl.ThrowableProxy;
@@ -40,7 +41,7 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
@JsonRootName(XmlConstants.ELT_EVENT)
@JacksonXmlRootElement(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_EVENT)
@JsonFilter("org.apache.logging.log4j.core.impl.Log4jLogEvent")
-@JsonPropertyOrder({ "timeMillis", "threadName", "level", "loggerName", "marker", "message", "thrown", XmlConstants.ELT_CONTEXT_MAP,
+@JsonPropertyOrder({ "timeMillis", XmlConstants.ELT_INSTANT, "threadName", "level", "loggerName", "marker", "message", "thrown", XmlConstants.ELT_CONTEXT_MAP,
JsonConstants.ELT_CONTEXT_STACK, "loggerFQCN", "Source", "endOfBatch" })
abstract class LogEventWithContextListMixIn implements LogEvent {
@@ -125,11 +126,17 @@ abstract class LogEventWithContextListMixIn implements LogEvent {
@Override
public abstract ThrowableProxy getThrownProxy();
- @JsonProperty()
- @JacksonXmlProperty(isAttribute = true)
+ @JsonIgnore // ignore from 2.11
+// @JsonProperty()
+// @JacksonXmlProperty(isAttribute = true)
@Override
public abstract long getTimeMillis();
+ @JsonProperty(JsonConstants.ELT_INSTANT)
+ @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_INSTANT)
+ @Override
+ public abstract Instant getInstant();
+
@JsonProperty()
@JacksonXmlProperty(isAttribute = true)
@Override
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/XmlConstants.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/XmlConstants.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/XmlConstants.java
index c3b03cc..0871440 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/XmlConstants.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/XmlConstants.java
@@ -27,6 +27,7 @@ public final class XmlConstants {
public static final String ELT_EVENT = "Event";
public static final String ELT_EXTENDED_STACK_TRACE = "ExtendedStackTrace";
public static final String ELT_EXTENDED_STACK_TRACE_ITEM = "ExtendedStackTraceItem";
+ public static final String ELT_INSTANT = "Instant";
public static final String ELT_MARKER = "Marker";
public static final String ELT_MESSAGE = "Message";
public static final String ELT_PARENTS = "Parents";
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07d6ba4/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/DatePatternConverter.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/DatePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/DatePatternConverter.java
index 732acf8..aa49ee4 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/DatePatternConverter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/DatePatternConverter.java
@@ -25,6 +25,8 @@ import java.util.concurrent.atomic.AtomicReference;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.util.Constants;
+import org.apache.logging.log4j.core.util.Instant;
+import org.apache.logging.log4j.core.util.MutableInstant;
import org.apache.logging.log4j.core.util.datetime.FastDateFormat;
import org.apache.logging.log4j.core.util.datetime.FixedDateFormat;
import org.apache.logging.log4j.core.util.datetime.FixedDateFormat.FixedFormat;
@@ -40,10 +42,11 @@ public final class DatePatternConverter extends LogEventPatternConverter impleme
private abstract static class Formatter {
long previousTime; // for ThreadLocal caching mode
+ int nanos;
- abstract String format(long timeMillis);
+ abstract String format(final Instant instant);
- abstract void formatToBuffer(long timeMillis, StringBuilder destination);
+ abstract void formatToBuffer(final Instant instant, StringBuilder destination);
public String toPattern() {
return null;
@@ -61,12 +64,13 @@ public final class DatePatternConverter extends LogEventPatternConverter impleme
}
@Override
- String format(final long timeMillis) {
- return fastDateFormat.format(timeMillis);
+ String format(final Instant instant) {
+ return fastDateFormat.format(instant.getEpochMillisecond());
}
@Override
- void formatToBuffer(final long timeMillis, final StringBuilder destination) {
+ void formatToBuffer(final Instant instant, final StringBuilder destination) {
+ final long timeMillis = instant.getEpochMillisecond();
if (previousTime != timeMillis) {
cachedBuffer.setLength(0);
fastDateFormat.format(timeMillis, cachedBuffer);
@@ -92,14 +96,18 @@ public final class DatePatternConverter extends LogEventPatternConverter impleme
}
@Override
- String format(final long timeMillis) {
- return fixedDateFormat.format(timeMillis);
+ String format(final Instant instant) {
+ return fixedDateFormat.formatInstant(instant);
}
@Override
- void formatToBuffer(final long timeMillis, final StringBuilder destination) {
- if (previousTime != timeMillis) {
- length = fixedDateFormat.format(timeMillis, cachedBuffer, 0);
+ void formatToBuffer(final Instant instant, final StringBuilder destination) {
+ final long epochSecond = instant.getEpochSecond();
+ final int nanoOfSecond = instant.getNanoOfSecond();
+ if (previousTime != epochSecond && nanos != nanoOfSecond) {
+ length = fixedDateFormat.formatInstant(instant, cachedBuffer, 0);
+ previousTime = epochSecond;
+ nanos = nanoOfSecond;
}
destination.append(cachedBuffer, 0, length);
}
@@ -113,36 +121,38 @@ public final class DatePatternConverter extends LogEventPatternConverter impleme
private static final class UnixFormatter extends Formatter {
@Override
- String format(final long timeMillis) {
- return Long.toString(timeMillis / 1000);
+ String format(final Instant instant) {
+ return Long.toString(instant.getEpochSecond());
}
@Override
- void formatToBuffer(final long timeMillis, final StringBuilder destination) {
- destination.append(timeMillis / 1000); // no need for caching
+ void formatToBuffer(final Instant instant, final StringBuilder destination) {
+ destination.append(instant.getEpochSecond()); // no need for caching
}
}
private static final class UnixMillisFormatter extends Formatter {
@Override
- String format(final long timeMillis) {
- return Long.toString(timeMillis);
+ String format(final Instant instant) {
+ return Long.toString(instant.getEpochMillisecond());
}
@Override
- void formatToBuffer(final long timeMillis, final StringBuilder destination) {
- destination.append(timeMillis); // no need for caching
+ void formatToBuffer(final Instant instant, final StringBuilder destination) {
+ destination.append(instant.getEpochMillisecond()); // no need for caching
}
}
private final class CachedTime {
- public long timestampMillis;
+ public long epochSecond;
+ public int nanoOfSecond;
public String formatted;
- public CachedTime(final long timestampMillis) {
- this.timestampMillis = timestampMillis;
- this.formatted = formatter.format(this.timestampMillis);
+ public CachedTime(final Instant instant) {
+ this.epochSecond = instant.getEpochSecond();
+ this.nanoOfSecond = instant.getNanoOfSecond();
+ this.formatted = formatter.format(instant);
}
}
@@ -157,6 +167,7 @@ public final class DatePatternConverter extends LogEventPatternConverter impleme
private static final String UNIX_MILLIS_FORMAT = "UNIX_MILLIS";
private final String[] options;
+ private final ThreadLocal<MutableInstant> threadLocalMutableInstant = new ThreadLocal<>();
private final ThreadLocal<Formatter> threadLocalFormatter = new ThreadLocal<>();
private final AtomicReference<CachedTime> cachedTime;
private final Formatter formatter;
@@ -170,7 +181,13 @@ public final class DatePatternConverter extends LogEventPatternConverter impleme
super("Date", "date");
this.options = options == null ? null : Arrays.copyOf(options, options.length);
this.formatter = createFormatter(options);
- cachedTime = new AtomicReference<>(new CachedTime(System.currentTimeMillis()));
+ cachedTime = new AtomicReference<>(fromEpochMillis(System.currentTimeMillis()));
+ }
+
+ private CachedTime fromEpochMillis(long epochMillis) {
+ final MutableInstant temp = new MutableInstant();
+ temp.initFromEpochMilli(epochMillis, 0);
+ return new CachedTime(temp);
}
private Formatter createFormatter(final String[] options) {
@@ -245,19 +262,38 @@ public final class DatePatternConverter extends LogEventPatternConverter impleme
*/
@Override
public void format(final LogEvent event, final StringBuilder output) {
- format(event.getTimeMillis(), output);
+ format(event.getInstant(), output);
+ }
+
+ public void format(final long epochMilli, final StringBuilder output) {
+ MutableInstant instant = getMutableInstant();
+ instant.initFromEpochMilli(epochMilli, 0);
+ format(instant, output);
+ }
+
+ private MutableInstant getMutableInstant() {
+ if (Constants.ENABLE_THREADLOCALS) {
+ MutableInstant result = threadLocalMutableInstant.get();
+ if (result == null) {
+ result = new MutableInstant();
+ threadLocalMutableInstant.set(result);
+ }
+ return result;
+ } else {
+ return new MutableInstant();
+ }
}
- public void format(final long timestampMillis, final StringBuilder output) {
+ public void format(final Instant instant, final StringBuilder output) {
if (Constants.ENABLE_THREADLOCALS) {
- formatWithoutAllocation(timestampMillis, output);
+ formatWithoutAllocation(instant, output);
} else {
- formatWithoutThreadLocals(timestampMillis, output);
+ formatWithoutThreadLocals(instant, output);
}
}
- private void formatWithoutAllocation(final long timestampMillis, final StringBuilder output) {
- getThreadLocalFormatter().formatToBuffer(timestampMillis, output);
+ private void formatWithoutAllocation(final Instant instant, final StringBuilder output) {
+ getThreadLocalFormatter().formatToBuffer(instant, output);
}
private Formatter getThreadLocalFormatter() {
@@ -269,10 +305,10 @@ public final class DatePatternConverter extends LogEventPatternConverter impleme
return result;
}
- private void formatWithoutThreadLocals(final long timestampMillis, final StringBuilder output) {
+ private void formatWithoutThreadLocals(final Instant instant, final StringBuilder output) {
CachedTime cached = cachedTime.get();
- if (timestampMillis != cached.timestampMillis) {
- final CachedTime newTime = new CachedTime(timestampMillis);
+ if (instant.getEpochSecond() != cached.epochSecond || instant.getNanoOfSecond() != cached.nanoOfSecond) {
+ final CachedTime newTime = new CachedTime(instant);
if (cachedTime.compareAndSet(cached, newTime)) {
cached = newTime;
} else {