PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 5.12.1
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v5.12.1
5.12.1 5.12.0 5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / vendor / prefixed / symfony / monolog-bridge / Command / ServerLogCommand.php
matomo / app / vendor / prefixed / symfony / monolog-bridge / Command Last commit date
ServerLogCommand.php 2 months ago
ServerLogCommand.php
126 lines
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 namespace Matomo\Dependencies\Symfony\Bridge\Monolog\Command;
12
13 use Matomo\Dependencies\Monolog\Formatter\FormatterInterface;
14 use Matomo\Dependencies\Monolog\Logger;
15 use Matomo\Dependencies\Symfony\Bridge\Monolog\Formatter\ConsoleFormatter;
16 use Matomo\Dependencies\Symfony\Bridge\Monolog\Handler\ConsoleHandler;
17 use Matomo\Dependencies\Symfony\Component\Console\Command\Command;
18 use Matomo\Dependencies\Symfony\Component\Console\Exception\LogicException;
19 use Matomo\Dependencies\Symfony\Component\Console\Exception\RuntimeException;
20 use Matomo\Dependencies\Symfony\Component\Console\Input\InputInterface;
21 use Matomo\Dependencies\Symfony\Component\Console\Input\InputOption;
22 use Matomo\Dependencies\Symfony\Component\Console\Output\OutputInterface;
23 use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
24 use Matomo\Dependencies\Symfony\Component\VarDumper\Cloner\Data;
25 use Matomo\Dependencies\Symfony\Component\VarDumper\Cloner\Stub;
26 /**
27 * @author Grégoire Pineau <lyrixx@lyrixx.info>
28 */
29 class ServerLogCommand extends Command
30 {
31 private const BG_COLOR = ['black', 'blue', 'cyan', 'green', 'magenta', 'red', 'white', 'yellow'];
32 private $el;
33 private $handler;
34 protected static $defaultName = 'server:log';
35 protected static $defaultDescription = 'Start a log server that displays logs in real time';
36 public function isEnabled()
37 {
38 if (!class_exists(ConsoleFormatter::class)) {
39 return \false;
40 }
41 // based on a symfony/symfony package, it crashes due a missing FormatterInterface from monolog/monolog
42 if (!interface_exists(FormatterInterface::class)) {
43 return \false;
44 }
45 return parent::isEnabled();
46 }
47 protected function configure()
48 {
49 if (!class_exists(ConsoleFormatter::class)) {
50 return;
51 }
52 $this->addOption('host', null, InputOption::VALUE_REQUIRED, 'The server host', '127.0.0.1:9911')->addOption('format', null, InputOption::VALUE_REQUIRED, 'The line format', ConsoleFormatter::SIMPLE_FORMAT)->addOption('date-format', null, InputOption::VALUE_REQUIRED, 'The date format', ConsoleFormatter::SIMPLE_DATE)->addOption('filter', null, InputOption::VALUE_REQUIRED, 'An expression to filter log. Example: "level > 200 or channel in [\'app\', \'doctrine\']"')->setDescription(self::$defaultDescription)->setHelp(<<<'EOF'
53 <info>%command.name%</info> starts a log server to display in real time the log
54 messages generated by your application:
55
56 <info>php %command.full_name%</info>
57
58 To filter the log messages using any ExpressionLanguage compatible expression, use the <comment>--filter</> option:
59
60 <info>php %command.full_name% --filter="level > 200 or channel in ['app', 'doctrine']"</info>
61 EOF
62 );
63 }
64 protected function execute(InputInterface $input, OutputInterface $output)
65 {
66 $filter = $input->getOption('filter');
67 if ($filter) {
68 if (!class_exists(ExpressionLanguage::class)) {
69 throw new LogicException('Package "symfony/expression-language" is required to use the "filter" option.');
70 }
71 $this->el = new ExpressionLanguage();
72 }
73 $this->handler = new ConsoleHandler($output, \true, [OutputInterface::VERBOSITY_NORMAL => Logger::DEBUG]);
74 $this->handler->setFormatter(new ConsoleFormatter(['format' => str_replace('\\n', "\n", $input->getOption('format')), 'date_format' => $input->getOption('date-format'), 'colors' => $output->isDecorated(), 'multiline' => OutputInterface::VERBOSITY_DEBUG <= $output->getVerbosity()]));
75 if (!str_contains($host = $input->getOption('host'), '://')) {
76 $host = 'tcp://' . $host;
77 }
78 if (!($socket = stream_socket_server($host, $errno, $errstr))) {
79 throw new RuntimeException(sprintf('Server start failed on "%s": ', $host) . $errstr . ' ' . $errno);
80 }
81 foreach ($this->getLogs($socket) as $clientId => $message) {
82 $record = @unserialize(base64_decode($message), ['allowed_classes' => [Data::class, Stub::class]]);
83 if (!\is_array($record)) {
84 continue;
85 }
86 if (isset($record['datetime']) && \is_string($record['datetime'])) {
87 $record['datetime'] = \DateTimeImmutable::createFromFormat('Y-m-d\\TH:i:s.uP', $record['datetime']) ?: $record['datetime'];
88 }
89 if ($filter && !$this->el->evaluate($filter, $record)) {
90 continue;
91 }
92 $this->displayLog($output, $clientId, $record);
93 }
94 return 0;
95 }
96 private function getLogs($socket) : iterable
97 {
98 $sockets = [(int) $socket => $socket];
99 $write = [];
100 while (\true) {
101 $read = $sockets;
102 stream_select($read, $write, $write, null);
103 foreach ($read as $stream) {
104 if ($socket === $stream) {
105 $stream = stream_socket_accept($socket);
106 $sockets[(int) $stream] = $stream;
107 } elseif (feof($stream)) {
108 unset($sockets[(int) $stream]);
109 fclose($stream);
110 } else {
111 (yield (int) $stream => fgets($stream));
112 }
113 }
114 }
115 }
116 private function displayLog(OutputInterface $output, int $clientId, array $record)
117 {
118 if (isset($record['log_id'])) {
119 $clientId = unpack('H*', $record['log_id'])[1];
120 }
121 $logBlock = sprintf('<bg=%s> </>', self::BG_COLOR[$clientId % 8]);
122 $output->write($logBlock);
123 $this->handler->handle($record);
124 }
125 }
126