This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/master by this push: new 4ad0a71 BZ 64190 Add 'proper' ms support to OneLineFormatter. 4ad0a71 is described below commit 4ad0a71bc11de50e0fe23fc38e6e67f134aa0589 Author: Mark Thomas <ma...@apache.org> AuthorDate: Tue Mar 3 14:36:08 2020 +0000 BZ 64190 Add 'proper' ms support to OneLineFormatter. S SS or SSS can now be used (once) anywhere in the format String. Format strings without S SS or SSS are now ~30% faster The current default (effectively "dd-MMM-yyyy HH:mm:ss.SSS") is within less than 1% of the old implementation. Using S SS or SSS anywhere but the very end doubles the time taken to generate the timestamp. --- java/org/apache/juli/OneLineFormatter.java | 77 +++++++++++++++++++--- .../TestOneLineFormatterMillisPerformance.java | 70 ++++++++++++++++++++ webapps/docs/changelog.xml | 5 ++ 3 files changed, 142 insertions(+), 10 deletions(-) diff --git a/java/org/apache/juli/OneLineFormatter.java b/java/org/apache/juli/OneLineFormatter.java index 75845cf..fad37b0 100644 --- a/java/org/apache/juli/OneLineFormatter.java +++ b/java/org/apache/juli/OneLineFormatter.java @@ -51,7 +51,7 @@ public class OneLineFormatter extends Formatter { }; /* Timestamp format */ - private static final String DEFAULT_TIME_FORMAT = "dd-MMM-yyyy HH:mm:ss"; + private static final String DEFAULT_TIME_FORMAT = "dd-MMM-yyyy HH:mm:ss.SSS"; /** * The size of our global date format cache @@ -68,6 +68,8 @@ public class OneLineFormatter extends Formatter { */ private ThreadLocal<DateFormatCache> localDateCache; + private volatile MillisHandling millisHandling = MillisHandling.APPEND; + public OneLineFormatter() { String timeFormat = LogManager.getLogManager().getProperty( @@ -86,12 +88,31 @@ public class OneLineFormatter extends Formatter { * {@link java.text.SimpleDateFormat} syntax */ public void setTimeFormat(final String timeFormat) { + final String cachedTimeFormat; + + if (timeFormat.endsWith(".SSS")) { + cachedTimeFormat = timeFormat.substring(0, timeFormat.length() - 4); + millisHandling = MillisHandling.APPEND; + } else if (timeFormat.contains("SSS")) { + millisHandling = MillisHandling.REPLACE_SSS; + cachedTimeFormat = timeFormat; + } else if (timeFormat.contains("SS")) { + millisHandling = MillisHandling.REPLACE_SS; + cachedTimeFormat = timeFormat; + } else if (timeFormat.contains("S")) { + millisHandling = MillisHandling.REPLACE_S; + cachedTimeFormat = timeFormat; + } else { + millisHandling = MillisHandling.NONE; + cachedTimeFormat = timeFormat; + } + final DateFormatCache globalDateCache = - new DateFormatCache(globalCacheSize, timeFormat, null); + new DateFormatCache(globalCacheSize, cachedTimeFormat, null); localDateCache = new ThreadLocal<DateFormatCache>() { @Override protected DateFormatCache initialValue() { - return new DateFormatCache(localCacheSize, timeFormat, globalDateCache); + return new DateFormatCache(localCacheSize, cachedTimeFormat, globalDateCache); } }; } @@ -156,18 +177,45 @@ public class OneLineFormatter extends Formatter { } protected void addTimestamp(StringBuilder buf, long timestamp) { - buf.append(localDateCache.get().getFormat(timestamp)); - long frac = timestamp % 1000; - buf.append('.'); - if (frac < 100) { - if (frac < 10) { + String cachedTimeStamp = localDateCache.get().getFormat(timestamp); + if (millisHandling == MillisHandling.NONE) { + buf.append(cachedTimeStamp); + } else if (millisHandling == MillisHandling.APPEND) { + buf.append(cachedTimeStamp); + long frac = timestamp % 1000; + buf.append('.'); + if (frac < 100) { + if (frac < 10) { + buf.append('0'); + buf.append('0'); + } else { + buf.append('0'); + } + } + buf.append(frac); + } else { + // Some version of replace + long frac = timestamp % 1000; + // Formatted string may vary in length so the insert point may vary + int insertStart = cachedTimeStamp.indexOf('#'); + buf.append(cachedTimeStamp.subSequence(0, insertStart)); + if (frac < 100 && millisHandling == MillisHandling.REPLACE_SSS) { buf.append('0'); + if (frac < 10) { + buf.append('0'); + } + } else if (frac < 10 && millisHandling == MillisHandling.REPLACE_SS) { buf.append('0'); + } + buf.append(frac); + if (millisHandling == MillisHandling.REPLACE_SSS) { + buf.append(cachedTimeStamp.substring(insertStart + 3)); + } else if (millisHandling == MillisHandling.REPLACE_SS) { + buf.append(cachedTimeStamp.substring(insertStart + 2)); } else { - buf.append('0'); + buf.append(cachedTimeStamp.substring(insertStart + 1)); } } - buf.append(frac); } @@ -250,4 +298,13 @@ public class OneLineFormatter extends Formatter { super.println(x); } } + + + private static enum MillisHandling { + NONE, + APPEND, + REPLACE_S, + REPLACE_SS, + REPLACE_SSS, + } } diff --git a/test/org/apache/juli/TestOneLineFormatterMillisPerformance.java b/test/org/apache/juli/TestOneLineFormatterMillisPerformance.java new file mode 100644 index 0000000..b7c0cab --- /dev/null +++ b/test/org/apache/juli/TestOneLineFormatterMillisPerformance.java @@ -0,0 +1,70 @@ +/* + * 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.juli; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; + +@RunWith(Parameterized.class) +public class TestOneLineFormatterMillisPerformance { + + @Parameterized.Parameters(name = "{index}: format[{0}]") + public static Collection<Object[]> parameters() { + + List<Object[]> parameterSets = new ArrayList<>(); + + parameterSets.add(new String[] { "dd-MMM-yyyy HH:mm:ss.SSS" }); + parameterSets.add(new String[] { "dd-MMM-yyyy HH:mm:ss.SS" }); + parameterSets.add(new String[] { "dd-MMM-yyyy HH:mm:ss.S" }); + parameterSets.add(new String[] { "dd-MMM-yyyy HH:mm:ss" }); + parameterSets.add(new String[] { "dd-MMM-yyyy HH:mm:ss XXX" }); + parameterSets.add(new String[] { "dd-MMM-yyyy HH:mm:ss.SSSXXX" }); + parameterSets.add(new String[] { "dd-MMM-yyyy HH:mm:ss.SSXXX" }); + parameterSets.add(new String[] { "dd-MMM-yyyy HH:mm:ss.SXXX" }); + parameterSets.add(new String[] { "SSS dd-MMM-yyyy HH:mm:ss" }); + parameterSets.add(new String[] { "SS dd-MMM-yyyy HH:mm:ss" }); + parameterSets.add(new String[] { "S dd-MMM-yyyy HH:mm:ss" }); + + return parameterSets; + } + + + @Parameter(0) + public String timestampFormat; + + @Test + public void testMillisHandling() { + OneLineFormatter olf = new OneLineFormatter(); + olf.setTimeFormat(timestampFormat); + + long timeStamp = System.currentTimeMillis(); + StringBuilder buf = new StringBuilder(64); + + long start = System.nanoTime(); + for (int i = 0; i < 10000000; i++) { + buf.setLength(0); + olf.addTimestamp(buf, timeStamp); + } + System.out.println("Format: [" + timestampFormat + "], Output: [" + buf + "], Duration: [" + (System.nanoTime() - start) + "] ns"); + } +} diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index cf486e2..38a525b 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -160,6 +160,11 @@ Expand the coverage of the French translations provided with Apache Tomcat. (remm) </add> + <add> + <bug>64190</bug>: Add support for specifing milliseconds (using + <code>S</code>, <code>SS</code> or <code>SSS</code>) in the timestamp + used by JULI's <code>OneLineFormatter</code>. (markt) + </add> </changelog> </subsection> </section> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org