Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
ConsoleLogger.php
Go to the documentation of this file.
1 <?php
6 namespace Magento\Deploy\Console;
7 
8 use Psr\Log\AbstractLogger;
9 use Psr\Log\LogLevel;
10 use Symfony\Component\Console\Output\OutputInterface;
11 use Symfony\Component\Console\Output\ConsoleOutputInterface;
12 use Symfony\Component\Console\Helper\FormatterHelper;
16 
20 class ConsoleLogger extends AbstractLogger
21 {
25  const INFO = 'info';
26 
30  const ERROR = 'error';
31 
37  private $tmpDir;
38 
44  private $output;
45 
51  private $formatterHelper;
52 
58  private $initialMaxBarSize = 0;
59 
67  private $renderedLines = 0;
68 
74  private $lastTimeRefreshed = 0;
75 
79  private $verbosityLevelMap = [
80  LogLevel::EMERGENCY => OutputInterface::VERBOSITY_NORMAL,
81  LogLevel::ALERT => OutputInterface::VERBOSITY_NORMAL,
82  LogLevel::CRITICAL => OutputInterface::VERBOSITY_NORMAL,
83  LogLevel::ERROR => OutputInterface::VERBOSITY_NORMAL,
84  LogLevel::WARNING => OutputInterface::VERBOSITY_NORMAL,
85  LogLevel::NOTICE => OutputInterface::VERBOSITY_NORMAL,
86  LogLevel::INFO => OutputInterface::VERBOSITY_VERBOSE,
87  LogLevel::DEBUG => OutputInterface::VERBOSITY_DEBUG
88  ];
89 
93  private $formatLevelMap = [
94  LogLevel::EMERGENCY => self::ERROR,
95  LogLevel::ALERT => self::ERROR,
96  LogLevel::CRITICAL => self::ERROR,
98  LogLevel::WARNING => self::INFO,
99  LogLevel::NOTICE => self::INFO,
101  LogLevel::DEBUG => self::INFO
102  ];
103 
109  private $processes = [];
110 
118  public function __construct(
120  OutputInterface $output,
121  FormatterHelper $formatterHelper,
122  array $verbosityLevelMap = [],
123  array $formatLevelMap = []
124  ) {
125  $this->tmpDir = $filesystem->getDirectoryWrite(DirectoryList::TMP_MATERIALIZATION_DIR);
126  $this->output = $output;
127  $this->formatterHelper = $formatterHelper;
128  $this->verbosityLevelMap = $verbosityLevelMap + $this->verbosityLevelMap;
129  $this->formatLevelMap = $formatLevelMap + $this->formatLevelMap;
130  }
131 
135  public function log($level, $message, array $context = [])
136  {
137  if (!isset($this->verbosityLevelMap[$level])) {
138  $level = self::INFO;
139  }
140 
141  // Write to the error output if necessary and available
142  if ($this->formatLevelMap[$level] === self::ERROR && $this->output instanceof ConsoleOutputInterface) {
143  $output = $this->output->getErrorOutput();
144  } else {
145  $output = $this->output;
146  }
147 
148  if (isset($context['process'])) {
149  $this->registerProcess($context);
150  } else {
151  $this->refresh($output);
152  }
153 
154  if ($output->getVerbosity() >= $this->verbosityLevelMap[$level]) {
155  $output->writeln(sprintf('<%1$s>%2$s</%1$s>', $this->formatLevelMap[$level], $message));
156  }
157  }
158 
165  private function registerProcess(array $context)
166  {
167  $name = isset($context['process']) ? $context['process'] : 'main';
168  if (!isset($this->processes[$name])) {
169  $context['start'] = time();
170  $context['elapsed'] = 0;
171  $this->processes[$name] = $context;
172  }
173  }
174 
181  private function refresh(OutputInterface $output)
182  {
183  if (!count($this->processes) || (time() - $this->lastTimeRefreshed < 1)) {
184  return;
185  }
186 
187  $this->cleanUp();
188 
189  $bars = [];
190  $maxBarSize = 0;
191  foreach ($this->processes as $name => & $process) {
192  $this->updateProcessInfo($name, $process);
193  $bar = $this->renderProgressBar($output, $process);
194  $maxBarSize = strlen($bar) > $maxBarSize ? strlen($bar) : $maxBarSize;
195  $bars[] = $bar;
196  }
197  if (!$this->initialMaxBarSize) {
198  $this->initialMaxBarSize = $maxBarSize + 10;
199  }
200  if ($bars) {
201  $this->renderedLines = count($bars);
202  $bar = '';
203  foreach ($bars as &$bar) {
204  if ($this->initialMaxBarSize > strlen($bar)) {
205  $bar .= str_pad(" ", ($this->initialMaxBarSize - strlen($bar)));
206  }
207  }
208  $bar = trim($bar);
209  $output->writeln(implode("\n", $bars));
210  }
211  }
212 
220  private function updateProcessInfo($deployedPackagePath, array & $process)
221  {
222  $packageDeploymentInfo = $this->getPackageDeploymentInfo($deployedPackagePath . '/info.json');
223  if ($packageDeploymentInfo) {
224  $process['done'] = $packageDeploymentInfo['count'];
225  } else {
226  $process['done'] = 0;
227  }
228  if ($process['done'] > $process['count']) {
229  $process['count'] = $process['done'];
230  }
231  if ($process['done'] !== $process['count']) {
232  $process['elapsed'] = $this->formatterHelper->formatTime(time() - $process['start']);
233  }
234  $process['percent'] = floor(
235  ($process['count'] ? (float)$process['done'] / $process['count'] : 0) * 100
236  );
237  }
238 
244  private function cleanUp()
245  {
246  $this->lastTimeRefreshed = time();
247  // Erase previous lines
248  if ($this->renderedLines > 0) {
249  for ($i = 0; $i < $this->renderedLines; ++$i) {
250  $this->output->write("\x1B[1A\x1B[2K", false, OutputInterface::OUTPUT_RAW);
251  }
252  }
253  $this->renderedLines = 0;
254  }
255 
263  private function renderProgressBar(OutputInterface $output, array $process)
264  {
265  $title = "{$process['process']}";
266  $titlePad = str_pad(' ', (40 - strlen($title)));
267  $count = "{$process['done']}/{$process['count']}";
268  $countPad = str_pad(' ', (20 - strlen($count)));
269  $percent = "{$process['percent']}% ";
270  $percentPad = str_pad(' ', (7 - strlen($percent)));
271  return "{$title}{$titlePad}"
272  . "{$count}{$countPad}"
273  . "{$this->renderBar($output, $process)} "
274  . "{$percent}%{$percentPad}"
275  . "{$process['elapsed']} ";
276  }
277 
285  private function renderBar(OutputInterface $output, array $process)
286  {
287  $completeBars = floor(
288  $process['count'] > 0 ? ($process['done'] / $process['count']) * 28 : $process['done'] % 28
289  );
290 
291  $display = str_repeat('=', $completeBars);
292  if ($completeBars < 28) {
293  $emptyBars = 28 - $completeBars
294  - $this->formatterHelper->strlenWithoutDecoration($output->getFormatter(), '>');
295  $display .= '>' . str_repeat('-', $emptyBars);
296  }
297  return $display;
298  }
299 
306  private function getPackageDeploymentInfo($relativePath)
307  {
308  if ($this->tmpDir->isFile($relativePath)) {
309  $info = $this->tmpDir->readFile($relativePath);
310  $info = json_decode($info, true);
311  } else {
312  $info = [];
313  }
314  return $info;
315  }
316 }
$title
Definition: default.phtml:14
output($string, $level=INFO, $label='')
if($this->helper('Magento\Tax\Helper\Data') ->displayFullSummary()) foreach( $block->getTotal() ->getFullInfo() as $info)(isset($info['hidden']) && $info['hidden']) $percent
Definition: tax.phtml:33
__construct(Filesystem $filesystem, OutputInterface $output, FormatterHelper $formatterHelper, array $verbosityLevelMap=[], array $formatLevelMap=[])
$count
Definition: recent.phtml:13
$message
$relativePath
Definition: get.php:35
log($level, $message, array $context=[])
foreach( $_productCollection as $_product)() ?>" class $info
Definition: listing.phtml:52
$filesystem
$i
Definition: gallery.phtml:31
if(!isset($_GET['name'])) $name
Definition: log.php:14