Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 814bcac

Browse filesBrowse files
feature #47416 [Console][FrameworkBundle][HttpKernel][WebProfilerBundle] Enable profiling commands (HeahDude)
This PR was merged into the 6.4 branch. Discussion ---------- [Console][FrameworkBundle][HttpKernel][WebProfilerBundle] Enable profiling commands | Q | A | ------------- | --- | Branch? | 6.4 | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | Fix #45241 | License | MIT | Doc PR | ~ TLDR; I've shown a POC of this feature at the Symfony Live Paris last April to some of the core team members (ping `@nicolas`-grekas, `@stof`, `@lyrixx`, `@chalasr`, `@GromNaN`). I propose here a new work from scratch addressing the comments I already got and based on Javier's profiler redesign (#47148). Reviews should better be done by commits. Summary --------- This PR aims to leverage the profiler and its collectors by using a `VirtualRequestStack` to aggregate data on virtual requests. Such requests are obfuscated by default to avoid side effects. It can feel like a hack... or a pragmatic way to get, without much complexity, tons of useful feedback on what's going on during console execution, from basic info about the command, time/memory metrics, to every existing features already available in HTTP context: events, message dispatching, http requests, emails, serialization, validation, cache, database queries... and so on, all that just out of the box! Previous work -------------- There were some work to extract the Profiler logic in a dedicated component, that proved to require a lot of complexity and BC breaks in the API: * #10374 * #14809 (see #14809 (comment)) * #20502 Screenshots ------------ For now I've focused only on the functional parts. <details><summary>Search view</summary> <img width="1221" alt="Screenshot 2022-08-28 at 11 29 25 PM" src="https://user-images.githubusercontent.com/10107633/187095381-851f6be5-cf8c-4fec-aa7b-9f9f80bf8404.png"> </details> <details><summary>Command panel</summary> <img width="1210" alt="Screenshot 2022-08-28 at 11 30 54 PM" src="https://user-images.githubusercontent.com/10107633/187095971-de8f9b85-eeb4-48cf-aff7-fdac0c6f9264.png"> <img width="974" alt="Screenshot 2022-08-28 at 11 31 08 PM" src="https://user-images.githubusercontent.com/10107633/187095980-337f4373-ebe5-4de5-bfb4-3715be868274.png"> <img width="962" alt="Screenshot 2022-08-28 at 11 31 21 PM" src="https://user-images.githubusercontent.com/10107633/187096022-ab18f70a-704a-4c75-81a6-43ca5b66eb9a.png"> <img width="964" alt="Screenshot 2022-08-28 at 11 31 34 PM" src="https://user-images.githubusercontent.com/10107633/187096037-cc45805e-ba65-447f-bca6-2d2ea38239b8.png"> If the command is signal-able the following panel will be available: <img width="961" alt="Screenshot 2022-08-28 at 11 31 46 PM" src="https://user-images.githubusercontent.com/10107633/187096084-2f6a39be-a780-411b-9000-b9ae3407e82b.png"> If sub commands are run using `$this->getApplication()->run()` sub profiles will be shown as for requests: <img width="696" alt="Screenshot 2022-08-28 at 11 31 56 PM" src="https://user-images.githubusercontent.com/10107633/187096105-bb7e4a84-42bc-47ed-9f58-527a771c48cc.png"> </details> The server tab is the same as in the request panel. <details><summary>Performance panel</summary> <img width="977" alt="Screenshot 2022-08-28 at 11 32 23 PM" src="https://user-images.githubusercontent.com/10107633/187096138-3ff3f347-61c7-4ade-8c73-b48d5b504c04.png"> <img width="969" alt="Screenshot 2022-08-28 at 11 32 32 PM" src="https://user-images.githubusercontent.com/10107633/187096168-35be4773-4941-4e5e-8dd4-f6cc009e5d48.png"> </details> <details> <summary>Failing command</summary> The exception panel is shown by default as for requests: <img width="1217" alt="Screenshot 2022-08-28 at 11 33 42 PM" src="https://user-images.githubusercontent.com/10107633/187096210-7b206c72-c2e4-4eb3-9978-916cd3dd6cd6.png"> </details> <details> <summary>Sub command</summary> <img width="1217" alt="Screenshot 2022-08-28 at 11 33 19 PM" src="https://user-images.githubusercontent.com/10107633/187096188-a090fb91-b7b8-4f98-a1d7-99b3605bf48b.png"> </details> <details> <summary>Profile token when verbose</summary> (clickable links with compatible terminals) <img width="534" alt="Screenshot 2022-08-28 at 11 26 51 PM" src="https://user-images.githubusercontent.com/10107633/187096349-8f7619b2-feb4-427c-a315-f4a844536316.png"> </details> <details> <summary>Command interrupted by signal</summary> <img width="1246" alt="Screenshot 2022-10-22 at 4 16 37 PM" src="https://user-images.githubusercontent.com/10107633/197344164-50d72a25-a6e7-4e77-ad87-2d5f54b29b93.png"> </details> Opt-in profiling --------------- Use the new global option `--profile` (in debug only) to profile a command. Future scopes -------------- * When I've discussed the limitation of profiling long running processes such as `messenger:consume` with `@GromNaN` (one of the reasons why I've added an `excludes` option), he told that it would be nice it we could find a way to profile consumers as well. So I've added ~an abstract `VirtualRequest`~ a `_virtual_type` request attribute and a `virtualType` property to profiles, that will allow to create a `MessengerWorkerRequest` and a new type of profile with ease in a follow-up PR if the current implementation is accepted. * We could add some dedicated casters for input and output in the `VarDumper` component (/cc `@nicolas`-grekas) * It could be interesting to decorate and collect traces from some helpers (i.e. when running processes) * ~Add a global option in debug to enable/disable the profiler on the fly when running commands (e.g. a negatable `--profile` flag)~ **[update] implemented in current scope in replacement of semantic config.** * Extract profiling to a new component. Limitations ----------- * ~No sub profiles are created when using `$this->getApplication()->find(...)->run()` because events (needed by the profiler to hook into) are dispatched from `Application::run()`, not from `Command::run()`.~ **[update] The docs has been updated in symfony/symfony-docs#18741 * ~No profiles are created when killing the command process (i.e. using `ctrl-C`, should we add a handler to some signals to force saving profiles?~ **[update] I've added support for this.** * ~Signals as int may not be as useful as they could in the profiler pages, does it worth trying to add a label to some (knowing that some signals can have different constants (labels) with the same int value)?~ **[update] done thanks to #50663 * ~Long running processes should be excluded via configuration to avoid memory leaks~ **[update] profiling is now opt-in using the `--profile` option.** * Profiling `messenger:consume` does not work since the kernel is reset after handling a message. __________________ TODO ------ * [x] I've left some todos inside the code for reviewers to share they thought before I try going further * [x] Add a few tests * [ ] Get help for the UI (new top nav, ~svg for the command panel~) /cc `@javiereguiluz` * ~PR on `symfony/recipes` to add the new `framework.profiler.cli` node~ Commits ------- 82914ba [Console][FrameworkBundle][HttpKernel][WebProfilerBundle] Enable profiling commands
2 parents 9233ea8 + 82914ba commit 814bcac
Copy full SHA for 814bcac

34 files changed

+1570
-159
lines changed

‎src/Symfony/Bundle/DebugBundle/Resources/config/services.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/DebugBundle/Resources/config/services.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
service('debug.stopwatch')->ignoreOnInvalid(),
5151
service('debug.file_link_formatter')->ignoreOnInvalid(),
5252
param('kernel.charset'),
53-
service('request_stack'),
53+
service('.virtual_request_stack'),
5454
null, // var_dumper.cli_dumper or var_dumper.server_connection when debug.dump_destination is set
5555
])
5656
->tag('data_collector', [

‎src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ CHANGELOG
3333
* Add parameters deprecations to the output of `debug:container` command
3434
* Change `framework.asset_mapper.importmap_polyfill` from a URL to the name of an item in the importmap
3535
* Provide `$buildDir` when running `CacheWarmer` to build read-only resources
36+
* Add the global `--profile` option to the console to enable profiling commands
3637

3738
6.3
3839
---

‎src/Symfony/Bundle/FrameworkBundle/Console/Application.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Console/Application.php
+35-3Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
use Symfony\Component\Console\Application as BaseApplication;
1515
use Symfony\Component\Console\Command\Command;
1616
use Symfony\Component\Console\Command\ListCommand;
17+
use Symfony\Component\Console\Command\TraceableCommand;
18+
use Symfony\Component\Console\Debug\CliRequest;
1719
use Symfony\Component\Console\Input\InputInterface;
1820
use Symfony\Component\Console\Input\InputOption;
1921
use Symfony\Component\Console\Output\ConsoleOutputInterface;
@@ -42,6 +44,7 @@ public function __construct(KernelInterface $kernel)
4244
$inputDefinition = $this->getDefinition();
4345
$inputDefinition->addOption(new InputOption('--env', '-e', InputOption::VALUE_REQUIRED, 'The Environment name.', $kernel->getEnvironment()));
4446
$inputDefinition->addOption(new InputOption('--no-debug', null, InputOption::VALUE_NONE, 'Switch off debug mode.'));
47+
$inputDefinition->addOption(new InputOption('--profile', null, InputOption::VALUE_NONE, 'Enables profiling (requires debug).'));
4548
}
4649

4750
/**
@@ -79,18 +82,47 @@ public function doRun(InputInterface $input, OutputInterface $output): int
7982

8083
protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output): int
8184
{
85+
$requestStack = null;
86+
$renderRegistrationErrors = true;
87+
8288
if (!$command instanceof ListCommand) {
8389
if ($this->registrationErrors) {
8490
$this->renderRegistrationErrors($input, $output);
8591
$this->registrationErrors = [];
92+
$renderRegistrationErrors = false;
8693
}
94+
}
95+
96+
if ($input->hasParameterOption('--profile')) {
97+
$container = $this->kernel->getContainer();
8798

88-
return parent::doRunCommand($command, $input, $output);
99+
if (!$this->kernel->isDebug()) {
100+
if ($output instanceof ConsoleOutputInterface) {
101+
$output = $output->getErrorOutput();
102+
}
103+
104+
(new SymfonyStyle($input, $output))->warning('Debug mode should be enabled when the "--profile" option is used.');
105+
} elseif (!$container->has('debug.stopwatch')) {
106+
if ($output instanceof ConsoleOutputInterface) {
107+
$output = $output->getErrorOutput();
108+
}
109+
110+
(new SymfonyStyle($input, $output))->warning('The "--profile" option needs the Stopwatch component. Try running "composer require symfony/stopwatch".');
111+
} else {
112+
$command = new TraceableCommand($command, $container->get('debug.stopwatch'));
113+
114+
$requestStack = $container->get('.virtual_request_stack');
115+
$requestStack->push(new CliRequest($command));
116+
}
89117
}
90118

91-
$returnCode = parent::doRunCommand($command, $input, $output);
119+
try {
120+
$returnCode = parent::doRunCommand($command, $input, $output);
121+
} finally {
122+
$requestStack?->pop();
123+
}
92124

93-
if ($this->registrationErrors) {
125+
if ($renderRegistrationErrors && $this->registrationErrors) {
94126
$this->renderRegistrationErrors($input, $output);
95127
$this->registrationErrors = [];
96128
}

‎src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+9-3Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
use Symfony\Component\Config\ResourceCheckerInterface;
5151
use Symfony\Component\Console\Application;
5252
use Symfony\Component\Console\Command\Command;
53+
use Symfony\Component\Console\Debug\CliRequest;
5354
use Symfony\Component\Console\Messenger\RunCommandMessageHandler;
5455
use Symfony\Component\DependencyInjection\Alias;
5556
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
@@ -912,6 +913,10 @@ private function registerProfilerConfiguration(array $config, ContainerBuilder $
912913

913914
$container->getDefinition('profiler_listener')
914915
->addArgument($config['collect_parameter']);
916+
917+
if (!$container->getParameter('kernel.debug') || !class_exists(CliRequest::class) || !$container->has('debug.stopwatch')) {
918+
$container->removeDefinition('console_profiler_listener');
919+
}
915920
}
916921

917922
private function registerWorkflowConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader): void
@@ -1134,15 +1139,16 @@ private function registerDebugConfiguration(array $config, ContainerBuilder $con
11341139
{
11351140
$loader->load('debug_prod.php');
11361141

1142+
$debug = $container->getParameter('kernel.debug');
1143+
11371144
if (class_exists(Stopwatch::class)) {
11381145
$container->register('debug.stopwatch', Stopwatch::class)
11391146
->addArgument(true)
1147+
->setPublic($debug)
11401148
->addTag('kernel.reset', ['method' => 'reset']);
11411149
$container->setAlias(Stopwatch::class, new Alias('debug.stopwatch', false));
11421150
}
11431151

1144-
$debug = $container->getParameter('kernel.debug');
1145-
11461152
if ($debug && !$container->hasParameter('debug.container.dump')) {
11471153
$container->setParameter('debug.container.dump', '%kernel.build_dir%/%kernel.container_class%.xml');
11481154
}
@@ -1165,7 +1171,7 @@ private function registerDebugConfiguration(array $config, ContainerBuilder $con
11651171

11661172
if ($debug && class_exists(DebugProcessor::class)) {
11671173
$definition = new Definition(DebugProcessor::class);
1168-
$definition->addArgument(new Reference('request_stack'));
1174+
$definition->addArgument(new Reference('.virtual_request_stack'));
11691175
$definition->addTag('kernel.reset', ['method' => 'reset']);
11701176
$container->setDefinition('debug.log_processor', $definition);
11711177

+144Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\EventListener;
13+
14+
use Symfony\Component\Console\ConsoleEvents;
15+
use Symfony\Component\Console\Debug\CliRequest;
16+
use Symfony\Component\Console\Event\ConsoleCommandEvent;
17+
use Symfony\Component\Console\Event\ConsoleErrorEvent;
18+
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
19+
use Symfony\Component\Console\Output\ConsoleOutputInterface;
20+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
21+
use Symfony\Component\HttpFoundation\Request;
22+
use Symfony\Component\HttpFoundation\RequestStack;
23+
use Symfony\Component\HttpKernel\Profiler\Profile;
24+
use Symfony\Component\HttpKernel\Profiler\Profiler;
25+
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
26+
use Symfony\Component\Stopwatch\Stopwatch;
27+
28+
/**
29+
* @internal
30+
*
31+
* @author Jules Pietri <jules@heahprod.com>
32+
*/
33+
final class ConsoleProfilerListener implements EventSubscriberInterface
34+
{
35+
private ?\Throwable $error = null;
36+
/** @var \SplObjectStorage<Request, Profile> */
37+
private \SplObjectStorage $profiles;
38+
/** @var \SplObjectStorage<Request, ?Request> */
39+
private \SplObjectStorage $parents;
40+
41+
public function __construct(
42+
private readonly Profiler $profiler,
43+
private readonly RequestStack $requestStack,
44+
private readonly Stopwatch $stopwatch,
45+
private readonly UrlGeneratorInterface $urlGenerator,
46+
) {
47+
$this->profiles = new \SplObjectStorage();
48+
$this->parents = new \SplObjectStorage();
49+
}
50+
51+
public static function getSubscribedEvents(): array
52+
{
53+
return [
54+
ConsoleEvents::COMMAND => ['initialize', 4096],
55+
ConsoleEvents::ERROR => ['catch', -2048],
56+
ConsoleEvents::TERMINATE => ['profile', -4096],
57+
];
58+
}
59+
60+
public function initialize(ConsoleCommandEvent $event): void
61+
{
62+
if (!$event->getInput()->getOption('profile')) {
63+
$this->profiler->disable();
64+
65+
return;
66+
}
67+
68+
$request = $this->requestStack->getCurrentRequest();
69+
70+
if (!$request instanceof CliRequest || $request->command !== $event->getCommand()) {
71+
return;
72+
}
73+
74+
$request->attributes->set('_stopwatch_token', substr(hash('sha256', uniqid(mt_rand(), true)), 0, 6));
75+
$this->stopwatch->openSection();
76+
}
77+
78+
public function catch(ConsoleErrorEvent $event): void
79+
{
80+
$this->error = $event->getError();
81+
}
82+
83+
public function profile(ConsoleTerminateEvent $event): void
84+
{
85+
if (!$this->profiler->isEnabled()) {
86+
return;
87+
}
88+
89+
$request = $this->requestStack->getCurrentRequest();
90+
91+
if (!$request instanceof CliRequest || $request->command !== $event->getCommand()) {
92+
return;
93+
}
94+
95+
if (null !== $sectionId = $request->attributes->get('_stopwatch_token')) {
96+
// we must close the section before saving the profile to allow late collect
97+
try {
98+
$this->stopwatch->stopSection($sectionId);
99+
} catch (\LogicException) {
100+
// noop
101+
}
102+
}
103+
104+
$request->command->exitCode = $event->getExitCode();
105+
$request->command->interruptedBySignal = $event->getInterruptingSignal();
106+
107+
$profile = $this->profiler->collect($request, $request->getResponse(), $this->error);
108+
$this->error = null;
109+
$this->profiles[$request] = $profile;
110+
111+
if ($this->parents[$request] = $this->requestStack->getParentRequest()) {
112+
// do not save on sub commands
113+
return;
114+
}
115+
116+
// attach children to parents
117+
foreach ($this->profiles as $request) {
118+
if (null !== $parentRequest = $this->parents[$request]) {
119+
if (isset($this->profiles[$parentRequest])) {
120+
$this->profiles[$parentRequest]->addChild($this->profiles[$request]);
121+
}
122+
}
123+
}
124+
125+
$output = $event->getOutput();
126+
$output = $output instanceof ConsoleOutputInterface && $output->isVerbose() ? $output->getErrorOutput() : null;
127+
128+
// save profiles
129+
foreach ($this->profiles as $r) {
130+
$p = $this->profiles[$r];
131+
$this->profiler->saveProfile($p);
132+
133+
$token = $p->getToken();
134+
$output?->writeln(sprintf(
135+
'See profile <href=%s>%s</>',
136+
$this->urlGenerator->generate('_profiler', ['token' => $token], UrlGeneratorInterface::ABSOLUTE_URL),
137+
$token
138+
));
139+
}
140+
141+
$this->profiles = new \SplObjectStorage();
142+
$this->parents = new \SplObjectStorage();
143+
}
144+
}

‎src/Symfony/Bundle/FrameworkBundle/Resources/config/collectors.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Resources/config/collectors.php
+7-3Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
1313

1414
use Symfony\Bundle\FrameworkBundle\DataCollector\RouterDataCollector;
15+
use Symfony\Component\Console\DataCollector\CommandDataCollector;
1516
use Symfony\Component\HttpKernel\DataCollector\AjaxDataCollector;
1617
use Symfony\Component\HttpKernel\DataCollector\ConfigDataCollector;
1718
use Symfony\Component\HttpKernel\DataCollector\EventDataCollector;
@@ -30,7 +31,7 @@
3031

3132
->set('data_collector.request', RequestDataCollector::class)
3233
->args([
33-
service('request_stack')->ignoreOnInvalid(),
34+
service('.virtual_request_stack')->ignoreOnInvalid(),
3435
])
3536
->tag('kernel.event_subscriber')
3637
->tag('data_collector', ['template' => '@WebProfiler/Collector/request.html.twig', 'id' => 'request', 'priority' => 335])
@@ -48,15 +49,15 @@
4849
->set('data_collector.events', EventDataCollector::class)
4950
->args([
5051
tagged_iterator('event_dispatcher.dispatcher', 'name'),
51-
service('request_stack')->ignoreOnInvalid(),
52+
service('.virtual_request_stack')->ignoreOnInvalid(),
5253
])
5354
->tag('data_collector', ['template' => '@WebProfiler/Collector/events.html.twig', 'id' => 'events', 'priority' => 290])
5455

5556
->set('data_collector.logger', LoggerDataCollector::class)
5657
->args([
5758
service('logger')->ignoreOnInvalid(),
5859
sprintf('%s/%s', param('kernel.build_dir'), param('kernel.container_class')),
59-
service('request_stack')->ignoreOnInvalid(),
60+
service('.virtual_request_stack')->ignoreOnInvalid(),
6061
])
6162
->tag('monolog.logger', ['channel' => 'profiler'])
6263
->tag('data_collector', ['template' => '@WebProfiler/Collector/logger.html.twig', 'id' => 'logger', 'priority' => 300])
@@ -74,5 +75,8 @@
7475
->set('data_collector.router', RouterDataCollector::class)
7576
->tag('kernel.event_listener', ['event' => KernelEvents::CONTROLLER, 'method' => 'onKernelController'])
7677
->tag('data_collector', ['template' => '@WebProfiler/Collector/router.html.twig', 'id' => 'router', 'priority' => 285])
78+
79+
->set('.data_collector.command', CommandDataCollector::class)
80+
->tag('data_collector', ['template' => '@WebProfiler/Collector/command.html.twig', 'id' => 'command', 'priority' => 335])
7781
;
7882
};

‎src/Symfony/Bundle/FrameworkBundle/Resources/config/debug.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Resources/config/debug.php
+6-1Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\HttpKernel\Controller\TraceableArgumentResolver;
1616
use Symfony\Component\HttpKernel\Controller\TraceableControllerResolver;
1717
use Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher;
18+
use Symfony\Component\HttpKernel\Debug\VirtualRequestStack;
1819

1920
return static function (ContainerConfigurator $container) {
2021
$container->services()
@@ -24,7 +25,7 @@
2425
service('debug.event_dispatcher.inner'),
2526
service('debug.stopwatch'),
2627
service('logger')->nullOnInvalid(),
27-
service('request_stack')->nullOnInvalid(),
28+
service('.virtual_request_stack')->nullOnInvalid(),
2829
])
2930
->tag('monolog.logger', ['channel' => 'event'])
3031
->tag('kernel.reset', ['method' => 'reset'])
@@ -46,5 +47,9 @@
4647
->set('argument_resolver.not_tagged_controller', NotTaggedControllerValueResolver::class)
4748
->args([abstract_arg('Controller argument, set in FrameworkExtension')])
4849
->tag('controller.argument_value_resolver', ['priority' => -200])
50+
51+
->set('.virtual_request_stack', VirtualRequestStack::class)
52+
->args([service('request_stack')])
53+
->public()
4954
;
5055
};

‎src/Symfony/Bundle/FrameworkBundle/Resources/config/profiling.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Resources/config/profiling.php
+10Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
1313

14+
use Symfony\Bundle\FrameworkBundle\EventListener\ConsoleProfilerListener;
1415
use Symfony\Component\HttpKernel\EventListener\ProfilerListener;
1516
use Symfony\Component\HttpKernel\Profiler\FileProfilerStorage;
1617
use Symfony\Component\HttpKernel\Profiler\Profiler;
@@ -35,5 +36,14 @@
3536
param('profiler_listener.only_main_requests'),
3637
])
3738
->tag('kernel.event_subscriber')
39+
40+
->set('console_profiler_listener', ConsoleProfilerListener::class)
41+
->args([
42+
service('profiler'),
43+
service('.virtual_request_stack'),
44+
service('debug.stopwatch'),
45+
service('router'),
46+
])
47+
->tag('kernel.event_subscriber')
3848
;
3949
};

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.