MediaWiki master
Profiler.php
Go to the documentation of this file.
1<?php
23use Psr\Log\LoggerInterface;
25use Wikimedia\ScopedCallback;
26
37abstract class Profiler {
39 protected $profileID = false;
41 protected $params = [];
43 protected $trxProfiler;
45 protected $logger;
47 private $allowOutput = false;
48
50 private static $instance = null;
51
55 public function __construct( array $params ) {
56 if ( isset( $params['profileID'] ) ) {
57 $this->profileID = $params['profileID'];
58 }
59 $this->params = $params;
60 $this->trxProfiler = new TransactionProfiler();
61 $this->logger = LoggerFactory::getInstance( 'profiler' );
62 }
63
68 final public static function init( array $profilerConf ): void {
69 $params = $profilerConf + [
70 'class' => ProfilerStub::class,
71 'sampling' => 1,
72 'threshold' => 0.0,
73 'output' => [],
74 'cliEnable' => false,
75 ];
76
77 // Avoid global func wfIsCLI() during setup
78 $isCLI = ( PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg' );
79 $inSample = $params['sampling'] === 1 || mt_rand( 1, $params['sampling'] ) === 1;
80 if (
81 !$inSample ||
82 // On CLI, profiling is disabled by default, and can be explicitly enabled
83 // via the `--profiler` option, which MediaWiki\Maintenance\MaintenanceRunner::setup
84 // translates into 'cliEnable'.
85 // See also $wgProfiler docs.
86 //
87 // For this to work, Setup.php must call Profiler::init() after handling of
88 // MW_FINAL_SETUP_CALLBACK, which is what doMaintenance.php uses to call
89 // MaintenanceRunner::setup.
90 ( $isCLI && !$params['cliEnable'] )
91 ) {
92 $params['class'] = ProfilerStub::class;
93 }
94
95 if ( !is_array( $params['output'] ) ) {
96 $params['output'] = [ $params['output'] ];
97 }
98
99 self::$instance = new $params['class']( $params );
100 }
101
105 final public static function instance() {
106 if ( !self::$instance ) {
107 trigger_error( 'Called Profiler::instance before settings are loaded', E_USER_WARNING );
108 self::init( [] );
109 }
110
111 return self::$instance;
112 }
113
118 public function setProfileID( $id ) {
119 wfDeprecated( __METHOD__, '1.41' );
120 $this->profileID = $id;
121 }
122
126 public function getProfileID() {
127 if ( $this->profileID === false ) {
128 return WikiMap::getCurrentWikiDbDomain()->getId();
129 } else {
130 return $this->profileID;
131 }
132 }
133
142 abstract public function scopedProfileIn( $section );
143
147 public function scopedProfileOut( ?SectionProfileCallback &$section = null ) {
148 $section = null;
149 }
150
155 public function getTransactionProfiler() {
156 return $this->trxProfiler;
157 }
158
162 abstract public function close();
163
170 private function getOutputs() {
171 $outputs = [];
172 foreach ( $this->params['output'] as $outputType ) {
173 // The class may be specified as either the full class name (for
174 // example, 'ProfilerOutputStats') or (for backward compatibility)
175 // the trailing portion of the class name (for example, 'stats').
176 $outputClass = strpos( $outputType, 'ProfilerOutput' ) === false
177 ? 'ProfilerOutput' . ucfirst( $outputType )
178 : $outputType;
179 if ( !class_exists( $outputClass ) ) {
180 throw new UnexpectedValueException( "'$outputType' is an invalid output type" );
181 }
182 $outputInstance = new $outputClass( $this, $this->params );
183 if ( $outputInstance->canUse() ) {
184 $outputs[] = $outputInstance;
185 }
186 }
187 return $outputs;
188 }
189
198 public function logData() {
199 if ( $this->params['threshold'] > 0.0 ) {
200 // Note, this is also valid for CLI processes.
201 $timeElapsed = microtime( true ) - $_SERVER['REQUEST_TIME_FLOAT'];
202 if ( $timeElapsed <= $this->params['threshold'] ) {
203 return;
204 }
205 }
206
207 $outputs = [];
208 foreach ( $this->getOutputs() as $output ) {
209 if ( !$output->logsToOutput() ) {
210 $outputs[] = $output;
211 }
212 }
213
214 if ( $outputs ) {
215 $stats = $this->getFunctionStats();
216 foreach ( $outputs as $output ) {
217 $output->log( $stats );
218 }
219 }
220 }
221
227 public function logDataPageOutputOnly() {
228 if ( !$this->allowOutput ) {
229 return;
230 }
231
232 $outputs = [];
233 foreach ( $this->getOutputs() as $output ) {
234 if ( $output->logsToOutput() ) {
235 $outputs[] = $output;
236 }
237 }
238
239 if ( $outputs ) {
240 $stats = $this->getFunctionStats();
241 foreach ( $outputs as $output ) {
242 $output->log( $stats );
243 }
244 }
245 }
246
256 public function getContentType() {
257 if ( $this->allowOutput ) {
258 foreach ( headers_list() as $header ) {
259 if ( preg_match( '#^content-type: (\w+/\w+);?#i', $header, $m ) ) {
260 return $m[1];
261 }
262 }
263 }
264 return null;
265 }
266
272 public function setAllowOutput() {
273 $this->allowOutput = true;
274 }
275
284 public function getAllowOutput() {
285 wfDeprecated( __METHOD__, '1.41' );
286 return $this->allowOutput;
287 }
288
315 abstract public function getFunctionStats();
316
322 abstract public function getOutput();
323}
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
Create PSR-3 logger objects.
Tools for dealing with other locally-hosted wikis.
Definition WikiMap.php:31
Stub profiler that does nothing.
Profiler base class that defines the interface and some shared functionality.
Definition Profiler.php:37
setAllowOutput()
Enable appending profiles to standard output.
Definition Profiler.php:272
setProfileID( $id)
Definition Profiler.php:118
scopedProfileOut(?SectionProfileCallback &$section=null)
Definition Profiler.php:147
getTransactionProfiler()
Definition Profiler.php:155
close()
Close opened profiling sections.
logData()
Log data to all the applicable backing stores.
Definition Profiler.php:198
TransactionProfiler $trxProfiler
Definition Profiler.php:43
__construct(array $params)
Definition Profiler.php:55
string false $profileID
Profiler ID for bucketing data.
Definition Profiler.php:39
logDataPageOutputOnly()
Log the data to the script/request output for all ProfilerOutput instances that do so.
Definition Profiler.php:227
getOutput()
Returns a profiling output to be stored in debug file.
static init(array $profilerConf)
Definition Profiler.php:68
static instance()
Definition Profiler.php:105
getContentType()
Get the Content-Type for deciding how to format appended profile output.
Definition Profiler.php:256
getFunctionStats()
Get the aggregated inclusive profiling data for each method.
getProfileID()
Definition Profiler.php:126
scopedProfileIn( $section)
Mark the start of a custom profiling frame (e.g.
getAllowOutput()
Whether appending profiles is allowed.
Definition Profiler.php:284
LoggerInterface $logger
Definition Profiler.php:45
array $params
All of the params passed from $wgProfiler.
Definition Profiler.php:41
Subclass ScopedCallback to avoid call_user_func_array(), which is slow.
Detect high-contention DB queries via profiling calls.
$header