FingersCrossedHandler.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. <?php
  2. /*
  3. * This file is part of the Monolog package.
  4. *
  5. * (c) Jordi Boggiano <j.boggiano@seld.be>
  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 Monolog\Handler;
  11. use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy;
  12. use Monolog\Handler\FingersCrossed\ActivationStrategyInterface;
  13. use Monolog\Logger;
  14. /**
  15. * Buffers all records until a certain level is reached
  16. *
  17. * The advantage of this approach is that you don't get any clutter in your log files.
  18. * Only requests which actually trigger an error (or whatever your actionLevel is) will be
  19. * in the logs, but they will contain all records, not only those above the level threshold.
  20. *
  21. * You can find the various activation strategies in the
  22. * Monolog\Handler\FingersCrossed\ namespace.
  23. *
  24. * @author Jordi Boggiano <j.boggiano@seld.be>
  25. */
  26. class FingersCrossedHandler extends AbstractHandler
  27. {
  28. protected $handler;
  29. protected $activationStrategy;
  30. protected $buffering = true;
  31. protected $bufferSize;
  32. protected $buffer = array();
  33. protected $stopBuffering;
  34. protected $passthruLevel;
  35. /**
  36. * @param callable|HandlerInterface $handler Handler or factory callable($record, $fingersCrossedHandler).
  37. * @param int|ActivationStrategyInterface $activationStrategy Strategy which determines when this handler takes action
  38. * @param int $bufferSize How many entries should be buffered at most, beyond that the oldest items are removed from the buffer.
  39. * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
  40. * @param Boolean $stopBuffering Whether the handler should stop buffering after being triggered (default true)
  41. * @param int $passthruLevel Minimum level to always flush to handler on close, even if strategy not triggered
  42. */
  43. public function __construct($handler, $activationStrategy = null, $bufferSize = 0, $bubble = true, $stopBuffering = true, $passthruLevel = null)
  44. {
  45. if (null === $activationStrategy) {
  46. $activationStrategy = new ErrorLevelActivationStrategy(Logger::WARNING);
  47. }
  48. // convert simple int activationStrategy to an object
  49. if (!$activationStrategy instanceof ActivationStrategyInterface) {
  50. $activationStrategy = new ErrorLevelActivationStrategy($activationStrategy);
  51. }
  52. $this->handler = $handler;
  53. $this->activationStrategy = $activationStrategy;
  54. $this->bufferSize = $bufferSize;
  55. $this->bubble = $bubble;
  56. $this->stopBuffering = $stopBuffering;
  57. if ($passthruLevel !== null) {
  58. $this->passthruLevel = Logger::toMonologLevel($passthruLevel);
  59. }
  60. if (!$this->handler instanceof HandlerInterface && !is_callable($this->handler)) {
  61. throw new \RuntimeException("The given handler (".json_encode($this->handler).") is not a callable nor a Monolog\Handler\HandlerInterface object");
  62. }
  63. }
  64. /**
  65. * {@inheritdoc}
  66. */
  67. public function isHandling(array $record)
  68. {
  69. return true;
  70. }
  71. /**
  72. * Manually activate this logger regardless of the activation strategy
  73. */
  74. public function activate()
  75. {
  76. if ($this->stopBuffering) {
  77. $this->buffering = false;
  78. }
  79. if (!$this->handler instanceof HandlerInterface) {
  80. $record = end($this->buffer) ?: null;
  81. $this->handler = call_user_func($this->handler, $record, $this);
  82. if (!$this->handler instanceof HandlerInterface) {
  83. throw new \RuntimeException("The factory callable should return a HandlerInterface");
  84. }
  85. }
  86. $this->handler->handleBatch($this->buffer);
  87. $this->buffer = array();
  88. }
  89. /**
  90. * {@inheritdoc}
  91. */
  92. public function handle(array $record)
  93. {
  94. if ($this->processors) {
  95. foreach ($this->processors as $processor) {
  96. $record = call_user_func($processor, $record);
  97. }
  98. }
  99. if ($this->buffering) {
  100. $this->buffer[] = $record;
  101. if ($this->bufferSize > 0 && count($this->buffer) > $this->bufferSize) {
  102. array_shift($this->buffer);
  103. }
  104. if ($this->activationStrategy->isHandlerActivated($record)) {
  105. $this->activate();
  106. }
  107. } else {
  108. $this->handler->handle($record);
  109. }
  110. return false === $this->bubble;
  111. }
  112. /**
  113. * {@inheritdoc}
  114. */
  115. public function close()
  116. {
  117. if (null !== $this->passthruLevel) {
  118. $level = $this->passthruLevel;
  119. $this->buffer = array_filter($this->buffer, function ($record) use ($level) {
  120. return $record['level'] >= $level;
  121. });
  122. if (count($this->buffer) > 0) {
  123. $this->handler->handleBatch($this->buffer);
  124. $this->buffer = array();
  125. }
  126. }
  127. }
  128. /**
  129. * Resets the state of the handler. Stops forwarding records to the wrapped handler.
  130. */
  131. public function reset()
  132. {
  133. $this->buffering = true;
  134. }
  135. /**
  136. * Clears the buffer without flushing any messages down to the wrapped handler.
  137. *
  138. * It also resets the handler to its initial buffering state.
  139. */
  140. public function clear()
  141. {
  142. $this->buffer = array();
  143. $this->reset();
  144. }
  145. }