PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 4.7.0
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v4.7.0
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
wp-optimize / vendor / monolog / monolog / src / Monolog / Handler / RotatingFileHandler.php

RotatingFileHandler.php in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 4.7.0, at vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php

204 lines 6.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php declare(strict_types=1);
2
3 /*
4 * This file is part of the Monolog package.
5 *
6 * (c) Jordi Boggiano <[email protected]>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12 namespace Monolog\Handler;
13
14 use InvalidArgumentException;
15 use Monolog\Logger;
16 use Monolog\Utils;
17
18 /**
19 * Stores logs to files that are rotated every day and a limited number of files are kept.
20 *
21 * This rotation is only intended to be used as a workaround. Using logrotate to
22 * handle the rotation is strongly encouraged when you can use it.
23 *
24 * @author Christophe Coevoet <[email protected]>
25 * @author Jordi Boggiano <[email protected]>
26 */
27 class RotatingFileHandler extends StreamHandler
28 {
29 public const FILE_PER_DAY = 'Y-m-d';
30 public const FILE_PER_MONTH = 'Y-m';
31 public const FILE_PER_YEAR = 'Y';
32
33 /** @var string */
34 protected $filename;
35 /** @var int */
36 protected $maxFiles;
37 /** @var bool */
38 protected $mustRotate;
39 /** @var \DateTimeImmutable */
40 protected $nextRotation;
41 /** @var string */
42 protected $filenameFormat;
43 /** @var string */
44 protected $dateFormat;
45
46 /**
47 * @param string $filename
48 * @param int $maxFiles The maximal amount of files to keep (0 means unlimited)
49 * @param int|null $filePermission Optional file permissions (default (0644) are only for owner read/write)
50 * @param bool $useLocking Try to lock log file before doing any writes
51 */
52 public function __construct(string $filename, int $maxFiles = 0, $level = Logger::DEBUG, bool $bubble = true, ?int $filePermission = null, bool $useLocking = false)
53 {
54 $this->filename = Utils::canonicalizePath($filename);
55 $this->maxFiles = $maxFiles;
56 $this->nextRotation = new \DateTimeImmutable('tomorrow');
57 $this->filenameFormat = '{filename}-{date}';
58 $this->dateFormat = static::FILE_PER_DAY;
59
60 parent::__construct($this->getTimedFilename(), $level, $bubble, $filePermission, $useLocking);
61 }
62
63 /**
64 * {@inheritDoc}
65 */
66 public function close(): void
67 {
68 parent::close();
69
70 if (true === $this->mustRotate) {
71 $this->rotate();
72 }
73 }
74
75 /**
76 * {@inheritDoc}
77 */
78 public function reset()
79 {
80 parent::reset();
81
82 if (true === $this->mustRotate) {
83 $this->rotate();
84 }
85 }
86
87 public function setFilenameFormat(string $filenameFormat, string $dateFormat): self
88 {
89 if (!preg_match('{^[Yy](([/_.-]?m)([/_.-]?d)?)?$}', $dateFormat)) {
90 throw new InvalidArgumentException(
91 'Invalid date format - format must be one of '.
92 'RotatingFileHandler::FILE_PER_DAY ("Y-m-d"), RotatingFileHandler::FILE_PER_MONTH ("Y-m") '.
93 'or RotatingFileHandler::FILE_PER_YEAR ("Y"), or you can set one of the '.
94 'date formats using slashes, underscores and/or dots instead of dashes.'
95 );
96 }
97 if (substr_count($filenameFormat, '{date}') === 0) {
98 throw new InvalidArgumentException(
99 'Invalid filename format - format must contain at least `{date}`, because otherwise rotating is impossible.'
100 );
101 }
102 $this->filenameFormat = $filenameFormat;
103 $this->dateFormat = $dateFormat;
104 $this->url = $this->getTimedFilename();
105 $this->close();
106
107 return $this;
108 }
109
110 /**
111 * {@inheritDoc}
112 */
113 protected function write(array $record): void
114 {
115 // on the first record written, if the log is new, we should rotate (once per day)
116 if (null === $this->mustRotate) {
117 $this->mustRotate = null === $this->url || !file_exists($this->url);
118 }
119
120 if ($this->nextRotation <= $record['datetime']) {
121 $this->mustRotate = true;
122 $this->close();
123 }
124
125 parent::write($record);
126 }
127
128 /**
129 * Rotates the files.
130 */
131 protected function rotate(): void
132 {
133 // update filename
134 $this->url = $this->getTimedFilename();
135 $this->nextRotation = new \DateTimeImmutable('tomorrow');
136
137 // skip GC of old logs if files are unlimited
138 if (0 === $this->maxFiles) {
139 return;
140 }
141
142 $logFiles = glob($this->getGlobPattern());
143 if (false === $logFiles) {
144 // failed to glob
145 return;
146 }
147
148 if ($this->maxFiles >= count($logFiles)) {
149 // no files to remove
150 return;
151 }
152
153 // Sorting the files by name to remove the older ones
154 usort($logFiles, function ($a, $b) {
155 return strcmp($b, $a);
156 });
157
158 foreach (array_slice($logFiles, $this->maxFiles) as $file) {
159 if (is_writable($file)) {
160 // suppress errors here as unlink() might fail if two processes
161 // are cleaning up/rotating at the same time
162 set_error_handler(function (int $errno, string $errstr, string $errfile, int $errline): bool {
163 return false;
164 });
165 unlink($file);
166 restore_error_handler();
167 }
168 }
169
170 $this->mustRotate = false;
171 }
172
173 protected function getTimedFilename(): string
174 {
175 $fileInfo = pathinfo($this->filename);
176 $timedFilename = str_replace(
177 ['{filename}', '{date}'],
178 [$fileInfo['filename'], date($this->dateFormat)],
179 $fileInfo['dirname'] . '/' . $this->filenameFormat
180 );
181
182 if (isset($fileInfo['extension'])) {
183 $timedFilename .= '.'.$fileInfo['extension'];
184 }
185
186 return $timedFilename;
187 }
188
189 protected function getGlobPattern(): string
190 {
191 $fileInfo = pathinfo($this->filename);
192 $glob = str_replace(
193 ['{filename}', '{date}'],
194 [$fileInfo['filename'], '[0-9][0-9][0-9][0-9]*'],
195 $fileInfo['dirname'] . '/' . $this->filenameFormat
196 );
197 if (isset($fileInfo['extension'])) {
198 $glob .= '.'.$fileInfo['extension'];
199 }
200
201 return $glob;
202 }
203 }
204