From 8c70660c1718e2b05d97f85a506a3ecbdb9513e0 Mon Sep 17 00:00:00 2001 From: liutao <473139299@qq.com> Date: Wed, 21 Jun 2023 16:37:30 +0800 Subject: [PATCH] Fix support of yearly and monthly rotation log file to rotate only once a month/year (#1805) Co-authored-by: liutao Co-authored-by: liutao02 --- src/Monolog/Handler/RotatingFileHandler.php | 41 ++++++++++++++------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/src/Monolog/Handler/RotatingFileHandler.php b/src/Monolog/Handler/RotatingFileHandler.php index 9d57af99..75081db5 100644 --- a/src/Monolog/Handler/RotatingFileHandler.php +++ b/src/Monolog/Handler/RotatingFileHandler.php @@ -43,13 +43,12 @@ class RotatingFileHandler extends StreamHandler * @param int|null $filePermission Optional file permissions (default (0644) are only for owner read/write) * @param bool $useLocking Try to lock log file before doing any writes */ - public function __construct(string $filename, int $maxFiles = 0, int|string|Level $level = Level::Debug, bool $bubble = true, ?int $filePermission = null, bool $useLocking = false) + public function __construct(string $filename, int $maxFiles = 0, int|string|Level $level = Level::Debug, bool $bubble = true, ?int $filePermission = null, bool $useLocking = false, string $dateFormat = self::FILE_PER_DAY, string $filenameFormat = '{filename}-{date}') { $this->filename = Utils::canonicalizePath($filename); $this->maxFiles = $maxFiles; - $this->nextRotation = new \DateTimeImmutable('tomorrow'); - $this->filenameFormat = '{filename}-{date}'; - $this->dateFormat = static::FILE_PER_DAY; + $this->setFilenameFormat($filenameFormat, $dateFormat); + $this->nextRotation = $this->getNextRotation(); parent::__construct($this->getTimedFilename(), $level, $bubble, $filePermission, $useLocking); } @@ -80,21 +79,13 @@ class RotatingFileHandler extends StreamHandler public function setFilenameFormat(string $filenameFormat, string $dateFormat): self { - if (0 === preg_match('{^[Yy](([/_.-]?m)([/_.-]?d)?)?$}', $dateFormat)) { - throw new InvalidArgumentException( - 'Invalid date format - format must be one of '. - 'RotatingFileHandler::FILE_PER_DAY ("Y-m-d"), RotatingFileHandler::FILE_PER_MONTH ("Y-m") '. - 'or RotatingFileHandler::FILE_PER_YEAR ("Y"), or you can set one of the '. - 'date formats using slashes, underscores and/or dots instead of dashes.' - ); - } + $this->setDateFormat($dateFormat); if (substr_count($filenameFormat, '{date}') === 0) { throw new InvalidArgumentException( 'Invalid filename format - format must contain at least `{date}`, because otherwise rotating is impossible.' ); } $this->filenameFormat = $filenameFormat; - $this->dateFormat = $dateFormat; $this->url = $this->getTimedFilename(); $this->close(); @@ -126,7 +117,7 @@ class RotatingFileHandler extends StreamHandler { // update filename $this->url = $this->getTimedFilename(); - $this->nextRotation = new \DateTimeImmutable('tomorrow'); + $this->nextRotation = $this->getNextRotation(); // skip GC of old logs if files are unlimited if (0 === $this->maxFiles) { @@ -198,4 +189,26 @@ class RotatingFileHandler extends StreamHandler return $glob; } + + protected function setDateFormat(string $dateFormat): void + { + if (0 === preg_match('{^[Yy](([/_.-]?m)([/_.-]?d)?)?$}', $dateFormat)) { + throw new InvalidArgumentException( + 'Invalid date format - format must be one of '. + 'RotatingFileHandler::FILE_PER_DAY ("Y-m-d"), RotatingFileHandler::FILE_PER_MONTH ("Y-m") '. + 'or RotatingFileHandler::FILE_PER_YEAR ("Y"), or you can set one of the '. + 'date formats using slashes, underscores and/or dots instead of dashes.' + ); + } + $this->dateFormat = $dateFormat; + } + + protected function getNextRotation(): \DateTimeImmutable + { + return match (str_replace(['/','_','.'], '-', $this->dateFormat)) { + self::FILE_PER_MONTH => (new \DateTimeImmutable('first day of next month'))->setTime(0, 0, 0), + self::FILE_PER_YEAR => (new \DateTimeImmutable('first day of January next year'))->setTime(0, 0, 0), + default => (new \DateTimeImmutable('tomorrow'))->setTime(0, 0, 0), + }; + } }