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