class LoggerDataCollector extends DataCollector implements LateDataCollectorInterface
{
private $logger;
+ private $containerPathPrefix;
- public function __construct($logger = null)
+ public function __construct($logger = null, $containerPathPrefix = null)
{
if (null !== $logger && $logger instanceof DebugLoggerInterface) {
+ if (!method_exists($logger, 'clear')) {
+ @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);
+ }
+
$this->logger = $logger;
}
+
+ $this->containerPathPrefix = $containerPathPrefix;
}
/**
// everything is done as late as possible
}
+ /**
+ * {@inheritdoc}
+ */
+ public function reset()
+ {
+ if ($this->logger && method_exists($this->logger, 'clear')) {
+ $this->logger->clear();
+ }
+ $this->data = array();
+ }
+
/**
* {@inheritdoc}
*/
public function lateCollect()
{
if (null !== $this->logger) {
- $this->data = $this->computeErrorsCount();
- $this->data['logs'] = $this->sanitizeLogs($this->logger->getLogs());
+ $containerDeprecationLogs = $this->getContainerDeprecationLogs();
+ $this->data = $this->computeErrorsCount($containerDeprecationLogs);
+ $this->data['compiler_logs'] = $this->getContainerCompilerLogs();
+ $this->data['logs'] = $this->sanitizeLogs(array_merge($this->logger->getLogs(), $containerDeprecationLogs));
+ $this->data = $this->cloneVar($this->data);
}
}
return isset($this->data['scream_count']) ? $this->data['scream_count'] : 0;
}
+ public function getCompilerLogs()
+ {
+ return isset($this->data['compiler_logs']) ? $this->data['compiler_logs'] : array();
+ }
+
/**
* {@inheritdoc}
*/
return 'logger';
}
+ private function getContainerDeprecationLogs()
+ {
+ if (null === $this->containerPathPrefix || !file_exists($file = $this->containerPathPrefix.'Deprecations.log')) {
+ return array();
+ }
+
+ $bootTime = filemtime($file);
+ $logs = array();
+ foreach (unserialize(file_get_contents($file)) as $log) {
+ $log['context'] = array('exception' => new SilencedErrorContext($log['type'], $log['file'], $log['line'], $log['trace'], $log['count']));
+ $log['timestamp'] = $bootTime;
+ $log['priority'] = 100;
+ $log['priorityName'] = 'DEBUG';
+ $log['channel'] = '-';
+ $log['scream'] = false;
+ unset($log['type'], $log['file'], $log['line'], $log['trace'], $log['trace'], $log['count']);
+ $logs[] = $log;
+ }
+
+ return $logs;
+ }
+
+ private function getContainerCompilerLogs()
+ {
+ if (null === $this->containerPathPrefix || !file_exists($file = $this->containerPathPrefix.'Compiler.log')) {
+ return array();
+ }
+
+ $logs = array();
+ foreach (file($file, FILE_IGNORE_NEW_LINES) as $log) {
+ $log = explode(': ', $log, 2);
+ 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])) {
+ $log = array('Unknown Compiler Pass', implode(': ', $log));
+ }
+
+ $logs[$log[0]][] = array('message' => $log[1]);
+ }
+
+ return $logs;
+ }
+
private function sanitizeLogs($logs)
{
$sanitizedLogs = array();
+ $silencedLogs = array();
foreach ($logs as $log) {
if (!$this->isSilencedOrDeprecationErrorLog($log)) {
- $log['context'] = $log['context'] ? $this->cloneVar($log['context']) : $log['context'];
$sanitizedLogs[] = $log;
continue;
}
+ $message = $log['message'];
$exception = $log['context']['exception'];
- $errorId = md5("{$exception->getSeverity()}/{$exception->getLine()}/{$exception->getFile()}".($exception instanceof \Exception ? "\0".$exception->getMessage() : ''), true);
+
+ if ($exception instanceof SilencedErrorContext) {
+ if (isset($silencedLogs[$h = spl_object_hash($exception)])) {
+ continue;
+ }
+ $silencedLogs[$h] = true;
+
+ if (!isset($sanitizedLogs[$message])) {
+ $sanitizedLogs[$message] = $log + array(
+ 'errorCount' => 0,
+ 'scream' => true,
+ );
+ }
+ $sanitizedLogs[$message]['errorCount'] += $exception->count;
+
+ continue;
+ }
+
+ $errorId = md5("{$exception->getSeverity()}/{$exception->getLine()}/{$exception->getFile()}\0{$message}", true);
if (isset($sanitizedLogs[$errorId])) {
++$sanitizedLogs[$errorId]['errorCount'];
} else {
- $log['context'] = $log['context'] ? $this->cloneVar($log['context']) : $log['context'];
-
$log += array(
'errorCount' => 1,
- 'scream' => $exception instanceof SilencedErrorContext,
+ 'scream' => false,
);
$sanitizedLogs[$errorId] = $log;
return false;
}
- private function computeErrorsCount()
+ private function computeErrorsCount(array $containerDeprecationLogs)
{
+ $silencedLogs = array();
$count = array(
'error_count' => $this->logger->countErrors(),
'deprecation_count' => 0,
}
if ($this->isSilencedOrDeprecationErrorLog($log)) {
- if ($log['context']['exception'] instanceof SilencedErrorContext) {
- ++$count['scream_count'];
+ $exception = $log['context']['exception'];
+ if ($exception instanceof SilencedErrorContext) {
+ if (isset($silencedLogs[$h = spl_object_hash($exception)])) {
+ continue;
+ }
+ $silencedLogs[$h] = true;
+ $count['scream_count'] += $exception->count;
} else {
++$count['deprecation_count'];
}
}
}
+ foreach ($containerDeprecationLogs as $deprecationLog) {
+ $count['deprecation_count'] += $deprecationLog['context']['exception']->count;
+ }
+
ksort($count['priorities']);
return $count;