You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4j-dev@logging.apache.org by "shishir chaturvedi (JIRA)" <ji...@apache.org> on 2017/03/13 19:57:41 UTC

[jira] [Commented] (LOG4J2-1849) Broken FixedDateFormat tests when daylight saving time starts

    [ https://issues.apache.org/jira/browse/LOG4J2-1849?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15922839#comment-15922839 ] 

shishir chaturvedi commented on LOG4J2-1849:
--------------------------------------------

We faced time lag while using log4j2 loggers on 03/12/2017. Log4j2 loggers were lagging 1 hour behind in log messages. This was auto corrected today(03/13/2017). I would share my findings here. 
Seems like the way FixedDateFormat is formatting the time is based on systemMillis/calcMidnightMillis is not correct. Ideally, it should consider the default Timezone. Here is my analysis of these two date patterns,
{code}
Scenario 1 - %d{DATE}
Scenario 2 - %d{dd MMM yyyy HH:mm:ss,sss} 
{code}

*Scenario 1 :*
{code:xml}
Use default literal date pattern : %d{DATE}
Log4j2 Configuration
<Property name="appenderPatternLayout">[%t] %d{DATE} %-5p %-15c{1} [%X]: %cm%n
{code}

In this log4j2 configuration, log4j2 creates a default FixedDateFormat. This class uses base reference time as midnight and all the time-based calculations are done with respect to this base time. This class is not TimeZone aware. 

These are the code snippets and class references,
{code}
org.apache.logging.log4j.core.util.datetime.FixedDateFormat#calcMidnightMillis
 - uses Calendar.getInstance()
org.apache.logging.log4j.core.util.datetime.FixedDateFormat#format(long, char[], int)

  public int format(final long time, 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));
        writeDate(buffer, startPos);
        return writeTime(ms, buffer, startPos + dateLength) - startPos;
    }

// Profiling showed this method is important to log4j performance. Modify with care!
    // 30 bytes (allows immediate JVM inlining: <= -XX:MaxInlineSize=35 bytes)
    private long millisSinceMidnight(final long now) {
        if (now >= midnightTomorrow || now < midnightToday) {
            updateMidnightMillis(now);
        }
        return now - midnightToday;
    }
{code}


***

*Scenario 2 :*

**This approach worked for us **

{code}
Use specific date pattern : %d{dd MMM yyyy HH:mm:ss,sss}
Log4j2 Configuration
	<Property name="appenderPatternLayout">[%t] %d{dd MMM yyyy HH:mm:ss,sss} %-5p %-15c{1} [%X]: %cm%n
{code}

In this log4j2 configuration, the date-formatter is calculated based on the date pattern configured in log4j2 configuration file. This forces Log4j2 to dynamically evaluate correct date-formatter. Also, it is timezone aware and will use default timezone from system timezone.

Please refer this code snippet,

{code}

org.apache.logging.log4j.core.util.datetime.FormatCache#getInstance(java.lang.String, java.util.TimeZone, java.util.Locale)

public F getInstance(final String pattern, TimeZone timeZone, Locale locale) {
        if (pattern == null) {
            throw new NullPointerException("pattern must not be null");
        }
        if (timeZone == null) {
            timeZone = TimeZone.getDefault();
        }
        if (locale == null) {
            locale = Locale.getDefault();
        }
        final MultipartKey key = new MultipartKey(pattern, timeZone, locale);
        F format = cInstanceCache.get(key);
        if (format == null) {
            format = createInstance(pattern, timeZone, locale);
            final F previousValue = cInstanceCache.putIfAbsent(key, format);
            if (previousValue != null) {
                // another thread snuck in and did the same work
                // we should return the instance that is in ConcurrentMap
                format = previousValue;
            }
        }
        return format;
    }
{code}

Log42 document also does not state it clearly elaborate aforementioned behaviors. Please let me know your thoughts. I would be more than happy to make any contributions for improving it.
Thanks,
Shishir.

> Broken FixedDateFormat tests when daylight saving time starts
> -------------------------------------------------------------
>
>                 Key: LOG4J2-1849
>                 URL: https://issues.apache.org/jira/browse/LOG4J2-1849
>             Project: Log4j 2
>          Issue Type: Bug
>          Components: Core
>    Affects Versions: 2.8.1
>            Reporter: Matt Sicker
>
> Today we started daylight saving time in the US, and the following tests failed:
> {noformat}
> Failed tests:
>   FixedDateFormatTest.testFormatLong:162 ABSOLUTE(HH:mm:ss,SSS)/1489305608119 expected:<0[3]:00:08,119> but was:<0[2]:00:08,119>
>   FixedDateFormatTest.testFormatLongCharArrayInt:196 ABSOLUTE(HH:mm:ss,SSS)/1489305607930 expected:<0[3]:00:07,930> but was:<0[2]:00:07,930>
>   FixedDateFormatTest.testFormatLongCharArrayInt_goingBackInTime:214 ABSOLUTE(HH:mm:ss,SSS)/1489381194091 expected:<2[3]:59:54,091> but was:<2[2]:59:54,091>
>   FixedDateFormatTest.testFormatLong_goingBackInTime:178 ABSOLUTE(HH:mm:ss,SSS)/1489381194072 expected:<2[3]:59:54,072> but was:<2[2]:59:54,072>
> {noformat}



--
This message was sent by Atlassian JIRA
(v6.3.15#6346)

---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-dev-unsubscribe@logging.apache.org
For additional commands, e-mail: log4j-dev-help@logging.apache.org