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 63dd7a3

Browse filesBrowse files
committed
bug #34673 Migrate server:log command away from WebServerBundle (jderusse)
This PR was merged into the 4.4 branch. Discussion ---------- Migrate server:log command away from WebServerBundle | Q | A | ------------- | --- | Branch? | 4.4 | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | #34657 | License | MIT | Doc PR | NA Duplicate ServerLogCommand in MonologBridge (currently in deprecated WebServerBundle) which does not have alternative in `symfony` bin. Targeted 4.4 in order to provide a migration path to users. Commits ------- 3bfa8db Migrate server:log command away from WebServerBundle
2 parents fd81bb8 + 3bfa8db commit 63dd7a3
Copy full SHA for 63dd7a3

File tree

7 files changed

+204
-2
lines changed
Filter options

7 files changed

+204
-2
lines changed

‎src/Symfony/Bridge/Monolog/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/Monolog/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ CHANGELOG
66

77
* The `RouteProcessor` class has been made final
88
* Added `ElasticsearchLogstashHandler`
9+
* Added the `ServerLogCommand`. Backport from the deprecated WebServerBundle
910

1011
4.3.0
1112
-----
+159Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
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\Bridge\Monolog\Command;
13+
14+
use Monolog\Formatter\FormatterInterface;
15+
use Monolog\Logger;
16+
use Symfony\Bridge\Monolog\Formatter\ConsoleFormatter;
17+
use Symfony\Bridge\Monolog\Handler\ConsoleHandler;
18+
use Symfony\Component\Console\Command\Command;
19+
use Symfony\Component\Console\Exception\LogicException;
20+
use Symfony\Component\Console\Exception\RuntimeException;
21+
use Symfony\Component\Console\Input\InputInterface;
22+
use Symfony\Component\Console\Input\InputOption;
23+
use Symfony\Component\Console\Output\OutputInterface;
24+
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
25+
26+
/**
27+
* @author Grégoire Pineau <lyrixx@lyrixx.info>
28+
*/
29+
class ServerLogCommand extends Command
30+
{
31+
private static $bgColor = ['black', 'blue', 'cyan', 'green', 'magenta', 'red', 'white', 'yellow'];
32+
33+
private $el;
34+
private $handler;
35+
36+
protected static $defaultName = 'server:log';
37+
38+
public function isEnabled()
39+
{
40+
if (!class_exists(ConsoleFormatter::class)) {
41+
return false;
42+
}
43+
44+
// based on a symfony/symfony package, it crashes due a missing FormatterInterface from monolog/monolog
45+
if (!interface_exists(FormatterInterface::class)) {
46+
return false;
47+
}
48+
49+
return parent::isEnabled();
50+
}
51+
52+
protected function configure()
53+
{
54+
if (!class_exists(ConsoleFormatter::class)) {
55+
return;
56+
}
57+
58+
$this
59+
->addOption('host', null, InputOption::VALUE_REQUIRED, 'The server host', '0.0.0.0:9911')
60+
->addOption('format', null, InputOption::VALUE_REQUIRED, 'The line format', ConsoleFormatter::SIMPLE_FORMAT)
61+
->addOption('date-format', null, InputOption::VALUE_REQUIRED, 'The date format', ConsoleFormatter::SIMPLE_DATE)
62+
->addOption('filter', null, InputOption::VALUE_REQUIRED, 'An expression to filter log. Example: "level > 200 or channel in [\'app\', \'doctrine\']"')
63+
->setDescription('Starts a log server that displays logs in real time')
64+
->setHelp(<<<'EOF'
65+
<info>%command.name%</info> starts a log server to display in real time the log
66+
messages generated by your application:
67+
68+
<info>php %command.full_name%</info>
69+
70+
To get the information as a machine readable format, use the
71+
<comment>--filter</> option:
72+
73+
<info>php %command.full_name% --filter=port</info>
74+
EOF
75+
)
76+
;
77+
}
78+
79+
protected function execute(InputInterface $input, OutputInterface $output)
80+
{
81+
$filter = $input->getOption('filter');
82+
if ($filter) {
83+
if (!class_exists(ExpressionLanguage::class)) {
84+
throw new LogicException('Package "symfony/expression-language" is required to use the "filter" option.');
85+
}
86+
$this->el = new ExpressionLanguage();
87+
}
88+
89+
$this->handler = new ConsoleHandler($output, true, [
90+
OutputInterface::VERBOSITY_NORMAL => Logger::DEBUG,
91+
]);
92+
93+
$this->handler->setFormatter(new ConsoleFormatter([
94+
'format' => str_replace('\n', "\n", $input->getOption('format')),
95+
'date_format' => $input->getOption('date-format'),
96+
'colors' => $output->isDecorated(),
97+
'multiline' => OutputInterface::VERBOSITY_DEBUG <= $output->getVerbosity(),
98+
]));
99+
100+
if (false === strpos($host = $input->getOption('host'), '://')) {
101+
$host = 'tcp://'.$host;
102+
}
103+
104+
if (!$socket = stream_socket_server($host, $errno, $errstr)) {
105+
throw new RuntimeException(sprintf('Server start failed on "%s": %s %s.', $host, $errstr, $errno));
106+
}
107+
108+
foreach ($this->getLogs($socket) as $clientId => $message) {
109+
$record = unserialize(base64_decode($message));
110+
111+
// Impossible to decode the message, give up.
112+
if (false === $record) {
113+
continue;
114+
}
115+
116+
if ($filter && !$this->el->evaluate($filter, $record)) {
117+
continue;
118+
}
119+
120+
$this->displayLog($output, $clientId, $record);
121+
}
122+
123+
return 0;
124+
}
125+
126+
private function getLogs($socket): iterable
127+
{
128+
$sockets = [(int) $socket => $socket];
129+
$write = [];
130+
131+
while (true) {
132+
$read = $sockets;
133+
stream_select($read, $write, $write, null);
134+
135+
foreach ($read as $stream) {
136+
if ($socket === $stream) {
137+
$stream = stream_socket_accept($socket);
138+
$sockets[(int) $stream] = $stream;
139+
} elseif (feof($stream)) {
140+
unset($sockets[(int) $stream]);
141+
fclose($stream);
142+
} else {
143+
yield (int) $stream => fgets($stream);
144+
}
145+
}
146+
}
147+
}
148+
149+
private function displayLog(OutputInterface $output, int $clientId, array $record)
150+
{
151+
if (isset($record['log_id'])) {
152+
$clientId = unpack('H*', $record['log_id'])[1];
153+
}
154+
$logBlock = sprintf('<bg=%s> </>', self::$bgColor[$clientId % 8]);
155+
$output->write($logBlock);
156+
157+
$this->handler->handle($record);
158+
}
159+
}

‎src/Symfony/Bundle/DebugBundle/DebugBundle.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/DebugBundle/DebugBundle.php
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Bundle\DebugBundle;
1313

1414
use Symfony\Bundle\DebugBundle\DependencyInjection\Compiler\DumpDataCollectorPass;
15+
use Symfony\Bundle\DebugBundle\DependencyInjection\Compiler\RemoveWebServerBundleLoggerPass;
1516
use Symfony\Component\Console\Application;
1617
use Symfony\Component\DependencyInjection\ContainerBuilder;
1718
use Symfony\Component\HttpKernel\Bundle\Bundle;
@@ -52,6 +53,7 @@ public function build(ContainerBuilder $container)
5253
parent::build($container);
5354

5455
$container->addCompilerPass(new DumpDataCollectorPass());
56+
$container->addCompilerPass(new RemoveWebServerBundleLoggerPass());
5557
}
5658

5759
public function registerCommands(Application $application)
+31Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
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\DebugBundle\DependencyInjection\Compiler;
13+
14+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
15+
use Symfony\Component\DependencyInjection\ContainerBuilder;
16+
17+
/**
18+
* @author Jérémy Derussé <jeremy@derusse.com>
19+
*/
20+
class RemoveWebServerBundleLoggerPass implements CompilerPassInterface
21+
{
22+
/**
23+
* {@inheritdoc}
24+
*/
25+
public function process(ContainerBuilder $container)
26+
{
27+
if ($container->hasDefinition('web_server.command.server_log') && $container->hasDefinition('monolog.command.server_log')) {
28+
$container->removeDefinition('web_server.command.server_log');
29+
}
30+
}
31+
}

‎src/Symfony/Bundle/DebugBundle/DependencyInjection/DebugExtension.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/DebugBundle/DependencyInjection/DebugExtension.php
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Bundle\DebugBundle\DependencyInjection;
1313

14+
use Symfony\Bridge\Monolog\Command\ServerLogCommand;
1415
use Symfony\Bundle\DebugBundle\Command\ServerDumpPlaceholderCommand;
1516
use Symfony\Component\Config\FileLocator;
1617
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -90,6 +91,10 @@ public function load(array $configs, ContainerBuilder $container)
9091
]])
9192
;
9293
}
94+
95+
if (!class_exists(ServerLogCommand::class)) {
96+
$container->removeDefinition('monolog.command.server_log');
97+
}
9398
}
9499

95100
/**

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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/DebugBundle/Resources/config/services.xml
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,5 +107,9 @@
107107
</argument>
108108
<tag name="console.command" command="server:dump" />
109109
</service>
110+
111+
<service id="monolog.command.server_log" class="Symfony\Bridge\Monolog\Command\ServerLogCommand">
112+
<tag name="console.command" command="server:log" />
113+
</service>
110114
</services>
111115
</container>

‎src/Symfony/Bundle/WebServerBundle/Command/ServerLogCommand.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/WebServerBundle/Command/ServerLogCommand.php
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
/**
2727
* @author Grégoire Pineau <lyrixx@lyrixx.info>
2828
*
29-
* @deprecated since Symfony 4.4, to be removed in 5.0; the new Symfony local server has more features, you can use it instead.
29+
* @deprecated since Symfony 4.4, to be removed in 5.0; use ServerLogCommand from symfony/monolog-bridge instead
3030
*/
3131
class ServerLogCommand extends Command
3232
{
@@ -80,7 +80,7 @@ protected function configure()
8080

8181
protected function execute(InputInterface $input, OutputInterface $output)
8282
{
83-
@trigger_error('Using the WebserverBundle is deprecated since Symfony 4.4. The new Symfony local server has more features, you can use it instead.', E_USER_DEPRECATED);
83+
@trigger_error('Using the WebserverBundle is deprecated since Symfony 4.4. Use the DebugBundle combined with MonologBridge instead.', E_USER_DEPRECATED);
8484

8585
$filter = $input->getOption('filter');
8686
if ($filter) {

0 commit comments

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