View file vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php

File size: 3.27Kb
  1. <?php declare(strict_types=1);
  2.  
  3. /*
  4. * This file is part of the Monolog package.
  5. *
  6. * (c) Jordi Boggiano <j.boggiano@seld.be>
  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\Processor;
  13.  
  14. use Monolog\Logger;
  15.  
  16. /**
  17. * Injects line/file:class/function where the log message came from
  18. *
  19. * Warning: This only works if the handler processes the logs directly.
  20. * If you put the processor on a handler that is behind a FingersCrossedHandler
  21. * for example, the processor will only be called once the trigger level is reached,
  22. * and all the log records will have the same file/line/.. data from the call that
  23. * triggered the FingersCrossedHandler.
  24. *
  25. * @author Jordi Boggiano <j.boggiano@seld.be>
  26. */
  27. class IntrospectionProcessor implements ProcessorInterface
  28. {
  29. private $level;
  30.  
  31. private $skipClassesPartials;
  32.  
  33. private $skipStackFramesCount;
  34.  
  35. private $skipFunctions = [
  36. 'call_user_func',
  37. 'call_user_func_array',
  38. ];
  39.  
  40. /**
  41. * @param string|int $level The minimum logging level at which this Processor will be triggered
  42. */
  43. public function __construct($level = Logger::DEBUG, array $skipClassesPartials = [], int $skipStackFramesCount = 0)
  44. {
  45. $this->level = Logger::toMonologLevel($level);
  46. $this->skipClassesPartials = array_merge(['Monolog\\'], $skipClassesPartials);
  47. $this->skipStackFramesCount = $skipStackFramesCount;
  48. }
  49.  
  50. public function __invoke(array $record): array
  51. {
  52. // return if the level is not high enough
  53. if ($record['level'] < $this->level) {
  54. return $record;
  55. }
  56.  
  57. $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
  58.  
  59. // skip first since it's always the current method
  60. array_shift($trace);
  61. // the call_user_func call is also skipped
  62. array_shift($trace);
  63.  
  64. $i = 0;
  65.  
  66. while ($this->isTraceClassOrSkippedFunction($trace, $i)) {
  67. if (isset($trace[$i]['class'])) {
  68. foreach ($this->skipClassesPartials as $part) {
  69. if (strpos($trace[$i]['class'], $part) !== false) {
  70. $i++;
  71.  
  72. continue 2;
  73. }
  74. }
  75. } elseif (in_array($trace[$i]['function'], $this->skipFunctions)) {
  76. $i++;
  77.  
  78. continue;
  79. }
  80.  
  81. break;
  82. }
  83.  
  84. $i += $this->skipStackFramesCount;
  85.  
  86. // we should have the call source now
  87. $record['extra'] = array_merge(
  88. $record['extra'],
  89. [
  90. 'file' => isset($trace[$i - 1]['file']) ? $trace[$i - 1]['file'] : null,
  91. 'line' => isset($trace[$i - 1]['line']) ? $trace[$i - 1]['line'] : null,
  92. 'class' => isset($trace[$i]['class']) ? $trace[$i]['class'] : null,
  93. 'function' => isset($trace[$i]['function']) ? $trace[$i]['function'] : null,
  94. ]
  95. );
  96.  
  97. return $record;
  98. }
  99.  
  100. private function isTraceClassOrSkippedFunction(array $trace, int $index)
  101. {
  102. if (!isset($trace[$index])) {
  103. return false;
  104. }
  105.  
  106. return isset($trace[$index]['class']) || in_array($trace[$index]['function'], $this->skipFunctions);
  107. }
  108. }