SamplingHandler.php 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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 Closure;
  12. use Monolog\Formatter\FormatterInterface;
  13. use Monolog\LogRecord;
  14. /**
  15. * Sampling handler
  16. *
  17. * A sampled event stream can be useful for logging high frequency events in
  18. * a production environment where you only need an idea of what is happening
  19. * and are not concerned with capturing every occurrence. Since the decision to
  20. * handle or not handle a particular event is determined randomly, the
  21. * resulting sampled log is not guaranteed to contain 1/N of the events that
  22. * occurred in the application, but based on the Law of large numbers, it will
  23. * tend to be close to this ratio with a large number of attempts.
  24. *
  25. * @author Bryan Davis <bd808@wikimedia.org>
  26. * @author Kunal Mehta <legoktm@gmail.com>
  27. */
  28. class SamplingHandler extends AbstractHandler implements ProcessableHandlerInterface, FormattableHandlerInterface
  29. {
  30. use ProcessableHandlerTrait;
  31. /**
  32. * Handler or factory callable($record, $this)
  33. *
  34. * @phpstan-var (Closure(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface
  35. */
  36. protected Closure|HandlerInterface $handler;
  37. protected int $factor;
  38. /**
  39. * @phpstan-param (Closure(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler
  40. *
  41. * @param Closure|HandlerInterface $handler Handler or factory callable($record|null, $samplingHandler).
  42. * @param int $factor Sample factor (e.g. 10 means every ~10th record is sampled)
  43. */
  44. public function __construct(Closure|HandlerInterface $handler, int $factor)
  45. {
  46. parent::__construct();
  47. $this->handler = $handler;
  48. $this->factor = $factor;
  49. }
  50. public function isHandling(LogRecord $record): bool
  51. {
  52. return $this->getHandler($record)->isHandling($record);
  53. }
  54. public function handle(LogRecord $record): bool
  55. {
  56. if ($this->isHandling($record) && mt_rand(1, $this->factor) === 1) {
  57. if ($this->processors) {
  58. $record = $this->processRecord($record);
  59. }
  60. $this->getHandler($record)->handle($record);
  61. }
  62. return false === $this->bubble;
  63. }
  64. /**
  65. * Return the nested handler
  66. *
  67. * If the handler was provided as a factory callable, this will trigger the handler's instantiation.
  68. */
  69. public function getHandler(LogRecord $record = null): HandlerInterface
  70. {
  71. if (!$this->handler instanceof HandlerInterface) {
  72. $handler = ($this->handler)($record, $this);
  73. if (!$handler instanceof HandlerInterface) {
  74. throw new \RuntimeException("The factory callable should return a HandlerInterface");
  75. }
  76. $this->handler = $handler;
  77. }
  78. return $this->handler;
  79. }
  80. /**
  81. * @inheritDoc
  82. */
  83. public function setFormatter(FormatterInterface $formatter): HandlerInterface
  84. {
  85. $handler = $this->getHandler();
  86. if ($handler instanceof FormattableHandlerInterface) {
  87. $handler->setFormatter($formatter);
  88. return $this;
  89. }
  90. throw new \UnexpectedValueException('The nested handler of type '.get_class($handler).' does not support formatters.');
  91. }
  92. /**
  93. * @inheritDoc
  94. */
  95. public function getFormatter(): FormatterInterface
  96. {
  97. $handler = $this->getHandler();
  98. if ($handler instanceof FormattableHandlerInterface) {
  99. return $handler->getFormatter();
  100. }
  101. throw new \UnexpectedValueException('The nested handler of type '.get_class($handler).' does not support formatters.');
  102. }
  103. }