MediaWiki master
Profiler.php
Go to the documentation of this file.
1<?php
9use Psr\Log\LoggerInterface;
11
22abstract class Profiler {
24 protected $profileID = false;
26 protected $params = [];
28 protected $trxProfiler;
30 protected $logger;
32 private $allowOutput = false;
33
35 private static $instance = null;
36
40 public function __construct( array $params ) {
41 if ( isset( $params['profileID'] ) ) {
42 $this->profileID = $params['profileID'];
43 }
44 $this->params = $params;
45 $this->trxProfiler = new TransactionProfiler();
46 $this->logger = LoggerFactory::getInstance( 'profiler' );
47 }
48
53 final public static function init( array $profilerConf ): void {
54 $params = $profilerConf + [
55 'class' => ProfilerStub::class,
56 'sampling' => 1,
57 'threshold' => 0.0,
58 'output' => [],
59 'cliEnable' => false,
60 ];
61
62 // Avoid global func wfIsCLI() during setup
63 $isCLI = ( PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg' );
64 $inSample = $params['sampling'] === 1 || mt_rand( 1, $params['sampling'] ) === 1;
65 if (
66 !$inSample ||
67 // On CLI, profiling is disabled by default, and can be explicitly enabled
68 // via the `--profiler` option, which MediaWiki\Maintenance\MaintenanceRunner::setup
69 // translates into 'cliEnable'.
70 // See also $wgProfiler docs.
71 //
72 // For this to work, Setup.php must call Profiler::init() after handling of
73 // MW_FINAL_SETUP_CALLBACK, which is what doMaintenance.php uses to call
74 // MaintenanceRunner::setup.
75 ( $isCLI && !$params['cliEnable'] )
76 ) {
77 $params['class'] = ProfilerStub::class;
78 }
79
80 if ( !is_array( $params['output'] ) ) {
81 $params['output'] = [ $params['output'] ];
82 }
83
84 self::$instance = new $params['class']( $params );
85 }
86
90 final public static function instance() {
91 if ( !self::$instance ) {
92 trigger_error( 'Called Profiler::instance before settings are loaded', E_USER_WARNING );
93 self::init( [] );
94 }
95
96 return self::$instance;
97 }
98
103 public function setProfileID( $id ) {
104 wfDeprecated( __METHOD__, '1.41' );
105 $this->profileID = $id;
106 }
107
111 public function getProfileID() {
112 if ( $this->profileID === false ) {
113 return WikiMap::getCurrentWikiDbDomain()->getId();
114 } else {
115 return $this->profileID;
116 }
117 }
118
126 abstract public function scopedProfileIn( $section ): ?SectionProfileCallback;
127
131 public function scopedProfileOut( ?SectionProfileCallback &$section = null ) {
132 $section = null;
133 }
134
139 public function getTransactionProfiler() {
140 return $this->trxProfiler;
141 }
142
146 abstract public function close();
147
154 private function getOutputs() {
155 $outputs = [];
156 foreach ( $this->params['output'] as $outputType ) {
157 // The class may be specified as either the full class name (for
158 // example, 'ProfilerOutputStats') or (for backward compatibility)
159 // the trailing portion of the class name (for example, 'stats').
160 $outputClass = !str_contains( $outputType, 'ProfilerOutput' )
161 ? 'ProfilerOutput' . ucfirst( $outputType )
162 : $outputType;
163 if ( !class_exists( $outputClass ) ) {
164 throw new UnexpectedValueException( "'$outputType' is an invalid output type" );
165 }
166 $outputInstance = new $outputClass( $this, $this->params );
167 if ( $outputInstance->canUse() ) {
168 $outputs[] = $outputInstance;
169 }
170 }
171 return $outputs;
172 }
173
182 public function logData() {
183 if ( $this->params['threshold'] > 0.0 ) {
184 // Note, this is also valid for CLI processes.
185 $timeElapsed = microtime( true ) - $_SERVER['REQUEST_TIME_FLOAT'];
186 if ( $timeElapsed <= $this->params['threshold'] ) {
187 return;
188 }
189 }
190
191 $outputs = [];
192 foreach ( $this->getOutputs() as $output ) {
193 if ( !$output->logsToOutput() ) {
194 $outputs[] = $output;
195 }
196 }
197
198 if ( $outputs ) {
199 $stats = $this->getFunctionStats();
200 foreach ( $outputs as $output ) {
201 $output->log( $stats );
202 }
203 }
204 }
205
211 public function logDataPageOutputOnly() {
212 if ( !$this->allowOutput ) {
213 return;
214 }
215
216 $outputs = [];
217 foreach ( $this->getOutputs() as $output ) {
218 if ( $output->logsToOutput() ) {
219 $outputs[] = $output;
220 }
221 }
222
223 if ( $outputs ) {
224 $stats = $this->getFunctionStats();
225 foreach ( $outputs as $output ) {
226 $output->log( $stats );
227 }
228 }
229 }
230
240 public function getContentType() {
241 if ( $this->allowOutput ) {
242 foreach ( headers_list() as $header ) {
243 if ( preg_match( '#^content-type: (\w+/\w+);?#i', $header, $m ) ) {
244 return $m[1];
245 }
246 }
247 }
248 return null;
249 }
250
256 public function setAllowOutput() {
257 $this->allowOutput = true;
258 }
259
268 public function getAllowOutput() {
269 wfDeprecated( __METHOD__, '1.41' );
270 return $this->allowOutput;
271 }
272
299 abstract public function getFunctionStats();
300
306 abstract public function getOutput();
307}
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:19
Stub profiler that does nothing.
Profiler base class that defines the interface and some shared functionality.
Definition Profiler.php:22
setAllowOutput()
Enable appending profiles to standard output.
Definition Profiler.php:256
setProfileID( $id)
Definition Profiler.php:103
scopedProfileOut(?SectionProfileCallback &$section=null)
Definition Profiler.php:131
getTransactionProfiler()
Definition Profiler.php:139
close()
Close opened profiling sections.
logData()
Log data to all the applicable backing stores.
Definition Profiler.php:182
TransactionProfiler $trxProfiler
Definition Profiler.php:28
__construct(array $params)
Definition Profiler.php:40
string false $profileID
Profiler ID for bucketing data.
Definition Profiler.php:24
logDataPageOutputOnly()
Log the data to the script/request output for all ProfilerOutput instances that do so.
Definition Profiler.php:211
getOutput()
Returns a profiling output to be stored in debug file.
static init(array $profilerConf)
Definition Profiler.php:53
static instance()
Definition Profiler.php:90
getContentType()
Get the Content-Type for deciding how to format appended profile output.
Definition Profiler.php:240
getFunctionStats()
Get the aggregated inclusive profiling data for each method.
getProfileID()
Definition Profiler.php:111
scopedProfileIn( $section)
Mark the start of a custom profiling frame (e.g.
getAllowOutput()
Whether appending profiles is allowed.
Definition Profiler.php:268
LoggerInterface $logger
Definition Profiler.php:30
array $params
All of the params passed from $wgProfiler.
Definition Profiler.php:26
Subclass ScopedCallback to avoid call_user_func_array(), which is slow.
Detect high-contention DB queries via profiling calls.