diff --git a/composer.json b/composer.json index 9574a1b0d..693df0a2a 100644 --- a/composer.json +++ b/composer.json @@ -14,6 +14,7 @@ ], "require": { "php": ">=8.1", + "psr/clock": "^1.0", "psr/log": "^2.0 || ^3.0" }, "require-dev": { diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index e545c4487..7ac72b93a 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -19,6 +19,7 @@ use Psr\Log\LoggerInterface; use Psr\Log\InvalidArgumentException; use Psr\Log\LogLevel; +use Psr\Clock\ClockInterface; use Throwable; use Stringable; use WeakMap; @@ -148,6 +149,8 @@ class Logger implements LoggerInterface, ResettableInterface protected Closure|null $exceptionHandler = null; + protected ClockInterface|null $clock = null; + /** * Keeps track of depth to prevent infinite logging loops */ @@ -169,16 +172,17 @@ class Logger implements LoggerInterface, ResettableInterface * @param list $handlers Optional stack of handlers, the first one in the array is called first, etc. * @param callable[] $processors Optional array of processors * @param DateTimeZone|null $timezone Optional timezone, if not provided date_default_timezone_get() will be used - * + * @param ClockInterface|null $clock Optional clock for timestamp generation * @phpstan-param array<(callable(LogRecord): LogRecord)|ProcessorInterface> $processors */ - public function __construct(string $name, array $handlers = [], array $processors = [], DateTimeZone|null $timezone = null) + public function __construct(string $name, array $handlers = [], array $processors = [], DateTimeZone|null $timezone = null, ClockInterface|null $clock = null) { $this->name = $name; $this->setHandlers($handlers); $this->processors = $processors; $this->timezone = $timezone ?? new DateTimeZone(date_default_timezone_get()); $this->fiberLogDepth = new \WeakMap(); + $this->clock = $clock; } public function getName(): string @@ -357,7 +361,7 @@ public function addRecord(int|Level $level, string $message, array $context = [] $recordInitialized = \count($this->processors) === 0; $record = new LogRecord( - datetime: $datetime ?? new JsonSerializableDateTimeImmutable($this->microsecondTimestamps, $this->timezone), + datetime: $datetime ?? ($this->clock instanceof ClockInterface ? $this->clock->now() : new JsonSerializableDateTimeImmutable($this->microsecondTimestamps, $this->timezone)), channel: $this->name, level: self::toMonologLevel($level), message: $message, diff --git a/src/Monolog/LoggerClock.php b/src/Monolog/LoggerClock.php new file mode 100644 index 000000000..4acacf925 --- /dev/null +++ b/src/Monolog/LoggerClock.php @@ -0,0 +1,39 @@ +useMicroseconds = $useMicroseconds; + $this->timezone = $timezone; + } + + public function now(): JsonSerializableDateTimeImmutable + { + return $this->fixedTime ?? new JsonSerializableDateTimeImmutable($this->useMicroseconds, $this->timezone); + } + + public function setUseMicroseconds(bool $useMicroseconds): void + { + $this->useMicroseconds = $useMicroseconds; + } + + public function setTimezone(?\DateTimeZone $timezone): void + { + $this->timezone = $timezone; + } + + public function setFixedTime(JsonSerializableDateTimeImmutable $fixedTime): void + { + $this->fixedTime = $fixedTime; + } +}