diff --git a/i18n/en.json b/i18n/en.json index c30a3a0..909b492 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -20,5 +20,6 @@ "speedscope-parser-report-link-text": "View", "speedscope-editpage-profile-preview-label": "Generate flamegraph", "speedscope-editpage-profile-preview-title": "Generate a speedscope flamegraph for the preview.", - "speedscope-editpage-profile-notice": "A speedscope profile for this preview can be viewed [$1 here]." + "speedscope-editpage-profile-notice": "A speedscope profile for this preview can be viewed [$1 here].", + "speedscope-profile-name-preview": "Preview of $1" } diff --git a/i18n/qqq.json b/i18n/qqq.json index dd285b5..8e597d0 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -20,5 +20,6 @@ "speedscope-parser-report-link-text": "Text of the link in the parser report that leads to the speedscope profile viewer.", "speedscope-editpage-profile-preview-label": "Label of the checkbox that can be ticked to generate a speedscope flamegraph for the preview.", "speedscope-editpage-profile-preview-title": "Title of the checkbox that can be ticked to generate a speedscope flamegraph for the preview.", - "speedscope-editpage-profile-notice": "Notice displayed when profiling a preview. $1 the URL for the profile viewer for the profile." + "speedscope-editpage-profile-notice": "Notice displayed when profiling a preview. $1 the URL for the profile viewer for the profile.", + "speedscope-profile-name-preview": "Name of profiles that were forced for previews through the preference.\n\nParameters:\n* $1 - The name of the page that's being previewed" } diff --git a/src/HookHandlers/ProfilePreviewsHooks.php b/src/HookHandlers/ProfilePreviewsHooks.php index 432a784..6344d61 100644 --- a/src/HookHandlers/ProfilePreviewsHooks.php +++ b/src/HookHandlers/ProfilePreviewsHooks.php @@ -88,6 +88,10 @@ public function onParserBeforeInternalParse( $parser, &$text, $stripState ): voi ); if ( !$this->profiler->getProfile() ) { $this->profiler->recordProfile( SpeedscopeProfile::CAUSE_FORCED_PREVIEW, $id ); + $this->profiler->getProfile()?->setName( $parser->msg( + 'speedscope-profile-name-preview', + (string)$parser->getPage(), + )->text() ); // @codeCoverageIgnoreStart if ( !defined( 'MW_PHPUNIT_TEST' ) ) { ProfileHooks::sendProfileHeader(); diff --git a/src/SpeedscopeLogger.php b/src/SpeedscopeLogger.php index 27ade4c..5d4a6a5 100644 --- a/src/SpeedscopeLogger.php +++ b/src/SpeedscopeLogger.php @@ -47,7 +47,7 @@ public function log( SpeedscopeProfile $profile ): StatusValue { } $requestUri = $_SERVER['REQUEST_URI'] ?? MW_ENTRY_POINT; - $data = $this->appendAdditionalData( $data, $requestUri ); + $data = $this->appendAdditionalData( $data, $profile->getName() ?? $requestUri ); $context = RequestContext::getMain(); $body = json_encode( [ @@ -92,11 +92,11 @@ public function log( SpeedscopeProfile $profile ): StatusValue { /** * Add some additional data to the profile. * @param array $data - * @param string $requestUri + * @param string $profileName * @return array */ - private function appendAdditionalData( array $data, string $requestUri ): array { - $data['profiles'][0]['name'] = $requestUri; + private function appendAdditionalData( array $data, string $profileName ): array { + $data['profiles'][0]['name'] = $profileName; if ( $this->options->get( SpeedscopeConfigNames::EXPOSE_CPU_INFO ) ) { $data['cpuinfo'] = file_get_contents( '/proc/stat' ); } diff --git a/src/SpeedscopeProfile.php b/src/SpeedscopeProfile.php index c9ccd5f..b15fbfa 100644 --- a/src/SpeedscopeProfile.php +++ b/src/SpeedscopeProfile.php @@ -24,8 +24,10 @@ class SpeedscopeProfile { private ?array $data = null; /** @see ParserOutput::getLimitReportJSData() */ private ?array $parserReport = null; - /** @var bool Whether we should store the parser output for the current request */ + /** Whether we should store the parser output for the current request */ private bool $storeParserReport = false; + /** The name of the profile. If null, the request URL will be used instead. */ + private ?string $name = null; /** * @param string $environment The environment of the request, e.g. `prod` or `dev` @@ -114,4 +116,18 @@ public function shouldStoreParserReport(): bool { return $this->storeParserReport; } + /** + * @return string|null The name of the profile, or null if none was set. + */ + public function getName(): ?string { + return $this->name; + } + + /** + * @param string|null $name The name of the profile, or null to use the request URL. + */ + public function setName( ?string $name ): void { + $this->name = $name; + } + } diff --git a/tests/phpunit/unit/ProfilePreviewsHooksUnitTest.php b/tests/phpunit/unit/ProfilePreviewsHooksUnitTest.php index 5a9dd4e..51296c3 100644 --- a/tests/phpunit/unit/ProfilePreviewsHooksUnitTest.php +++ b/tests/phpunit/unit/ProfilePreviewsHooksUnitTest.php @@ -8,6 +8,8 @@ use MediaWiki\Extension\Speedscope\Profiler\ISpeedscopeProfiler; use MediaWiki\Extension\Speedscope\SpeedscopeConfigNames; use MediaWiki\Extension\Speedscope\SpeedscopeProfile; +use MediaWiki\Message\Message; +use MediaWiki\Page\PageIdentityValue; use MediaWiki\Parser\Parser; use MediaWiki\Parser\ParserOptions; use MediaWiki\Parser\ParserOutput; @@ -77,7 +79,10 @@ public function testOnParserBeforeInternalParse_OptionDisabled() { public function testOnParserBeforeInternalParse_Success() { RequestContext::getMain()->getRequest()->setVal( 'wpProfilePreview', true ); - $parser = $this->createNoOpMock( Parser::class, [ 'getOptions', 'getOutput', 'getUserIdentity' ] ); + $parser = $this->createNoOpMock( + Parser::class, + [ 'getOptions', 'getOutput', 'getPage', 'getUserIdentity', 'msg' ] + ); $parserOptions = $this->createMock( ParserOptions::class ); $parserOptions->expects( $this->once() )->method( 'getRenderReason' )->willReturn( 'page-preview' ); $parser->method( 'getOptions' )->willReturn( $parserOptions ); @@ -93,7 +98,9 @@ public function testOnParserBeforeInternalParse_Success() { ->with( ProfilePreviewsHooks::EXTENSION_DATA_KEY, true ); $parser->expects( $this->atLeastOnce() )->method( 'getOutput' )->willReturn( $parserOutput ); $user = $this->createNoOpMock( User::class ); + $parser->method( 'getPage' )->willReturn( PageIdentityValue::localReference( 0, __METHOD__ ) ); $parser->expects( $this->atLeastOnce() )->method( 'getUserIdentity' )->willReturn( $user ); + $parser->method( 'msg' )->willReturn( $this->createMock( Message::class ) ); $text = ''; $createdProfile = false;