MediaWiki master
Profiler.php
Go to the documentation of this file.
1<?php
7namespace MediaWiki\Profiler;
8
11use Psr\Log\LoggerInterface;
12use UnexpectedValueException;
14
25abstract class Profiler {
27 protected $profileID = false;
29 protected $params = [];
31 protected $trxProfiler;
33 protected $logger;
35 private $allowOutput = false;
36
38 private static $instance = null;
39
43 public function __construct( array $params ) {
44 if ( isset( $params['profileID'] ) ) {
45 $this->profileID = $params['profileID'];
46 }
47 $this->params = $params;
48 $this->trxProfiler = new TransactionProfiler();
49 $this->logger = LoggerFactory::getInstance( 'profiler' );
50 }
51
56 final public static function init( array $profilerConf ): void {
57 $params = $profilerConf + [
58 'class' => ProfilerStub::class,
59 'sampling' => 1,
60 'threshold' => 0.0,
61 'output' => [],
62 'cliEnable' => false,
63 ];
64
65 // Avoid global func wfIsCLI() during setup
66 $isCLI = ( PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg' );
67 $inSample = $params['sampling'] === 1 || mt_rand( 1, $params['sampling'] ) === 1;
68 if (
69 !$inSample ||
70 // On CLI, profiling is disabled by default, and can be explicitly enabled
71 // via the `--profiler` option, which MediaWiki\Maintenance\MaintenanceRunner::setup
72 // translates into 'cliEnable'.
73 // See also $wgProfiler docs.
74 //
75 // For this to work, Setup.php must call Profiler::init() after handling of
76 // MW_FINAL_SETUP_CALLBACK, which is what doMaintenance.php uses to call
77 // MaintenanceRunner::setup.
78 ( $isCLI && !$params['cliEnable'] )
79 ) {
80 $params['class'] = ProfilerStub::class;
81 }
82
83 if ( !is_array( $params['output'] ) ) {
84 $params['output'] = [ $params['output'] ];
85 }
86
87 self::$instance = new $params['class']( $params );
88 }
89
93 final public static function instance() {
94 if ( !self::$instance ) {
95 trigger_error( 'Called Profiler::instance before settings are loaded', E_USER_WARNING );
96 self::init( [] );
97 }
98
99 return self::$instance;
100 }
101
106 public function setProfileID( $id ) {
107 wfDeprecated( __METHOD__, '1.41' );
108 $this->profileID = $id;
109 }
110
114 public function getProfileID() {
115 if ( $this->profileID === false ) {
116 return WikiMap::getCurrentWikiDbDomain()->getId();
117 } else {
118 return $this->profileID;
119 }
120 }
121
129 #[\NoDiscard]
130 abstract public function scopedProfileIn( $section ): ?SectionProfileCallback;
131
135 public function scopedProfileOut( ?SectionProfileCallback &$section = null ) {
136 $section = null;
137 }
138
143 public function getTransactionProfiler() {
144 return $this->trxProfiler;
145 }
146
150 abstract public function close();
151
158 private function getOutputs() {
159 $outputs = [];
160 foreach ( $this->params['output'] as $outputType ) {
161 // The class may be specified as either the full class name (for
162 // example, 'ProfilerOutputStats') or (for backward compatibility)
163 // the trailing portion of the class name (for example, 'stats').
164 $outputClass = !str_contains( $outputType, 'ProfilerOutput' )
165 ? 'ProfilerOutput' . ucfirst( $outputType )
166 : $outputType;
167 if ( !class_exists( $outputClass ) ) {
168 throw new UnexpectedValueException( "'$outputType' is an invalid output type" );
169 }
170 $outputInstance = new $outputClass( $this, $this->params );
171 if ( $outputInstance->canUse() ) {
172 $outputs[] = $outputInstance;
173 }
174 }
175 return $outputs;
176 }
177
186 public function logData() {
187 if ( $this->params['threshold'] > 0.0 ) {
188 // Note, this is also valid for CLI processes.
189 $timeElapsed = microtime( true ) - $_SERVER['REQUEST_TIME_FLOAT'];
190 if ( $timeElapsed <= $this->params['threshold'] ) {
191 return;
192 }
193 }
194
195 $outputs = [];
196 foreach ( $this->getOutputs() as $output ) {
197 if ( !$output->logsToOutput() ) {
198 $outputs[] = $output;
199 }
200 }
201
202 if ( $outputs ) {
203 $stats = $this->getFunctionStats();
204 foreach ( $outputs as $output ) {
205 $output->log( $stats );
206 }
207 }
208 }
209
215 public function logDataPageOutputOnly() {
216 if ( !$this->allowOutput ) {
217 return;
218 }
219
220 $outputs = [];
221 foreach ( $this->getOutputs() as $output ) {
222 if ( $output->logsToOutput() ) {
223 $outputs[] = $output;
224 }
225 }
226
227 if ( $outputs ) {
228 $stats = $this->getFunctionStats();
229 foreach ( $outputs as $output ) {
230 $output->log( $stats );
231 }
232 }
233 }
234
244 public function getContentType() {
245 if ( $this->allowOutput ) {
246 foreach ( headers_list() as $header ) {
247 if ( preg_match( '#^content-type: (\w+/\w+);?#i', $header, $m ) ) {
248 return $m[1];
249 }
250 }
251 }
252 return null;
253 }
254
260 public function setAllowOutput() {
261 $this->allowOutput = true;
262 }
263
272 public function getAllowOutput() {
273 wfDeprecated( __METHOD__, '1.41' );
274 return $this->allowOutput;
275 }
276
303 abstract public function getFunctionStats();
304
310 abstract public function getOutput();
311}
312
314class_alias( Profiler::class, 'Profiler' );
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
Create PSR-3 logger objects.
Stub profiler that does nothing.
Profiler base class that defines the interface and some shared functionality.
Definition Profiler.php:25
setAllowOutput()
Enable appending profiles to standard output.
Definition Profiler.php:260
TransactionProfiler $trxProfiler
Definition Profiler.php:31
scopedProfileOut(?SectionProfileCallback &$section=null)
Definition Profiler.php:135
scopedProfileIn( $section)
Mark the start of a custom profiling frame (e.g.
LoggerInterface $logger
Definition Profiler.php:33
getFunctionStats()
Get the aggregated inclusive profiling data for each method.
string false $profileID
Profiler ID for bucketing data.
Definition Profiler.php:27
__construct(array $params)
Definition Profiler.php:43
getOutput()
Returns a profiling output to be stored in debug file.
getAllowOutput()
Whether appending profiles is allowed.
Definition Profiler.php:272
array $params
All of the params passed from $wgProfiler.
Definition Profiler.php:29
close()
Close opened profiling sections.
logDataPageOutputOnly()
Log the data to the script/request output for all ProfilerOutput instances that do so.
Definition Profiler.php:215
logData()
Log data to all the applicable backing stores.
Definition Profiler.php:186
getContentType()
Get the Content-Type for deciding how to format appended profile output.
Definition Profiler.php:244
static init(array $profilerConf)
Definition Profiler.php:56
Subclass ScopedCallback to avoid call_user_func_array(), which is slow.
Tools for dealing with other locally-hosted wikis.
Definition WikiMap.php:19
Detect high-contention DB queries via profiling calls.