PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / trunk
Matomo Analytics – Powerful, Privacy-First Insights for WordPress vtrunk
5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / vendor / prefixed / symfony / http-kernel / DataCollector / LoggerDataCollector.php
matomo / app / vendor / prefixed / symfony / http-kernel / DataCollector Last commit date
AjaxDataCollector.php 2 years ago ConfigDataCollector.php 1 year ago DataCollector.php 2 years ago DataCollectorInterface.php 2 years ago DumpDataCollector.php 1 year ago EventDataCollector.php 2 years ago ExceptionDataCollector.php 2 years ago LateDataCollectorInterface.php 2 years ago LoggerDataCollector.php 1 year ago MemoryDataCollector.php 1 year ago RequestDataCollector.php 1 year ago RouterDataCollector.php 1 year ago TimeDataCollector.php 1 year ago
LoggerDataCollector.php
267 lines
1 <?php
2
3 /*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11 namespace Matomo\Dependencies\Symfony\Component\HttpKernel\DataCollector;
12
13 use Matomo\Dependencies\Symfony\Component\ErrorHandler\Exception\SilencedErrorContext;
14 use Matomo\Dependencies\Symfony\Component\HttpFoundation\Request;
15 use Matomo\Dependencies\Symfony\Component\HttpFoundation\RequestStack;
16 use Matomo\Dependencies\Symfony\Component\HttpFoundation\Response;
17 use Matomo\Dependencies\Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
18 /**
19 * @author Fabien Potencier <fabien@symfony.com>
20 *
21 * @final
22 */
23 class LoggerDataCollector extends DataCollector implements LateDataCollectorInterface
24 {
25 private $logger;
26 private $containerPathPrefix;
27 private $currentRequest;
28 private $requestStack;
29 private $processedLogs;
30 public function __construct(?object $logger = null, ?string $containerPathPrefix = null, ?RequestStack $requestStack = null)
31 {
32 if (null !== $logger && $logger instanceof DebugLoggerInterface) {
33 $this->logger = $logger;
34 }
35 $this->containerPathPrefix = $containerPathPrefix;
36 $this->requestStack = $requestStack;
37 }
38 /**
39 * {@inheritdoc}
40 */
41 public function collect(Request $request, Response $response, ?\Throwable $exception = null)
42 {
43 $this->currentRequest = $this->requestStack && $this->requestStack->getMainRequest() !== $request ? $request : null;
44 }
45 /**
46 * {@inheritdoc}
47 */
48 public function reset()
49 {
50 if ($this->logger instanceof DebugLoggerInterface) {
51 $this->logger->clear();
52 }
53 $this->data = [];
54 }
55 /**
56 * {@inheritdoc}
57 */
58 public function lateCollect()
59 {
60 if (null !== $this->logger) {
61 $containerDeprecationLogs = $this->getContainerDeprecationLogs();
62 $this->data = $this->computeErrorsCount($containerDeprecationLogs);
63 // get compiler logs later (only when they are needed) to improve performance
64 $this->data['compiler_logs'] = [];
65 $this->data['compiler_logs_filepath'] = $this->containerPathPrefix . 'Compiler.log';
66 $this->data['logs'] = $this->sanitizeLogs(array_merge($this->logger->getLogs($this->currentRequest), $containerDeprecationLogs));
67 $this->data = $this->cloneVar($this->data);
68 }
69 $this->currentRequest = null;
70 }
71 public function getLogs()
72 {
73 return $this->data['logs'] ?? [];
74 }
75 public function getProcessedLogs()
76 {
77 if (null !== $this->processedLogs) {
78 return $this->processedLogs;
79 }
80 $rawLogs = $this->getLogs();
81 if ([] === $rawLogs) {
82 return $this->processedLogs = $rawLogs;
83 }
84 $logs = [];
85 foreach ($this->getLogs()->getValue() as $rawLog) {
86 $rawLogData = $rawLog->getValue();
87 if ($rawLogData['priority']->getValue() > 300) {
88 $logType = 'error';
89 } elseif (isset($rawLogData['scream']) && \false === $rawLogData['scream']->getValue()) {
90 $logType = 'deprecation';
91 } elseif (isset($rawLogData['scream']) && \true === $rawLogData['scream']->getValue()) {
92 $logType = 'silenced';
93 } else {
94 $logType = 'regular';
95 }
96 $logs[] = ['type' => $logType, 'errorCount' => $rawLog['errorCount'] ?? 1, 'timestamp' => $rawLogData['timestamp_rfc3339']->getValue(), 'priority' => $rawLogData['priority']->getValue(), 'priorityName' => $rawLogData['priorityName']->getValue(), 'channel' => $rawLogData['channel']->getValue(), 'message' => $rawLogData['message'], 'context' => $rawLogData['context']];
97 }
98 // sort logs from oldest to newest
99 usort($logs, static function ($logA, $logB) {
100 return $logA['timestamp'] <=> $logB['timestamp'];
101 });
102 return $this->processedLogs = $logs;
103 }
104 public function getFilters()
105 {
106 $filters = ['channel' => [], 'priority' => ['Debug' => 100, 'Info' => 200, 'Notice' => 250, 'Warning' => 300, 'Error' => 400, 'Critical' => 500, 'Alert' => 550, 'Emergency' => 600]];
107 $allChannels = [];
108 foreach ($this->getProcessedLogs() as $log) {
109 if ('' === trim($log['channel'] ?? '')) {
110 continue;
111 }
112 $allChannels[] = $log['channel'];
113 }
114 $channels = array_unique($allChannels);
115 sort($channels);
116 $filters['channel'] = $channels;
117 return $filters;
118 }
119 public function getPriorities()
120 {
121 return $this->data['priorities'] ?? [];
122 }
123 public function countErrors()
124 {
125 return $this->data['error_count'] ?? 0;
126 }
127 public function countDeprecations()
128 {
129 return $this->data['deprecation_count'] ?? 0;
130 }
131 public function countWarnings()
132 {
133 return $this->data['warning_count'] ?? 0;
134 }
135 public function countScreams()
136 {
137 return $this->data['scream_count'] ?? 0;
138 }
139 public function getCompilerLogs()
140 {
141 return $this->cloneVar($this->getContainerCompilerLogs($this->data['compiler_logs_filepath'] ?? null));
142 }
143 /**
144 * {@inheritdoc}
145 */
146 public function getName() : string
147 {
148 return 'logger';
149 }
150 private function getContainerDeprecationLogs() : array
151 {
152 if (null === $this->containerPathPrefix || !is_file($file = $this->containerPathPrefix . 'Deprecations.log')) {
153 return [];
154 }
155 if ('' === ($logContent = trim(file_get_contents($file)))) {
156 return [];
157 }
158 $bootTime = filemtime($file);
159 $logs = [];
160 foreach (unserialize($logContent) as $log) {
161 $log['context'] = ['exception' => new SilencedErrorContext($log['type'], $log['file'], $log['line'], $log['trace'], $log['count'])];
162 $log['timestamp'] = $bootTime;
163 $log['timestamp_rfc3339'] = (new \DateTimeImmutable())->setTimestamp($bootTime)->format(\DateTimeInterface::RFC3339_EXTENDED);
164 $log['priority'] = 100;
165 $log['priorityName'] = 'DEBUG';
166 $log['channel'] = null;
167 $log['scream'] = \false;
168 unset($log['type'], $log['file'], $log['line'], $log['trace'], $log['trace'], $log['count']);
169 $logs[] = $log;
170 }
171 return $logs;
172 }
173 private function getContainerCompilerLogs(?string $compilerLogsFilepath = null) : array
174 {
175 if (!$compilerLogsFilepath || !is_file($compilerLogsFilepath)) {
176 return [];
177 }
178 $logs = [];
179 foreach (file($compilerLogsFilepath, \FILE_IGNORE_NEW_LINES) as $log) {
180 $log = explode(': ', $log, 2);
181 if (!isset($log[1]) || !preg_match('/^[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*+(?:\\\\[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*+)++$/', $log[0])) {
182 $log = ['Unknown Compiler Pass', implode(': ', $log)];
183 }
184 $logs[$log[0]][] = ['message' => $log[1]];
185 }
186 return $logs;
187 }
188 private function sanitizeLogs(array $logs)
189 {
190 $sanitizedLogs = [];
191 $silencedLogs = [];
192 foreach ($logs as $log) {
193 if (!$this->isSilencedOrDeprecationErrorLog($log)) {
194 $sanitizedLogs[] = $log;
195 continue;
196 }
197 $message = '_' . $log['message'];
198 $exception = $log['context']['exception'];
199 if ($exception instanceof SilencedErrorContext) {
200 if (isset($silencedLogs[$h = spl_object_hash($exception)])) {
201 continue;
202 }
203 $silencedLogs[$h] = \true;
204 if (!isset($sanitizedLogs[$message])) {
205 $sanitizedLogs[$message] = $log + ['errorCount' => 0, 'scream' => \true];
206 }
207 $sanitizedLogs[$message]['errorCount'] += $exception->count;
208 continue;
209 }
210 $errorId = md5("{$exception->getSeverity()}/{$exception->getLine()}/{$exception->getFile()}\x00{$message}", \true);
211 if (isset($sanitizedLogs[$errorId])) {
212 ++$sanitizedLogs[$errorId]['errorCount'];
213 } else {
214 $log += ['errorCount' => 1, 'scream' => \false];
215 $sanitizedLogs[$errorId] = $log;
216 }
217 }
218 return array_values($sanitizedLogs);
219 }
220 private function isSilencedOrDeprecationErrorLog(array $log) : bool
221 {
222 if (!isset($log['context']['exception'])) {
223 return \false;
224 }
225 $exception = $log['context']['exception'];
226 if ($exception instanceof SilencedErrorContext) {
227 return \true;
228 }
229 if ($exception instanceof \ErrorException && \in_array($exception->getSeverity(), [\E_DEPRECATED, \E_USER_DEPRECATED], \true)) {
230 return \true;
231 }
232 return \false;
233 }
234 private function computeErrorsCount(array $containerDeprecationLogs) : array
235 {
236 $silencedLogs = [];
237 $count = ['error_count' => $this->logger->countErrors($this->currentRequest), 'deprecation_count' => 0, 'warning_count' => 0, 'scream_count' => 0, 'priorities' => []];
238 foreach ($this->logger->getLogs($this->currentRequest) as $log) {
239 if (isset($count['priorities'][$log['priority']])) {
240 ++$count['priorities'][$log['priority']]['count'];
241 } else {
242 $count['priorities'][$log['priority']] = ['count' => 1, 'name' => $log['priorityName']];
243 }
244 if ('WARNING' === $log['priorityName']) {
245 ++$count['warning_count'];
246 }
247 if ($this->isSilencedOrDeprecationErrorLog($log)) {
248 $exception = $log['context']['exception'];
249 if ($exception instanceof SilencedErrorContext) {
250 if (isset($silencedLogs[$h = spl_object_hash($exception)])) {
251 continue;
252 }
253 $silencedLogs[$h] = \true;
254 $count['scream_count'] += $exception->count;
255 } else {
256 ++$count['deprecation_count'];
257 }
258 }
259 }
260 foreach ($containerDeprecationLogs as $deprecationLog) {
261 $count['deprecation_count'] += $deprecationLog['context']['exception']->count;
262 }
263 ksort($count['priorities']);
264 return $count;
265 }
266 }
267