http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/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/e3a126ee/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/e3a126ee/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/e3a126ee/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/e3a126ee/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/e3a126ee/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/e3a126ee/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/e3a126ee/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/e3a126ee/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/e3a126ee/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/e3a126ee/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/e3a126ee/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/e3a126ee/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/e3a126ee/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/e3a126ee/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/e3a126ee/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/e3a126ee/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/e3a126ee/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/e3a126ee/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/e3a126ee/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/e3a126ee/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 http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/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/e3a126ee/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/e3a126ee/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/AbstractLogEventWrapperEntity.java ---------------------------------------------------------------------- diff --git a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/AbstractLogEventWrapperEntity.java b/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/AbstractLogEventWrapperEntity.java index 60ca692..6c736c6 100644 --- a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/AbstractLogEventWrapperEntity.java +++ b/log4j-jpa/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/e3a126ee/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/BasicLogEventEntity.java ---------------------------------------------------------------------- diff --git a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/BasicLogEventEntity.java b/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/BasicLogEventEntity.java index 5c06316..492aa61 100644 --- a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/BasicLogEventEntity.java +++ b/log4j-jpa/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.
