Simplify profiler output class selection
[lhc/web/wiklou.git] / includes / profiler / Profiler.php
index 667a9e2..dbf80fa 100644 (file)
@@ -35,23 +35,12 @@ abstract class Profiler {
        protected $templated = false;
        /** @var array All of the params passed from $wgProfiler */
        protected $params = array();
-
+       /** @var IContextSource Current request context */
+       protected $context = null;
        /** @var TransactionProfiler */
        protected $trxProfiler;
-
-       /**
-        * @var array Mapping of output type to class name
-        */
-       private static $outputTypes = array(
-               'db' => 'ProfilerOutputDb',
-               'text' => 'ProfilerOutputText',
-               'udp' => 'ProfilerOutputUdp',
-       );
-
-       // @codingStandardsIgnoreStart PSR2.Classes.PropertyDeclaration.Underscore
-       /** @var Profiler Do not call this outside Profiler and ProfileSection */
-       public static $__instance = null;
-       // @codingStandardsIgnoreEnd
+       /** @var Profiler */
+       private static $instance = null;
 
        /**
         * @param array $params
@@ -69,20 +58,31 @@ abstract class Profiler {
         * @return Profiler
         */
        final public static function instance() {
-               if ( self::$__instance === null ) {
-                       global $wgProfiler;
+               if ( self::$instance === null ) {
+                       global $wgProfiler, $wgProfileLimit;
+
+                       $params = array(
+                               'class'     => 'ProfilerStub',
+                               'sampling'  => 1,
+                               'threshold' => $wgProfileLimit,
+                               'output'    => array(),
+                       );
                        if ( is_array( $wgProfiler ) ) {
-                               $class = isset( $wgProfiler['class'] ) ? $wgProfiler['class'] : 'ProfilerStub';
-                               $factor = isset( $wgProfiler['sampling'] ) ? $wgProfiler['sampling'] : 1;
-                               if ( PHP_SAPI === 'cli' || mt_rand( 0, $factor - 1 ) != 0 ) {
-                                       $class = 'ProfilerStub';
-                               }
-                               self::$__instance = new $class( $wgProfiler );
-                       } else {
-                               self::$__instance = new ProfilerStub( array() );
+                               $params = array_merge( $params, $wgProfiler );
+                       }
+
+                       $inSample = mt_rand( 0, $params['sampling'] - 1 ) === 0;
+                       if ( PHP_SAPI === 'cli' || !$inSample ) {
+                               $params['class'] = 'ProfilerStub';
                        }
+
+                       if ( !is_array( $params['output'] ) ) {
+                               $params['output'] = array( $params['output'] );
+                       }
+
+                       self::$instance = new $params['class']( $params );
                }
-               return self::$__instance;
+               return self::$instance;
        }
 
        /**
@@ -93,10 +93,10 @@ abstract class Profiler {
         * @since 1.25
         */
        final public static function replaceStubInstance( Profiler $profiler ) {
-               if ( self::$__instance && !( self::$__instance instanceof ProfilerStub ) ) {
+               if ( self::$instance && !( self::$instance instanceof ProfilerStub ) ) {
                        throw new MWException( 'Could not replace non-stub profiler instance.' );
                } else {
-                       self::$__instance = $profiler;
+                       self::$instance = $profiler;
                }
        }
 
@@ -119,18 +119,34 @@ abstract class Profiler {
        }
 
        /**
-        * Called by wfProfieIn()
+        * Sets the context for this Profiler
         *
-        * @param string $functionname
+        * @param IContextSource $context
+        * @since 1.25
         */
-       abstract public function profileIn( $functionname );
+       public function setContext( $context ) {
+               $this->context = $context;
+       }
 
        /**
-        * Called by wfProfieOut()
+        * Gets the context for this Profiler
         *
-        * @param string $functionname
+        * @return IContextSource
+        * @since 1.25
         */
-       abstract public function profileOut( $functionname );
+       public function getContext() {
+               if ( $this->context ) {
+                       return $this->context;
+               } else {
+                       wfDebug( __METHOD__ . " called and \$context is null. " .
+                               "Return RequestContext::getMain(); for sanity\n" );
+                       return RequestContext::getMain();
+               }
+       }
+
+       // Kept BC for now, remove when possible
+       public function profileIn( $functionname ) {}
+       public function profileOut( $functionname ) {}
 
        /**
         * Mark the start of a custom profiling frame (e.g. DB queries).
@@ -145,7 +161,7 @@ abstract class Profiler {
        /**
         * @param ScopedCallback $section
         */
-       public function scopedProfileOut( ScopedCallback &$section ) {
+       public function scopedProfileOut( ScopedCallback &$section = null ) {
                $section = null;
        }
 
@@ -163,34 +179,54 @@ abstract class Profiler {
        abstract public function close();
 
        /**
-        * Log the data to some store or even the page output
+        * Get all usable outputs.
         *
         * @throws MWException
+        * @return array Array of ProfilerOutput instances.
+        * @since 1.25
+        */
+       private function getOutputs() {
+               $outputs = array();
+               foreach ( $this->params['output'] as $outputType ) {
+                       // The class may be specified as either the full class name (for
+                       // example, 'ProfilerOutputUdp') or (for backward compatibility)
+                       // the trailing portion of the class name (for example, 'udp').
+                       $outputClass = strpos( $outputType, 'ProfilerOutput' ) === false
+                               ? 'ProfilerOutput' . ucfirst( $outputType )
+                               : $outputType;
+                       if ( !class_exists( $outputClass ) ) {
+                               throw new MWException( "'$outputType' is an invalid output type" );
+                       }
+                       $outputInstance = new $outputClass( $this, $this->params );
+                       if ( $outputInstance->canUse() ) {
+                               $outputs[] = $outputInstance;
+                       }
+               }
+               return $outputs;
+       }
+
+       /**
+        * Log the data to some store or even the page output
+        *
         * @since 1.25
         */
        public function logData() {
-               $output = isset( $this->params['output'] ) ? $this->params['output'] : null;
+               $request = $this->getContext()->getRequest();
 
-               if ( !$output || $this instanceof ProfilerStub ) {
-                       // return early when no output classes defined or we're a stub
+               $timeElapsed = $request->getElapsedTime();
+               $timeElapsedThreshold = $this->params['threshold'];
+               if ( $timeElapsed <= $timeElapsedThreshold ) {
                        return;
                }
 
-               if ( !is_array( $output ) ) {
-                       $output = array( $output );
+               $outputs = $this->getOutputs();
+               if ( !$outputs ) {
+                       return;
                }
 
-               foreach ( $output as $outType ) {
-                       if ( !isset( self::$outputTypes[$outType] ) ) {
-                               throw new MWException( "'$outType' is an invalid output type" );
-                       }
-                       $class = self::$outputTypes[$outType];
-
-                       /** @var ProfilerOutput $profileOut */
-                       $profileOut = new $class( $this, $this->params );
-                       if ( $profileOut->canUse() ) {
-                               $profileOut->log( $this->getFunctionStats() );
-                       }
+               $stats = $this->getFunctionStats();
+               foreach ( $outputs as $output ) {
+                       $output->log( $stats );
                }
        }