Skip to content

Commit ab9359c

Browse files
committed
feature #10194 [Console] Added standalone PSR-3 compliant logger (dunglas)
This PR was merged into the 2.5-dev branch. Discussion ---------- [Console] Added standalone PSR-3 compliant logger This PR adds a standalone, PSR-3 compliant, logger to the Console component. It logs all messages on the console output. Messages of `DEBUG`, `INFO` and `NOTICE` levels are displayed using the `info` format (default to green). Higher levels are displayed using the `error` formatter (default to red). This logger is similar to the [Monolog's Console Handler](http://symfony.com/doc/current/cookbook/logging/monolog_console.html) but does not have any external dependency (except `php-fig/log`). This is useful for console applications and commands needing a lightweight PSR-3 compliant logger (e.g. required by a dependency or to display basic informations to the user). An usage example is available here: https://github.com./dunglas/php-schema.org-model/blob/master/src/SchemaOrgModel/Command/GenerateEntitiesCommand.php#L71 | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | n/a | License | MIT | Doc PR | symfony/symfony-docs#3696 Commits ------- e40b34d [Console] Added standalone PSR-3 compliant logger
2 parents 54059de + f1e5bad commit ab9359c

File tree

4 files changed

+214
-2
lines changed

4 files changed

+214
-2
lines changed

Logger/ConsoleLogger.php

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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\Component\Console\Logger;
13+
14+
use Psr\Log\AbstractLogger;
15+
use Psr\Log\InvalidArgumentException;
16+
use Psr\Log\LogLevel;
17+
use Symfony\Component\Console\Output\OutputInterface;
18+
use Symfony\Component\Console\Output\ConsoleOutputInterface;
19+
20+
/**
21+
* PSR-3 compliant console logger
22+
*
23+
* @author Kévin Dunglas <[email protected]>
24+
* @link http://www.php-fig.org/psr/psr-3/
25+
*/
26+
class ConsoleLogger extends AbstractLogger
27+
{
28+
const INFO = 'info';
29+
const ERROR = 'error';
30+
31+
/**
32+
* @var OutputInterface
33+
*/
34+
private $output;
35+
/**
36+
* @var array
37+
*/
38+
private $verbosityLevelMap = array(
39+
LogLevel::EMERGENCY => OutputInterface::VERBOSITY_NORMAL,
40+
LogLevel::ALERT => OutputInterface::VERBOSITY_NORMAL,
41+
LogLevel::CRITICAL => OutputInterface::VERBOSITY_NORMAL,
42+
LogLevel::ERROR => OutputInterface::VERBOSITY_NORMAL,
43+
LogLevel::WARNING => OutputInterface::VERBOSITY_NORMAL,
44+
LogLevel::NOTICE => OutputInterface::VERBOSITY_VERBOSE,
45+
LogLevel::INFO => OutputInterface::VERBOSITY_VERY_VERBOSE,
46+
LogLevel::DEBUG => OutputInterface::VERBOSITY_DEBUG
47+
);
48+
/**
49+
* @var array
50+
*/
51+
private $formatLevelMap = array(
52+
LogLevel::EMERGENCY => self::ERROR,
53+
LogLevel::ALERT => self::ERROR,
54+
LogLevel::CRITICAL => self::ERROR,
55+
LogLevel::ERROR => self::ERROR,
56+
LogLevel::WARNING => self::INFO,
57+
LogLevel::NOTICE => self::INFO,
58+
LogLevel::INFO => self::INFO,
59+
LogLevel::DEBUG => self::INFO
60+
);
61+
62+
/**
63+
* @param OutputInterface $output
64+
* @param array $verbosityLevelMap
65+
* @param array $formatLevelMap
66+
*/
67+
public function __construct(OutputInterface $output, array $verbosityLevelMap = array(), array $formatLevelMap = array())
68+
{
69+
$this->output = $output;
70+
$this->verbosityLevelMap = $verbosityLevelMap + $this->verbosityLevelMap;
71+
$this->formatLevelMap = $formatLevelMap + $this->formatLevelMap;
72+
}
73+
74+
/**
75+
* {@inheritdoc}
76+
*/
77+
public function log($level, $message, array $context = array())
78+
{
79+
if (!isset($this->verbosityLevelMap[$level])) {
80+
throw new InvalidArgumentException(sprintf('The log level "%s" does not exist.', $level));
81+
}
82+
83+
// Write to the error output if necessary and available
84+
if ($this->formatLevelMap[$level] === self::ERROR && $this->output instanceof ConsoleOutputInterface) {
85+
$output = $this->output->getErrorOutput();
86+
} else {
87+
$output = $this->output;
88+
}
89+
90+
if ($output->getVerbosity() >= $this->verbosityLevelMap[$level]) {
91+
$output->writeln(sprintf('<%1$s>[%2$s] %3$s</%1$s>', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context)));
92+
}
93+
}
94+
95+
/**
96+
* Interpolates context values into the message placeholders
97+
*
98+
* @author PHP Framework Interoperability Group
99+
* @param string $message
100+
* @param array $context
101+
* @return string
102+
*/
103+
private function interpolate($message, array $context)
104+
{
105+
// build a replacement array with braces around the context keys
106+
$replace = array();
107+
foreach ($context as $key => $val) {
108+
if (!is_array($val) && (!is_object($val) || method_exists($val, '__toString'))) {
109+
$replace[sprintf('{%s}', $key)] = $val;
110+
}
111+
}
112+
113+
// interpolate replacement values into the message and return
114+
return strtr($message, $replace);
115+
}
116+
}

Tests/Fixtures/DummyOutput.php

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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\Component\Console\Tests\Fixtures;
13+
14+
use Symfony\Component\Console\Output\BufferedOutput;
15+
16+
/**
17+
* Dummy output
18+
*
19+
* @author Kévin Dunglas <[email protected]>
20+
*/
21+
class DummyOutput extends BufferedOutput
22+
{
23+
/**
24+
* @return array
25+
*/
26+
public function getLogs()
27+
{
28+
$logs = array();
29+
foreach (explode("\n", trim($this->fetch())) as $message) {
30+
preg_match('/^\[(.*)\] (.*)/', $message, $matches);
31+
$logs[] = sprintf('%s %s', $matches[1], $matches[2]);
32+
}
33+
34+
return $logs;
35+
}
36+
}

Tests/Logger/ConsoleLoggerTest.php

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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\Component\Console\Tests\Logger;
13+
14+
use Psr\Log\Test\LoggerInterfaceTest;
15+
use Psr\Log\LogLevel;
16+
use Symfony\Component\Console\Logger\ConsoleLogger;
17+
use Symfony\Component\Console\Tests\Fixtures\DummyOutput;
18+
use Symfony\Component\Console\Output\OutputInterface;
19+
20+
/**
21+
* Console logger test
22+
*
23+
* @author Kévin Dunglas <[email protected]>
24+
*/
25+
class ConsoleLoggerTest extends LoggerInterfaceTest
26+
{
27+
/**
28+
* @var DummyOutput
29+
*/
30+
protected $output;
31+
32+
/**
33+
* {@inheritdoc}
34+
*/
35+
public function getLogger()
36+
{
37+
$this->output = new DummyOutput(OutputInterface::VERBOSITY_VERBOSE);
38+
39+
return new ConsoleLogger($this->output, array(
40+
LogLevel::EMERGENCY => OutputInterface::VERBOSITY_NORMAL,
41+
LogLevel::ALERT => OutputInterface::VERBOSITY_NORMAL,
42+
LogLevel::CRITICAL => OutputInterface::VERBOSITY_NORMAL,
43+
LogLevel::ERROR => OutputInterface::VERBOSITY_NORMAL,
44+
LogLevel::WARNING => OutputInterface::VERBOSITY_NORMAL,
45+
LogLevel::NOTICE => OutputInterface::VERBOSITY_NORMAL,
46+
LogLevel::INFO => OutputInterface::VERBOSITY_NORMAL,
47+
LogLevel::DEBUG => OutputInterface::VERBOSITY_NORMAL
48+
));
49+
}
50+
51+
/**
52+
* {@inheritdoc}
53+
*/
54+
public function getLogs()
55+
{
56+
return $this->output->getLogs();
57+
}
58+
}

composer.json

+4-2
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@
1919
"php": ">=5.3.3"
2020
},
2121
"require-dev": {
22-
"symfony/event-dispatcher": "~2.1"
22+
"symfony/event-dispatcher": "~2.1",
23+
"psr/log": "~1.0"
2324
},
2425
"suggest": {
25-
"symfony/event-dispatcher": ""
26+
"symfony/event-dispatcher": "",
27+
"psr/log": "For using the console logger"
2628
},
2729
"autoload": {
2830
"psr-0": { "Symfony\\Component\\Console\\": "" }

0 commit comments

Comments
 (0)