annotate vendor/symfony/http-kernel/DataCollector/LoggerDataCollector.php @ 17:129ea1e6d783

Update, including to Drupal core 8.6.10
author Chris Cannam
date Thu, 28 Feb 2019 13:21:36 +0000
parents 1fec387a4317
children af1871eacc83
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 /*
Chris@0 4 * This file is part of the Symfony package.
Chris@0 5 *
Chris@0 6 * (c) Fabien Potencier <fabien@symfony.com>
Chris@0 7 *
Chris@0 8 * For the full copyright and license information, please view the LICENSE
Chris@0 9 * file that was distributed with this source code.
Chris@0 10 */
Chris@0 11
Chris@0 12 namespace Symfony\Component\HttpKernel\DataCollector;
Chris@0 13
Chris@0 14 use Symfony\Component\Debug\Exception\SilencedErrorContext;
Chris@0 15 use Symfony\Component\HttpFoundation\Request;
Chris@0 16 use Symfony\Component\HttpFoundation\Response;
Chris@0 17 use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
Chris@0 18
Chris@0 19 /**
Chris@0 20 * LogDataCollector.
Chris@0 21 *
Chris@0 22 * @author Fabien Potencier <fabien@symfony.com>
Chris@0 23 */
Chris@0 24 class LoggerDataCollector extends DataCollector implements LateDataCollectorInterface
Chris@0 25 {
Chris@0 26 private $logger;
Chris@14 27 private $containerPathPrefix;
Chris@0 28
Chris@14 29 public function __construct($logger = null, $containerPathPrefix = null)
Chris@0 30 {
Chris@0 31 if (null !== $logger && $logger instanceof DebugLoggerInterface) {
Chris@14 32 if (!method_exists($logger, 'clear')) {
Chris@14 33 @trigger_error(sprintf('Implementing "%s" without the "clear()" method is deprecated since Symfony 3.4 and will be unsupported in 4.0 for class "%s".', DebugLoggerInterface::class, \get_class($logger)), E_USER_DEPRECATED);
Chris@14 34 }
Chris@14 35
Chris@0 36 $this->logger = $logger;
Chris@0 37 }
Chris@14 38
Chris@14 39 $this->containerPathPrefix = $containerPathPrefix;
Chris@0 40 }
Chris@0 41
Chris@0 42 /**
Chris@0 43 * {@inheritdoc}
Chris@0 44 */
Chris@0 45 public function collect(Request $request, Response $response, \Exception $exception = null)
Chris@0 46 {
Chris@0 47 // everything is done as late as possible
Chris@0 48 }
Chris@0 49
Chris@0 50 /**
Chris@0 51 * {@inheritdoc}
Chris@0 52 */
Chris@14 53 public function reset()
Chris@14 54 {
Chris@14 55 if ($this->logger && method_exists($this->logger, 'clear')) {
Chris@14 56 $this->logger->clear();
Chris@14 57 }
Chris@17 58 $this->data = [];
Chris@14 59 }
Chris@14 60
Chris@14 61 /**
Chris@14 62 * {@inheritdoc}
Chris@14 63 */
Chris@0 64 public function lateCollect()
Chris@0 65 {
Chris@0 66 if (null !== $this->logger) {
Chris@14 67 $containerDeprecationLogs = $this->getContainerDeprecationLogs();
Chris@14 68 $this->data = $this->computeErrorsCount($containerDeprecationLogs);
Chris@14 69 $this->data['compiler_logs'] = $this->getContainerCompilerLogs();
Chris@14 70 $this->data['logs'] = $this->sanitizeLogs(array_merge($this->logger->getLogs(), $containerDeprecationLogs));
Chris@14 71 $this->data = $this->cloneVar($this->data);
Chris@0 72 }
Chris@0 73 }
Chris@0 74
Chris@0 75 /**
Chris@0 76 * Gets the logs.
Chris@0 77 *
Chris@0 78 * @return array An array of logs
Chris@0 79 */
Chris@0 80 public function getLogs()
Chris@0 81 {
Chris@17 82 return isset($this->data['logs']) ? $this->data['logs'] : [];
Chris@0 83 }
Chris@0 84
Chris@0 85 public function getPriorities()
Chris@0 86 {
Chris@17 87 return isset($this->data['priorities']) ? $this->data['priorities'] : [];
Chris@0 88 }
Chris@0 89
Chris@0 90 public function countErrors()
Chris@0 91 {
Chris@0 92 return isset($this->data['error_count']) ? $this->data['error_count'] : 0;
Chris@0 93 }
Chris@0 94
Chris@0 95 public function countDeprecations()
Chris@0 96 {
Chris@0 97 return isset($this->data['deprecation_count']) ? $this->data['deprecation_count'] : 0;
Chris@0 98 }
Chris@0 99
Chris@0 100 public function countWarnings()
Chris@0 101 {
Chris@0 102 return isset($this->data['warning_count']) ? $this->data['warning_count'] : 0;
Chris@0 103 }
Chris@0 104
Chris@0 105 public function countScreams()
Chris@0 106 {
Chris@0 107 return isset($this->data['scream_count']) ? $this->data['scream_count'] : 0;
Chris@0 108 }
Chris@0 109
Chris@14 110 public function getCompilerLogs()
Chris@14 111 {
Chris@17 112 return isset($this->data['compiler_logs']) ? $this->data['compiler_logs'] : [];
Chris@14 113 }
Chris@14 114
Chris@0 115 /**
Chris@0 116 * {@inheritdoc}
Chris@0 117 */
Chris@0 118 public function getName()
Chris@0 119 {
Chris@0 120 return 'logger';
Chris@0 121 }
Chris@0 122
Chris@14 123 private function getContainerDeprecationLogs()
Chris@14 124 {
Chris@14 125 if (null === $this->containerPathPrefix || !file_exists($file = $this->containerPathPrefix.'Deprecations.log')) {
Chris@17 126 return [];
Chris@14 127 }
Chris@14 128
Chris@14 129 $bootTime = filemtime($file);
Chris@17 130 $logs = [];
Chris@14 131 foreach (unserialize(file_get_contents($file)) as $log) {
Chris@17 132 $log['context'] = ['exception' => new SilencedErrorContext($log['type'], $log['file'], $log['line'], $log['trace'], $log['count'])];
Chris@14 133 $log['timestamp'] = $bootTime;
Chris@14 134 $log['priority'] = 100;
Chris@14 135 $log['priorityName'] = 'DEBUG';
Chris@14 136 $log['channel'] = '-';
Chris@14 137 $log['scream'] = false;
Chris@14 138 unset($log['type'], $log['file'], $log['line'], $log['trace'], $log['trace'], $log['count']);
Chris@14 139 $logs[] = $log;
Chris@14 140 }
Chris@14 141
Chris@14 142 return $logs;
Chris@14 143 }
Chris@14 144
Chris@14 145 private function getContainerCompilerLogs()
Chris@14 146 {
Chris@14 147 if (null === $this->containerPathPrefix || !file_exists($file = $this->containerPathPrefix.'Compiler.log')) {
Chris@17 148 return [];
Chris@14 149 }
Chris@14 150
Chris@17 151 $logs = [];
Chris@14 152 foreach (file($file, FILE_IGNORE_NEW_LINES) as $log) {
Chris@14 153 $log = explode(': ', $log, 2);
Chris@14 154 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])) {
Chris@17 155 $log = ['Unknown Compiler Pass', implode(': ', $log)];
Chris@14 156 }
Chris@14 157
Chris@17 158 $logs[$log[0]][] = ['message' => $log[1]];
Chris@14 159 }
Chris@14 160
Chris@14 161 return $logs;
Chris@14 162 }
Chris@14 163
Chris@0 164 private function sanitizeLogs($logs)
Chris@0 165 {
Chris@17 166 $sanitizedLogs = [];
Chris@17 167 $silencedLogs = [];
Chris@0 168
Chris@0 169 foreach ($logs as $log) {
Chris@0 170 if (!$this->isSilencedOrDeprecationErrorLog($log)) {
Chris@0 171 $sanitizedLogs[] = $log;
Chris@0 172
Chris@0 173 continue;
Chris@0 174 }
Chris@0 175
Chris@14 176 $message = $log['message'];
Chris@0 177 $exception = $log['context']['exception'];
Chris@14 178
Chris@14 179 if ($exception instanceof SilencedErrorContext) {
Chris@14 180 if (isset($silencedLogs[$h = spl_object_hash($exception)])) {
Chris@14 181 continue;
Chris@14 182 }
Chris@14 183 $silencedLogs[$h] = true;
Chris@14 184
Chris@14 185 if (!isset($sanitizedLogs[$message])) {
Chris@17 186 $sanitizedLogs[$message] = $log + [
Chris@14 187 'errorCount' => 0,
Chris@14 188 'scream' => true,
Chris@17 189 ];
Chris@14 190 }
Chris@14 191 $sanitizedLogs[$message]['errorCount'] += $exception->count;
Chris@14 192
Chris@14 193 continue;
Chris@14 194 }
Chris@14 195
Chris@14 196 $errorId = md5("{$exception->getSeverity()}/{$exception->getLine()}/{$exception->getFile()}\0{$message}", true);
Chris@0 197
Chris@0 198 if (isset($sanitizedLogs[$errorId])) {
Chris@0 199 ++$sanitizedLogs[$errorId]['errorCount'];
Chris@0 200 } else {
Chris@17 201 $log += [
Chris@0 202 'errorCount' => 1,
Chris@14 203 'scream' => false,
Chris@17 204 ];
Chris@0 205
Chris@0 206 $sanitizedLogs[$errorId] = $log;
Chris@0 207 }
Chris@0 208 }
Chris@0 209
Chris@0 210 return array_values($sanitizedLogs);
Chris@0 211 }
Chris@0 212
Chris@0 213 private function isSilencedOrDeprecationErrorLog(array $log)
Chris@0 214 {
Chris@0 215 if (!isset($log['context']['exception'])) {
Chris@0 216 return false;
Chris@0 217 }
Chris@0 218
Chris@0 219 $exception = $log['context']['exception'];
Chris@0 220
Chris@0 221 if ($exception instanceof SilencedErrorContext) {
Chris@0 222 return true;
Chris@0 223 }
Chris@0 224
Chris@17 225 if ($exception instanceof \ErrorException && \in_array($exception->getSeverity(), [E_DEPRECATED, E_USER_DEPRECATED], true)) {
Chris@0 226 return true;
Chris@0 227 }
Chris@0 228
Chris@0 229 return false;
Chris@0 230 }
Chris@0 231
Chris@14 232 private function computeErrorsCount(array $containerDeprecationLogs)
Chris@0 233 {
Chris@17 234 $silencedLogs = [];
Chris@17 235 $count = [
Chris@0 236 'error_count' => $this->logger->countErrors(),
Chris@0 237 'deprecation_count' => 0,
Chris@0 238 'warning_count' => 0,
Chris@0 239 'scream_count' => 0,
Chris@17 240 'priorities' => [],
Chris@17 241 ];
Chris@0 242
Chris@0 243 foreach ($this->logger->getLogs() as $log) {
Chris@0 244 if (isset($count['priorities'][$log['priority']])) {
Chris@0 245 ++$count['priorities'][$log['priority']]['count'];
Chris@0 246 } else {
Chris@17 247 $count['priorities'][$log['priority']] = [
Chris@0 248 'count' => 1,
Chris@0 249 'name' => $log['priorityName'],
Chris@17 250 ];
Chris@0 251 }
Chris@0 252 if ('WARNING' === $log['priorityName']) {
Chris@0 253 ++$count['warning_count'];
Chris@0 254 }
Chris@0 255
Chris@0 256 if ($this->isSilencedOrDeprecationErrorLog($log)) {
Chris@14 257 $exception = $log['context']['exception'];
Chris@14 258 if ($exception instanceof SilencedErrorContext) {
Chris@14 259 if (isset($silencedLogs[$h = spl_object_hash($exception)])) {
Chris@14 260 continue;
Chris@14 261 }
Chris@14 262 $silencedLogs[$h] = true;
Chris@14 263 $count['scream_count'] += $exception->count;
Chris@0 264 } else {
Chris@0 265 ++$count['deprecation_count'];
Chris@0 266 }
Chris@0 267 }
Chris@0 268 }
Chris@0 269
Chris@14 270 foreach ($containerDeprecationLogs as $deprecationLog) {
Chris@14 271 $count['deprecation_count'] += $deprecationLog['context']['exception']->count;
Chris@14 272 }
Chris@14 273
Chris@0 274 ksort($count['priorities']);
Chris@0 275
Chris@0 276 return $count;
Chris@0 277 }
Chris@0 278 }