From 9e0b5ef728dd4df8004f83c3be37e25db4dfb7f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Romey?= Date: Wed, 21 May 2025 19:04:19 +0200 Subject: [PATCH 1/4] [WebProfilerBundle] display profiler url in logs --- .../EventListener/ProfilerLinkLogListener.php | 60 ++++++++ .../Resources/config/profiler.php | 10 ++ .../ProfilerLinkLogListenerTest.php | 142 ++++++++++++++++++ 3 files changed, 212 insertions(+) create mode 100644 src/Symfony/Bundle/WebProfilerBundle/EventListener/ProfilerLinkLogListener.php create mode 100644 src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/ProfilerLinkLogListenerTest.php diff --git a/src/Symfony/Bundle/WebProfilerBundle/EventListener/ProfilerLinkLogListener.php b/src/Symfony/Bundle/WebProfilerBundle/EventListener/ProfilerLinkLogListener.php new file mode 100644 index 0000000000000..2d5a6066ef187 --- /dev/null +++ b/src/Symfony/Bundle/WebProfilerBundle/EventListener/ProfilerLinkLogListener.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\WebProfilerBundle\EventListener; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpKernel\Event\ResponseEvent; +use Symfony\Component\HttpKernel\KernelEvents; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; +use Psr\Log\LoggerInterface; + +/** + * @author Jérémy Romey jeremyFreeAgent + */ +class ProfilerLinkLogListener implements EventSubscriberInterface +{ + public function __construct( + protected ?LoggerInterface $logger = null, + private ?UrlGeneratorInterface $urlGenerator = null, + ) { + } + + public function onKernelResponse(ResponseEvent $event): void + { + if (null === $this->logger) { + return; + } + if (null === $this->urlGenerator) { + return; + } + + $response = $event->getResponse(); + $request = $event->getRequest(); + + if (!$event->isMainRequest()) { + return; + } + + if (false === $response->headers->has('X-Debug-Token')) { + return; + } + + $this->logger->debug(\sprintf('See profiler at %s', $this->urlGenerator->generate('_profiler', ['token' => $response->headers->get('X-Debug-Token')], UrlGeneratorInterface::ABSOLUTE_URL))); + } + + public static function getSubscribedEvents(): array + { + return [ + KernelEvents::RESPONSE => ['onKernelResponse', -2048], + ]; + } +} diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/config/profiler.php b/src/Symfony/Bundle/WebProfilerBundle/Resources/config/profiler.php index edb464158045f..6079803e4232e 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/config/profiler.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/config/profiler.php @@ -16,6 +16,7 @@ use Symfony\Bundle\WebProfilerBundle\Controller\RouterController; use Symfony\Bundle\WebProfilerBundle\Csp\ContentSecurityPolicyHandler; use Symfony\Bundle\WebProfilerBundle\Csp\NonceGenerator; +use Symfony\Bundle\WebProfilerBundle\EventListener\ProfilerLinkLogListener; use Symfony\Bundle\WebProfilerBundle\Profiler\CodeExtension; use Symfony\Bundle\WebProfilerBundle\Twig\WebProfilerExtension; use Symfony\Component\ErrorHandler\ErrorRenderer\FileLinkFormatter; @@ -84,5 +85,14 @@ ->set('twig.extension.code', CodeExtension::class) ->args([service('debug.file_link_formatter'), param('kernel.project_dir'), param('kernel.charset')]) ->tag('twig.extension') + + ->set('web_profiler.profiler_link_log_listener', ProfilerLinkLogListener::class) + ->args([ + service('logger')->nullOnInvalid(), + service('router')->ignoreOnInvalid(), + ]) + + ->tag('monolog.logger', ['channel' => 'profiler']) + ->tag('kernel.event_subscriber') ; }; diff --git a/src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/ProfilerLinkLogListenerTest.php b/src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/ProfilerLinkLogListenerTest.php new file mode 100644 index 0000000000000..3cb47fce5c1f6 --- /dev/null +++ b/src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/ProfilerLinkLogListenerTest.php @@ -0,0 +1,142 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\WebProfilerBundle\Tests\EventListener; + +use PHPUnit\Framework\TestCase; +use Symfony\Bundle\WebProfilerBundle\EventListener\ProfilerLinkLogListener; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Event\ResponseEvent; +use Symfony\Component\HttpKernel\HttpKernelInterface; +use Symfony\Component\HttpKernel\Kernel; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; +use Psr\Log\LoggerInterface; + +/** + * @author Jérémy Romey jeremyFreeAgent + */ +class ProfilerLinkLogListenerTest extends TestCase +{ + public function testProfilerLinkLog() + { + $response = new Response('I love Symfony', 200); + $response->headers->set('Location', 'https://example.com/'); + $response->headers->set('X-Debug-Token', '04bb3f'); + + $event = new ResponseEvent($this->createMock(Kernel::class), new Request(), HttpKernelInterface::MAIN_REQUEST, $response); + + $logger = $this->createMock(LoggerInterface::class); + $logger + ->expects($this->once()) + ->method('debug') + ->with('See profiler at http://mydomain.com/_profiler/04bb3f') + ; + + $urlGenerator = $this->createMock(UrlGeneratorInterface::class); + $urlGenerator + ->expects($this->once()) + ->method('generate') + ->with('_profiler', ['token' => '04bb3f'], UrlGeneratorInterface::ABSOLUTE_URL) + ->willReturn('http://mydomain.com/_profiler/04bb3f') + ; + + $listener = new ProfilerLinkLogListener($logger, $urlGenerator); + $listener->onKernelResponse($event); + } + + public function testProfilerLinkLogShouldNotLogWhenNoLogger() + { + $response = new Response('I love Symfony', 200); + $response->headers->set('Location', 'https://example.com/'); + $response->headers->set('X-Debug-Token', '04bb3f'); + + $event = new ResponseEvent($this->createMock(Kernel::class), new Request(), HttpKernelInterface::MAIN_REQUEST, $response); + + $logger = null; + + $urlGenerator = $this->createMock(UrlGeneratorInterface::class); + $urlGenerator + ->expects($this->never()) + ->method('generate') + ; + + $listener = new ProfilerLinkLogListener($logger, $urlGenerator); + $listener->onKernelResponse($event); + } + + public function testProfilerLinkLogShouldNotLogWhenNoUrlGenerator() + { + $response = new Response('I love Symfony', 200); + $response->headers->set('Location', 'https://example.com/'); + $response->headers->set('X-Debug-Token', '04bb3f'); + + $event = new ResponseEvent($this->createMock(Kernel::class), new Request(), HttpKernelInterface::MAIN_REQUEST, $response); + + $logger = $this->createMock(LoggerInterface::class); + $logger + ->expects($this->never()) + ->method('debug') + ; + + $urlGenerator = null; + + $listener = new ProfilerLinkLogListener($logger, $urlGenerator); + $listener->onKernelResponse($event); + } + + public function testProfilerLinkLogShouldNotLogWhenNotMainRequest() + { + $response = new Response('I love Symfony', 200); + $response->headers->set('Location', 'https://example.com/'); + $response->headers->set('X-Debug-Token', '04bb3f'); + + $event = new ResponseEvent($this->createMock(Kernel::class), new Request(), HttpKernelInterface::SUB_REQUEST, $response); + + $logger = $this->createMock(LoggerInterface::class); + $logger + ->expects($this->never()) + ->method('debug') + ; + + $urlGenerator = $this->createMock(UrlGeneratorInterface::class); + $urlGenerator + ->expects($this->never()) + ->method('generate') + ; + + $listener = new ProfilerLinkLogListener($logger, $urlGenerator); + $listener->onKernelResponse($event); + } + + public function testProfilerLinkLogShouldNotLogWhenNoToken() + { + $response = new Response('I love Symfony', 200); + $response->headers->set('Location', 'https://example.com/'); + + $event = new ResponseEvent($this->createMock(Kernel::class), new Request(), HttpKernelInterface::MAIN_REQUEST, $response); + + $logger = $this->createMock(LoggerInterface::class); + $logger + ->expects($this->never()) + ->method('debug') + ; + + $urlGenerator = $this->createMock(UrlGeneratorInterface::class); + $urlGenerator + ->expects($this->never()) + ->method('generate') + ; + + $listener = new ProfilerLinkLogListener($logger, $urlGenerator); + $listener->onKernelResponse($event); + } +} From 22559d0e1371cb7288bc64c605a84034b3e30c83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Romey?= Date: Wed, 21 May 2025 19:11:12 +0200 Subject: [PATCH 2/4] add changelog entry --- src/Symfony/Bundle/WebProfilerBundle/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Symfony/Bundle/WebProfilerBundle/CHANGELOG.md b/src/Symfony/Bundle/WebProfilerBundle/CHANGELOG.md index 5e5e8db36e233..adfe0a440737f 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/WebProfilerBundle/CHANGELOG.md @@ -4,6 +4,8 @@ CHANGELOG 7.3 --- + * Display profiler URL in logs + * Add `profiler.php` and `wdt.php` routing configuration files (use them instead of their XML equivalent) Before: From bd46580aed2b2e55d5f6eedeb4d7a1598ca44ecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Romey?= Date: Wed, 21 May 2025 20:05:03 +0200 Subject: [PATCH 3/4] use final and private attributes --- .../EventListener/ProfilerLinkLogListener.php | 4 ++-- .../Tests/EventListener/ProfilerLinkLogListenerTest.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/EventListener/ProfilerLinkLogListener.php b/src/Symfony/Bundle/WebProfilerBundle/EventListener/ProfilerLinkLogListener.php index 2d5a6066ef187..05007fe11f927 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/EventListener/ProfilerLinkLogListener.php +++ b/src/Symfony/Bundle/WebProfilerBundle/EventListener/ProfilerLinkLogListener.php @@ -20,10 +20,10 @@ /** * @author Jérémy Romey jeremyFreeAgent */ -class ProfilerLinkLogListener implements EventSubscriberInterface +final class ProfilerLinkLogListener implements EventSubscriberInterface { public function __construct( - protected ?LoggerInterface $logger = null, + private ?LoggerInterface $logger = null, private ?UrlGeneratorInterface $urlGenerator = null, ) { } diff --git a/src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/ProfilerLinkLogListenerTest.php b/src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/ProfilerLinkLogListenerTest.php index 3cb47fce5c1f6..e8342b7109b54 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/ProfilerLinkLogListenerTest.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/ProfilerLinkLogListenerTest.php @@ -24,7 +24,7 @@ /** * @author Jérémy Romey jeremyFreeAgent */ -class ProfilerLinkLogListenerTest extends TestCase +final class ProfilerLinkLogListenerTest extends TestCase { public function testProfilerLinkLog() { From 6143514547fa19c9dab99f57fd2c31b53b8719f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Romey?= Date: Wed, 21 May 2025 20:05:33 +0200 Subject: [PATCH 4/4] Update src/Symfony/Bundle/WebProfilerBundle/EventListener/ProfilerLinkLogListener.php Co-authored-by: Christophe Coevoet --- .../WebProfilerBundle/EventListener/ProfilerLinkLogListener.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/EventListener/ProfilerLinkLogListener.php b/src/Symfony/Bundle/WebProfilerBundle/EventListener/ProfilerLinkLogListener.php index 05007fe11f927..b18a61c781a3d 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/EventListener/ProfilerLinkLogListener.php +++ b/src/Symfony/Bundle/WebProfilerBundle/EventListener/ProfilerLinkLogListener.php @@ -44,7 +44,7 @@ public function onKernelResponse(ResponseEvent $event): void return; } - if (false === $response->headers->has('X-Debug-Token')) { + if (!$response->headers->has('X-Debug-Token')) { return; } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy