BryanDavis has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/181346

Change subject: monolog: MWLoggerMonologSamplingHandler
......................................................................

monolog: MWLoggerMonologSamplingHandler

Introduce the MWLoggerMonologSamplingHandler which can
be used to probabilistically sample the log event stream.

Bug: T85067
Change-Id: Icd14fc8c44ca9eef0f3f5cc4f1d1d8b68d517f07
---
M autoload.php
M includes/debug/logger/Logger.php
A includes/debug/logger/monolog/SamplingHandler.php
M includes/debug/logger/monolog/Spi.php
4 files changed, 148 insertions(+), 8 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core 
refs/changes/46/181346/1

diff --git a/autoload.php b/autoload.php
index d4a152a..50727bc 100644
--- a/autoload.php
+++ b/autoload.php
@@ -684,6 +684,7 @@
        'MWLoggerMonologHandler' => __DIR__ . 
'/includes/debug/logger/monolog/Handler.php',
        'MWLoggerMonologLegacyFormatter' => __DIR__ . 
'/includes/debug/logger/monolog/LegacyFormatter.php',
        'MWLoggerMonologProcessor' => __DIR__ . 
'/includes/debug/logger/monolog/Processor.php',
+       'MWLoggerMonologSamplingHandler' => __DIR__ . 
'/includes/debug/logger/monolog/SamplingHandler.php',
        'MWLoggerMonologSpi' => __DIR__ . 
'/includes/debug/logger/monolog/Spi.php',
        'MWLoggerNullSpi' => __DIR__ . '/includes/debug/logger/NullSpi.php',
        'MWLoggerSpi' => __DIR__ . '/includes/debug/logger/Spi.php',
diff --git a/includes/debug/logger/Logger.php b/includes/debug/logger/Logger.php
index c54d241..960faef 100644
--- a/includes/debug/logger/Logger.php
+++ b/includes/debug/logger/Logger.php
@@ -199,12 +199,18 @@
 
 
        /**
-        * Get a named logger instance from the currently configured logger 
factory.
+        * Get the registered service provider.
         *
-        * @param string $channel Logger channel (name)
-        * @return MWLogger
+        * If called before any service provider has been registered, it will
+        * attempt to use the $wgMWLoggerDefaultSpi global to bootstrap
+        * MWLoggerSpi registration. $wgMWLoggerDefaultSpi is expected to be an
+        * array usable by ObjectFactory::getObjectFromSpec() to create a class.
+        *
+        * @return MWLoggerSpi
+        * @see registerProvider()
+        * @see ObjectFactory::getObjectFromSpec()
         */
-       public static function getInstance( $channel ) {
+       public static function getProvider() {
                if ( self::$spi === null ) {
                        global $wgMWLoggerDefaultSpi;
                        $provider = ObjectFactory::getObjectFromSpec(
@@ -212,8 +218,17 @@
                        );
                        self::registerProvider( $provider );
                }
+               return self::$spi;
+       }
 
-               return self::$spi->getLogger( $channel );
+       /**
+        * Get a named logger instance from the currently configured logger 
factory.
+        *
+        * @param string $channel Logger channel (name)
+        * @return MWLogger
+        */
+       public static function getInstance( $channel ) {
+               return self::getProvider()->getLogger( $channel );
        }
 
 }
diff --git a/includes/debug/logger/monolog/SamplingHandler.php 
b/includes/debug/logger/monolog/SamplingHandler.php
new file mode 100644
index 0000000..b35d108
--- /dev/null
+++ b/includes/debug/logger/monolog/SamplingHandler.php
@@ -0,0 +1,124 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+use Monolog\Handler\HandlerInterface;
+
+/**
+ * Wrapper for another HandlerInterface that will only handle a percentage of
+ * records offered to it.
+ *
+ * When HandlerInterface::handle() is called for a given record, it will be
+ * handled or ignored with a one in N chance based on the sample factor given
+ * for the handler.
+ *
+ * Usage with MWLoggerMonologSpi:
+ * @code
+ * $wgMWLoggerDefaultSpi = array(
+ *   'class' => 'MWLoggerMonologSpi',
+ *   'args' => array( array(
+ *     'handlers' => array(
+ *       'some-handler' => array( ... ),
+ *       'sampled-some-handler' => array(
+ *         'class' => 'MWLoggerMonologSamplingHandler',
+ *         'args' => array(
+ *           function() {
+ *             return MWLogger::getProvider()->getHandler( 'some-handler');
+ *           },
+ *           2, // emit logs with a 1:2 chance
+ *         ),
+ *       ),
+ *     ),
+ *   ) ),
+ * );
+ * @endcode
+ *
+ * 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 occurence. 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 [[Law of large numbers]] it will
+ * tend to be close to this ratio with a large number of attempts.
+ *
+ * @since 1.25
+ * @author Bryan Davis <[email protected]>
+ * @copyright © 2014 Bryan Davis and Wikimedia Foundation.
+ */
+class MWLoggerMonologSamplingHandler implements HandlerInterface {
+
+       const EMIT_KEY = '__MWLoggerMonologSamplingHandler__emit';
+
+       /**
+        * @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 ) {
+               $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 handleBatch( array $records ) {
+               foreach ( $records as $record ) {
+                       $this->handle( $record );
+               }
+       }
+
+       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();
+       }
+
+}
diff --git a/includes/debug/logger/monolog/Spi.php 
b/includes/debug/logger/monolog/Spi.php
index 4ad5687..121dbe4 100644
--- a/includes/debug/logger/monolog/Spi.php
+++ b/includes/debug/logger/monolog/Spi.php
@@ -199,7 +199,7 @@
         * @param string $name Processor name
         * @return callable
         */
-       protected function getProcessor( $name ) {
+       public function getProcessor( $name ) {
                if ( !isset( $this->singletons['processors'][$name] ) ) {
                        $spec = $this->config['processors'][$name];
                        $processor = ObjectFactory::getObjectFromSpec( $spec );
@@ -214,7 +214,7 @@
         * @param string $name Processor name
         * @return \Monolog\Handler\HandlerInterface
         */
-       protected function getHandler( $name ) {
+       public function getHandler( $name ) {
                if ( !isset( $this->singletons['handlers'][$name] ) ) {
                        $spec = $this->config['handlers'][$name];
                        $handler = ObjectFactory::getObjectFromSpec( $spec );
@@ -234,7 +234,7 @@
         * @param string $name Formatter name
         * @return \Monolog\Formatter\FormatterInterface
         */
-       protected function getFormatter( $name ) {
+       public function getFormatter( $name ) {
                if ( !isset( $this->singletons['formatters'][$name] ) ) {
                        $spec = $this->config['formatters'][$name];
                        $formatter = ObjectFactory::getObjectFromSpec( $spec );

-- 
To view, visit https://gerrit.wikimedia.org/r/181346
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Icd14fc8c44ca9eef0f3f5cc4f1d1d8b68d517f07
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: BryanDavis <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to