为什么Log4j2需要额外的11毫秒来写入文件?

时间:2017-12-04 12:22:24

标签: java logging log4j log4j2

我是Log4j2的新手。我编写了一个简单的程序,实际上使用log4j2将数据记录到RollingRandomAccessFile中。以下是该计划:

public class Log4j2Example {

/**
 * @param args the command line arguments
 */
public static Logger mlogger = null;

public static void main(String[] args) throws InterruptedException {

    mlogger = LogManager.getLogger("Messages-log");
    int i = 0;
    while (true) {
        String str = "Hello" + i;
        System.out.println(str);
        mlogger.info(str);
        i++;
        Thread.sleep(20);
    }
}
}

我的log4j2.xml文件

    <?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
  <Appenders>
     <RollingRandomAccessFile name="Messages-log" fileName="Log4J/Messages-${date:yyyy-MM-dd}.log"
               immediateflush="true" filePattern="Log4J/Messages-%d{MM-dd-yyyy-HH}-%i.log.gz">
      <PatternLayout>
        <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %p %m%n</Pattern>
      </PatternLayout>
      <Policies>
        <TimeBasedTriggeringPolicy />
        <SizeBasedTriggeringPolicy size="500 MB"/>
      </Policies>
      <DefaultRolloverStrategy max="50"/>
    </RollingRandomAccessFile>
  </Appenders>
  <Loggers>
    <Logger name="Messages-log" level="info" additivity="false">
        <appender-ref ref="Messages-log" level="info"/>
      </Logger>
    <root level="info">
        <appender-ref ref="Messages-log"/>
    </root>
</Loggers>
</Configuration>

我正在为日志文件写一个简单的语句,为每条记录休眠20毫秒。现在文件中的时间戳应该是例如: 如果第一个语句记录在17:20:32:354,则下一个语句应记录在17:20:32:374,但它记录的是17:20:32:384。每条记录都会额外增加11毫秒。下面是我的日志文件输出

2017-12-04 17:40:42.205 INFO Hello11
2017-12-04 17:40:42.236 INFO Hello12
2017-12-04 17:40:42.268 INFO Hello13
2017-12-04 17:40:42.299 INFO Hello14
2017-12-04 17:40:42.330 INFO Hello15
2017-12-04 17:40:42.361 INFO Hello16
2017-12-04 17:40:42.393 INFO Hello17
2017-12-04 17:40:42.424 INFO Hello18

您可以看到第一个语句记录为.205毫秒,第二个语句记录为.236毫秒。事实上,我正在睡眠线程20毫秒,因此正确的时间戳应为.226毫秒。我在这做错了什么?我需要写出准确的时间戳,因为它在制作中非常重要。我也用log4j 1尝试了这个但结果相同。我也将我的系统时间与互联网时间同步。有一件事我发现它可以在5毫秒和15毫秒的睡眠时间内完美地工作,但从20毫秒开始,这引起了一个大问题。

2 个答案:

答案 0 :(得分:2)

  

我在这里做错了什么?

大多数缺陷的假设和期望:

  1. Incorrect micro-benchmark.
  2. Flawed assumption that System.currentTimeMillis has sufficient granularity.
  3. Assuming Thread.sleep is accurate.
  4. Assuming adjustments to the system clock won't change wake up time.
  5. 尝试在不使用实时软件的情况下解决实时问题。
  6. 不考虑代码记录框架。
  7. 不考虑执行I / O的appenders

答案 1 :(得分:1)

我认为这不是由日志记录引起的。您可以通过将测试代码更改为以下(以排除日志记录)来验证这一点,并查看您是否得到了类似的结果:

   public static void main(String[] args) throws InterruptedException {
       SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss.SSS");
       int i = 0;
       while (true) {
           System.out.println(format.format(new Date()) + " Hello " + i);
           i++;
           Thread.sleep(20);
       }
   }

正如Ralph在Log4j2-2141中指出的那样,很可能是你遇到了Windows调度程序的粒度。请参阅WinAPI Sleep() function call sleeps for longer than expectedhttps://forum.sysinternals.com/bug-in-waitable-timers_topic16229.html