Răsfoiți Sursa

Add a SamplingHandler

It wraps around another handler, and only passes on some messages
based on the provided sampling handler.

This was originally written for MediaWiki: https://gerrit.wikimedia.org/r/181346
Kunal Mehta 11 ani în urmă
părinte
comite
d79400bade

+ 2 - 0
README.mdown

@@ -186,6 +186,8 @@ Handlers
   sent to all the handlers it is configured with.
   sent to all the handlers it is configured with.
 - _FilterHandler_: This handler only lets records of the given levels through
 - _FilterHandler_: This handler only lets records of the given levels through
    to the wrapped handler.
    to the wrapped handler.
+- _SamplingHandler_: Wraps around another handler and lets you sample records
+   if you only want to store some of them.
 - _TestHandler_: Used for testing, it records everything that is sent to it and
 - _TestHandler_: Used for testing, it records everything that is sent to it and
   has accessors to read out the information.
   has accessors to read out the information.
 - _WhatFailureGroupHandler_: This handler extends the _GroupHandler_ ignoring
 - _WhatFailureGroupHandler_: This handler extends the _GroupHandler_ ignoring

+ 89 - 0
src/Monolog/Handler/SamplingHandler.php

@@ -0,0 +1,89 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\FormatterInterface;
+
+/**
+ * Sampling handler
+ *
+ * A sampled event stream can be useful for logging high frequency events in
+ * a production environment where you only need an idea of what is happening
+ * and are not concerned with capturing every occurrence. Since the decision to
+ * handle or not handle a particular event is determined randomly, the
+ * resulting sampled log is not guaranteed to contain 1/N of the events that
+ * occurred in the application, but based on the Law of large numbers, it will
+ * tend to be close to this ratio with a large number of attempts.
+ *
+ * @author Bryan Davis <bd808@wikimedia.org>
+ * @author Kunal Mehta <legoktm@gmail.com>
+ */
+class SamplingHandler extends AbstractHandler
+{
+    /**
+     * @var HandlerInterface $delegate
+     */
+    protected $delegate;
+
+    /**
+     * @var int $factor
+     */
+    protected $factor;
+
+    /**
+     * @param HandlerInterface $handler Wrapped handler
+     * @param int $factor Sample factor
+     */
+    public function __construct(HandlerInterface $handler, $factor)
+    {
+        parent::__construct();
+        $this->delegate = $handler;
+        $this->factor = $factor;
+    }
+
+    public function isHandling(array $record)
+    {
+        return $this->delegate->isHandling($record);
+    }
+
+    public function handle(array $record)
+    {
+        if ($this->isHandling($record)
+            && mt_rand(1, $this->factor) === 1)
+        {
+            return $this->delegate->handle($record);
+        }
+        return false;
+    }
+
+    public function pushProcessor($callback)
+    {
+        $this->delegate->pushProcessor($callback);
+        return $this;
+    }
+
+    public function popProcessor()
+    {
+        return $this->delegate->popProcessor();
+    }
+
+    public function setFormatter(FormatterInterface $formatter)
+    {
+        $this->delegate->setFormatter($formatter);
+        return $this;
+    }
+
+    public function getFormatter()
+    {
+        return $this->delegate->getFormatter();
+    }
+}

+ 35 - 0
tests/Monolog/Handler/SamplingHandlerTest.php

@@ -0,0 +1,35 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+
+/**
+ * @covers Monolog\Handler\SamplingHandler::handle
+ */
+class SamplingHandlerTest extends TestCase
+{
+    public function testHandle()
+    {
+        $testHandler = new TestHandler();
+        $handler = new SamplingHandler($testHandler, 2);
+        for ($i=0; $i<10000; $i++)
+        {
+            $handler->handle($this->getRecord());
+        }
+        $count = count($testHandler->getRecords());
+        // $count should be half of 10k, so between 4k and 6k
+        $this->assertLessThan(6000, $count);
+        $this->assertGreaterThan(4000, $count);
+    }
+}