Просмотр исходного кода

Optionally reduce timestamp resolution for performance

Introduce a new `useMicrosecondTimestamps()` method to Logger that
allows runtime selection of whether or not to create microsecond
resolution timestamps for log records.

Generating microsecond resolution timestamps by calling
`microtime(true)`, formatting the result via `sprintf()` and then
parsing the resulting string via `DateTime::createFromFormat` can incur
a measurable runtime overhead vs simple usage of `new DateTime` to
capture a second resolution timestamp in systems which generate a large
number of log events.

The default behavior of generating high precision timestamps remains the
same, but may be changed in a future release. Users requiring high
precision timestamps are encouraged to explicitly call
`Monolog\Logger::useMicrosecondTimestamps(true)` in their setup code.

Closes #657
Bryan Davis 10 лет назад
Родитель
Сommit
4e69837afc
2 измененных файлов с 58 добавлено и 1 удалено
  1. 32 1
      src/Monolog/Logger.php
  2. 26 0
      tests/Monolog/LoggerTest.php

+ 32 - 1
src/Monolog/Logger.php

@@ -128,6 +128,11 @@ class Logger implements LoggerInterface
      */
     protected $processors;
 
+    /**
+     * @var bool
+     */
+    protected $microsecondTimestamps = true;
+
     /**
      * @param string             $name       The logging channel
      * @param HandlerInterface[] $handlers   Optional stack of handlers, the first one in the array is called first, etc.
@@ -239,6 +244,25 @@ class Logger implements LoggerInterface
         return $this->processors;
     }
 
+
+    /**
+     * Control the use of microsecond resolution timestamps in the 'datetime'
+     * member of new records.
+     *
+     * Generating microsecond resolution timestamps by calling
+     * microtime(true), formatting the result via sprintf() and then parsing
+     * the resulting string via \DateTime::createFromFormat() can incur
+     * a measurable runtime overhead vs simple usage of DateTime to capture
+     * a second resolution timestamp in systems which generate a large number
+     * of log events.
+     *
+     * @param bool $micro True to use microtime() to create timestamps
+     */
+    public function useMicrosecondTimestamps($micro)
+    {
+        $this->microsecondTimestamps = (bool)$micro;
+    }
+
     /**
      * Adds a log record.
      *
@@ -272,13 +296,20 @@ class Logger implements LoggerInterface
             static::$timezone = new \DateTimeZone(date_default_timezone_get() ?: 'UTC');
         }
 
+        if ($this->microsecondTimestamps) {
+            $ts = \DateTime::createFromFormat('U.u', sprintf('%.6F', microtime(true)), static::$timezone);
+        } else {
+            $ts = new \DateTime(null, static::$timezone);
+        }
+        $ts->setTimezone(static::$timezone);
+
         $record = array(
             'message' => (string) $message,
             'context' => $context,
             'level' => $level,
             'level_name' => $levelName,
             'channel' => $this->name,
-            'datetime' => \DateTime::createFromFormat('U.u', sprintf('%.6F', microtime(true)), static::$timezone)->setTimezone(static::$timezone),
+            'datetime' => $ts,
             'extra' => array(),
         );
 

+ 26 - 0
tests/Monolog/LoggerTest.php

@@ -468,4 +468,30 @@ class LoggerTest extends \PHPUnit_Framework_TestCase
             \DateTimeZone::listIdentifiers()
         );
     }
+
+    /**
+     * @dataProvider useMicrosecondTimestampsProvider
+     * @covers Monolog\Logger::useMicrosecondTimestamps
+     * @covers Monolog\Logger::addRecord
+     */
+    public function testUseMicrosecondTimestamps($micro, $assert)
+    {
+        $logger = new Logger('foo');
+        $logger->useMicrosecondTimestamps($micro);
+        $handler = new TestHandler;
+        $logger->pushHandler($handler);
+        $logger->info('test');
+        list($record) = $handler->getRecords();
+        $this->{$assert}('000000', $record['datetime']->format('u'));
+    }
+
+    public function useMicrosecondTimestampsProvider()
+    {
+        return array(
+            // this has a very small chance of a false negative (1/10^6)
+            'with microseconds' => array(true, 'assertNotSame'),
+            'without microseconds' => array(false, 'assertSame'),
+        );
+    }
+
 }