LoggerDataCollector.php 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\HttpKernel\DataCollector;
  11. use Symfony\Component\HttpFoundation\Request;
  12. use Symfony\Component\HttpFoundation\Response;
  13. use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
  14. /**
  15. * LogDataCollector.
  16. *
  17. * @author Fabien Potencier <fabien@symfony.com>
  18. */
  19. class LoggerDataCollector extends DataCollector implements LateDataCollectorInterface
  20. {
  21. private $errorNames = array(
  22. E_DEPRECATED => 'E_DEPRECATED',
  23. E_USER_DEPRECATED => 'E_USER_DEPRECATED',
  24. E_NOTICE => 'E_NOTICE',
  25. E_USER_NOTICE => 'E_USER_NOTICE',
  26. E_STRICT => 'E_STRICT',
  27. E_WARNING => 'E_WARNING',
  28. E_USER_WARNING => 'E_USER_WARNING',
  29. E_COMPILE_WARNING => 'E_COMPILE_WARNING',
  30. E_CORE_WARNING => 'E_CORE_WARNING',
  31. E_USER_ERROR => 'E_USER_ERROR',
  32. E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR',
  33. E_COMPILE_ERROR => 'E_COMPILE_ERROR',
  34. E_PARSE => 'E_PARSE',
  35. E_ERROR => 'E_ERROR',
  36. E_CORE_ERROR => 'E_CORE_ERROR',
  37. );
  38. private $logger;
  39. public function __construct($logger = null)
  40. {
  41. if (null !== $logger && $logger instanceof DebugLoggerInterface) {
  42. $this->logger = $logger;
  43. }
  44. }
  45. /**
  46. * {@inheritdoc}
  47. */
  48. public function collect(Request $request, Response $response, \Exception $exception = null)
  49. {
  50. // everything is done as late as possible
  51. }
  52. /**
  53. * {@inheritdoc}
  54. */
  55. public function lateCollect()
  56. {
  57. if (null !== $this->logger) {
  58. $this->data = $this->computeErrorsCount();
  59. $this->data['logs'] = $this->sanitizeLogs($this->logger->getLogs());
  60. }
  61. }
  62. /**
  63. * Gets the logs.
  64. *
  65. * @return array An array of logs
  66. */
  67. public function getLogs()
  68. {
  69. return isset($this->data['logs']) ? $this->data['logs'] : array();
  70. }
  71. public function getPriorities()
  72. {
  73. return isset($this->data['priorities']) ? $this->data['priorities'] : array();
  74. }
  75. public function countErrors()
  76. {
  77. return isset($this->data['error_count']) ? $this->data['error_count'] : 0;
  78. }
  79. public function countDeprecations()
  80. {
  81. return isset($this->data['deprecation_count']) ? $this->data['deprecation_count'] : 0;
  82. }
  83. public function countScreams()
  84. {
  85. return isset($this->data['scream_count']) ? $this->data['scream_count'] : 0;
  86. }
  87. /**
  88. * {@inheritdoc}
  89. */
  90. public function getName()
  91. {
  92. return 'logger';
  93. }
  94. private function sanitizeLogs($logs)
  95. {
  96. $errorContextById = array();
  97. $sanitizedLogs = array();
  98. foreach ($logs as $log) {
  99. $context = $this->sanitizeContext($log['context']);
  100. if (isset($context['type'], $context['file'], $context['line'], $context['level'])) {
  101. $errorId = md5("{$context['type']}/{$context['line']}/{$context['file']}\x00{$log['message']}", true);
  102. $silenced = !($context['type'] & $context['level']);
  103. if (isset($this->errorNames[$context['type']])) {
  104. $context = array_merge(array('name' => $this->errorNames[$context['type']]), $context);
  105. }
  106. if (isset($errorContextById[$errorId])) {
  107. if (isset($errorContextById[$errorId]['errorCount'])) {
  108. ++$errorContextById[$errorId]['errorCount'];
  109. } else {
  110. $errorContextById[$errorId]['errorCount'] = 2;
  111. }
  112. if (!$silenced && isset($errorContextById[$errorId]['scream'])) {
  113. unset($errorContextById[$errorId]['scream']);
  114. $errorContextById[$errorId]['level'] = $context['level'];
  115. }
  116. continue;
  117. }
  118. $errorContextById[$errorId] = &$context;
  119. if ($silenced) {
  120. $context['scream'] = true;
  121. }
  122. $log['context'] = &$context;
  123. unset($context);
  124. } else {
  125. $log['context'] = $context;
  126. }
  127. $sanitizedLogs[] = $log;
  128. }
  129. return $sanitizedLogs;
  130. }
  131. private function sanitizeContext($context)
  132. {
  133. if (\is_array($context)) {
  134. foreach ($context as $key => $value) {
  135. $context[$key] = $this->sanitizeContext($value);
  136. }
  137. return $context;
  138. }
  139. if (\is_resource($context)) {
  140. return sprintf('Resource(%s)', get_resource_type($context));
  141. }
  142. if (\is_object($context)) {
  143. if ($context instanceof \Exception) {
  144. return sprintf('Exception(%s): %s', \get_class($context), $context->getMessage());
  145. }
  146. return sprintf('Object(%s)', \get_class($context));
  147. }
  148. return $context;
  149. }
  150. private function computeErrorsCount()
  151. {
  152. $count = array(
  153. 'error_count' => $this->logger->countErrors(),
  154. 'deprecation_count' => 0,
  155. 'scream_count' => 0,
  156. 'priorities' => array(),
  157. );
  158. foreach ($this->logger->getLogs() as $log) {
  159. if (isset($count['priorities'][$log['priority']])) {
  160. ++$count['priorities'][$log['priority']]['count'];
  161. } else {
  162. $count['priorities'][$log['priority']] = array(
  163. 'count' => 1,
  164. 'name' => $log['priorityName'],
  165. );
  166. }
  167. if (isset($log['context']['type'], $log['context']['level'])) {
  168. if (E_DEPRECATED === $log['context']['type'] || E_USER_DEPRECATED === $log['context']['type']) {
  169. ++$count['deprecation_count'];
  170. } elseif (!($log['context']['type'] & $log['context']['level'])) {
  171. ++$count['scream_count'];
  172. }
  173. }
  174. }
  175. ksort($count['priorities']);
  176. return $count;
  177. }
  178. }