MediaWiki REL1_39
Profiler.php
Go to the documentation of this file.
1<?php
22use Psr\Log\LoggerInterface;
24use Wikimedia\ScopedCallback;
25
36abstract class Profiler {
38 protected $profileID = false;
40 protected $params = [];
42 protected $context = null;
44 protected $trxProfiler;
46 protected $logger;
48 private $allowOutput = false;
49
51 private static $instance = null;
52
56 public function __construct( array $params ) {
57 if ( isset( $params['profileID'] ) ) {
58 $this->profileID = $params['profileID'];
59 }
60 $this->params = $params;
61 $this->trxProfiler = new TransactionProfiler();
62 $this->logger = LoggerFactory::getInstance( 'profiler' );
63 }
64
69 final public static function instance() {
70 if ( self::$instance === null ) {
71 global $wgProfiler;
72
73 $params = ( $wgProfiler ?? [] ) + [
74 'class' => ProfilerStub::class,
75 'sampling' => 1,
76 'threshold' => 0.0,
77 'output' => [],
78 ];
79
80 $inSample = mt_rand( 0, $params['sampling'] - 1 ) === 0;
81 // wfIsCLI() is not available yet
82 if ( PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg' || !$inSample ) {
83 $params['class'] = ProfilerStub::class;
84 }
85
86 // "Redundant attempt to cast $params['output'] of type array{} to array"
87 // Not correct, this could be a non-array if $wgProfiler sets it to a non-array.
88 // @phan-suppress-next-line PhanRedundantCondition
89 if ( !is_array( $params['output'] ) ) {
90 $params['output'] = [ $params['output'] ];
91 }
92
93 self::$instance = new $params['class']( $params );
94 }
95 return self::$instance;
96 }
97
105 final public static function replaceStubInstance( Profiler $profiler ) {
106 if ( self::$instance && !( self::$instance instanceof ProfilerStub ) ) {
107 throw new MWException( 'Could not replace non-stub profiler instance.' );
108 } else {
109 self::$instance = $profiler;
110 }
111 }
112
116 public function setProfileID( $id ) {
117 $this->profileID = $id;
118 }
119
123 public function getProfileID() {
124 if ( $this->profileID === false ) {
125 return WikiMap::getCurrentWikiDbDomain()->getId();
126 } else {
127 return $this->profileID;
128 }
129 }
130
136 public function setContext( $context ) {
137 wfDeprecated( __METHOD__, '1.38' );
138 $this->context = $context;
139 }
140
146 public function getContext() {
147 wfDeprecated( __METHOD__, '1.38' );
148 return $this->context ?? RequestContext::getMain();
149 }
150
159 abstract public function scopedProfileIn( $section );
160
164 public function scopedProfileOut( SectionProfileCallback &$section = null ) {
165 $section = null;
166 }
167
172 public function getTransactionProfiler() {
173 return $this->trxProfiler;
174 }
175
179 abstract public function close();
180
188 private function getOutputs() {
189 $outputs = [];
190 foreach ( $this->params['output'] as $outputType ) {
191 // The class may be specified as either the full class name (for
192 // example, 'ProfilerOutputStats') or (for backward compatibility)
193 // the trailing portion of the class name (for example, 'stats').
194 $outputClass = strpos( $outputType, 'ProfilerOutput' ) === false
195 ? 'ProfilerOutput' . ucfirst( $outputType )
196 : $outputType;
197 if ( !class_exists( $outputClass ) ) {
198 throw new MWException( "'$outputType' is an invalid output type" );
199 }
200 $outputInstance = new $outputClass( $this, $this->params );
201 if ( $outputInstance->canUse() ) {
202 $outputs[] = $outputInstance;
203 }
204 }
205 return $outputs;
206 }
207
213 public function logData() {
214 if ( $this->params['threshold'] > 0.0 ) {
215 // Note, this is also valid for CLI processes.
216 $timeElapsed = microtime( true ) - $_SERVER['REQUEST_TIME_FLOAT'];
217 if ( $timeElapsed <= $this->params['threshold'] ) {
218 return;
219 }
220 }
221
222 $outputs = [];
223 foreach ( $this->getOutputs() as $output ) {
224 if ( !$output->logsToOutput() ) {
225 $outputs[] = $output;
226 }
227 }
228
229 if ( $outputs ) {
230 $stats = $this->getFunctionStats();
231 foreach ( $outputs as $output ) {
232 $output->log( $stats );
233 }
234 }
235 }
236
243 public function logDataPageOutputOnly() {
244 if ( !$this->allowOutput ) {
245 return;
246 }
247
248 $outputs = [];
249 foreach ( $this->getOutputs() as $output ) {
250 if ( $output->logsToOutput() ) {
251 $outputs[] = $output;
252 }
253 }
254
255 if ( $outputs ) {
256 $stats = $this->getFunctionStats();
257 foreach ( $outputs as $output ) {
258 $output->log( $stats );
259 }
260 }
261 }
262
272 public function getContentType() {
273 if ( $this->allowOutput ) {
274 foreach ( headers_list() as $header ) {
275 if ( preg_match( '#^content-type: (\w+/\w+);?#i', $header, $m ) ) {
276 return $m[1];
277 }
278 }
279 }
280 return null;
281 }
282
288 public function setAllowOutput() {
289 $this->allowOutput = true;
290 }
291
298 public function getAllowOutput() {
299 return $this->allowOutput;
300 }
301
328 abstract public function getFunctionStats();
329
335 abstract public function getOutput();
336}
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
MediaWiki exception.
PSR-3 logger instance factory.
Stub profiler that does nothing.
Profiler base class that defines the interface and some shared functionality.
Definition Profiler.php:36
setAllowOutput()
Enable appending profiles to standard output.
Definition Profiler.php:288
static replaceStubInstance(Profiler $profiler)
Replace the current profiler with $profiler if no non-stub profiler is set.
Definition Profiler.php:105
setProfileID( $id)
Definition Profiler.php:116
string bool $profileID
Profiler ID for bucketing data.
Definition Profiler.php:38
getTransactionProfiler()
Definition Profiler.php:172
setContext( $context)
Definition Profiler.php:136
IContextSource $context
Current request context.
Definition Profiler.php:42
close()
Close opened profiling sections.
logData()
Log the data to the backing store for all ProfilerOutput instances that have one.
Definition Profiler.php:213
TransactionProfiler $trxProfiler
Definition Profiler.php:44
__construct(array $params)
Definition Profiler.php:56
logDataPageOutputOnly()
Log the data to the script/request output for all ProfilerOutput instances that do so.
Definition Profiler.php:243
getOutput()
Returns a profiling output to be stored in debug file.
static instance()
Singleton.
Definition Profiler.php:69
getContentType()
Get the Content-Type for deciding how to format appended profile output.
Definition Profiler.php:272
getFunctionStats()
Get the aggregated inclusive profiling data for each method.
getProfileID()
Definition Profiler.php:123
scopedProfileIn( $section)
Mark the start of a custom profiling frame (e.g.
getAllowOutput()
Whether appending profiles is allowed.
Definition Profiler.php:298
scopedProfileOut(SectionProfileCallback &$section=null)
Definition Profiler.php:164
LoggerInterface $logger
Definition Profiler.php:46
array $params
All of the params passed from $wgProfiler.
Definition Profiler.php:40
Subclass ScopedCallback to avoid call_user_func_array(), which is slow.
Detect high-contention DB queries via profiling calls.
$wgProfiler
Config variable stub for the Profiler setting, for use by phpdoc and IDEs.
Interface for objects which can provide a MediaWiki context on request.
$header