BufferHandler.php 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. <?php declare(strict_types=1);
  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\Logger;
  12. use Monolog\ResettableInterface;
  13. /**
  14. * Buffers all records until closing the handler and then pass them as batch.
  15. *
  16. * This is useful for a MailHandler to send only one mail per request instead of
  17. * sending one per log message.
  18. *
  19. * @author Christophe Coevoet <stof@notk.org>
  20. */
  21. class BufferHandler extends AbstractHandler implements ProcessableHandlerInterface
  22. {
  23. use ProcessableHandlerTrait;
  24. protected $handler;
  25. protected $bufferSize = 0;
  26. protected $bufferLimit;
  27. protected $flushOnOverflow;
  28. protected $buffer = [];
  29. protected $initialized = false;
  30. /**
  31. * @param HandlerInterface $handler Handler.
  32. * @param int $bufferLimit How many entries should be buffered at most, beyond that the oldest items are removed from the buffer.
  33. * @param string|int $level The minimum logging level at which this handler will be triggered
  34. * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
  35. * @param bool $flushOnOverflow If true, the buffer is flushed when the max size has been reached, by default oldest entries are discarded
  36. */
  37. public function __construct(HandlerInterface $handler, int $bufferLimit = 0, $level = Logger::DEBUG, bool $bubble = true, bool $flushOnOverflow = false)
  38. {
  39. parent::__construct($level, $bubble);
  40. $this->handler = $handler;
  41. $this->bufferLimit = $bufferLimit;
  42. $this->flushOnOverflow = $flushOnOverflow;
  43. }
  44. /**
  45. * {@inheritdoc}
  46. */
  47. public function handle(array $record): bool
  48. {
  49. if ($record['level'] < $this->level) {
  50. return false;
  51. }
  52. if (!$this->initialized) {
  53. // __destructor() doesn't get called on Fatal errors
  54. register_shutdown_function([$this, 'close']);
  55. $this->initialized = true;
  56. }
  57. if ($this->bufferLimit > 0 && $this->bufferSize === $this->bufferLimit) {
  58. if ($this->flushOnOverflow) {
  59. $this->flush();
  60. } else {
  61. array_shift($this->buffer);
  62. $this->bufferSize--;
  63. }
  64. }
  65. if ($this->processors) {
  66. $record = $this->processRecord($record);
  67. }
  68. $this->buffer[] = $record;
  69. $this->bufferSize++;
  70. return false === $this->bubble;
  71. }
  72. public function flush(): void
  73. {
  74. if ($this->bufferSize === 0) {
  75. return;
  76. }
  77. $this->handler->handleBatch($this->buffer);
  78. $this->clear();
  79. }
  80. public function __destruct()
  81. {
  82. // suppress the parent behavior since we already have register_shutdown_function()
  83. // to call close(), and the reference contained there will prevent this from being
  84. // GC'd until the end of the request
  85. }
  86. /**
  87. * {@inheritdoc}
  88. */
  89. public function close(): void
  90. {
  91. $this->flush();
  92. $this->handler->close();
  93. }
  94. /**
  95. * Clears the buffer without flushing any messages down to the wrapped handler.
  96. */
  97. public function clear(): void
  98. {
  99. $this->bufferSize = 0;
  100. $this->buffer = [];
  101. }
  102. public function reset()
  103. {
  104. $this->flush();
  105. parent::reset();
  106. $this->resetProcessors();
  107. if ($this->handler instanceof ResettableInterface) {
  108. $this->handler->reset();
  109. }
  110. }
  111. }