Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Symfony\Component\Console\Logger; Chris@0: Chris@0: use Psr\Log\AbstractLogger; Chris@0: use Psr\Log\InvalidArgumentException; Chris@0: use Psr\Log\LogLevel; Chris@17: use Symfony\Component\Console\Output\ConsoleOutputInterface; Chris@0: use Symfony\Component\Console\Output\OutputInterface; Chris@0: Chris@0: /** Chris@0: * PSR-3 compliant console logger. Chris@0: * Chris@0: * @author Kévin Dunglas Chris@0: * Chris@0: * @see http://www.php-fig.org/psr/psr-3/ Chris@0: */ Chris@0: class ConsoleLogger extends AbstractLogger Chris@0: { Chris@0: const INFO = 'info'; Chris@0: const ERROR = 'error'; Chris@0: Chris@0: private $output; Chris@17: private $verbosityLevelMap = [ Chris@0: LogLevel::EMERGENCY => OutputInterface::VERBOSITY_NORMAL, Chris@0: LogLevel::ALERT => OutputInterface::VERBOSITY_NORMAL, Chris@0: LogLevel::CRITICAL => OutputInterface::VERBOSITY_NORMAL, Chris@0: LogLevel::ERROR => OutputInterface::VERBOSITY_NORMAL, Chris@0: LogLevel::WARNING => OutputInterface::VERBOSITY_NORMAL, Chris@0: LogLevel::NOTICE => OutputInterface::VERBOSITY_VERBOSE, Chris@0: LogLevel::INFO => OutputInterface::VERBOSITY_VERY_VERBOSE, Chris@0: LogLevel::DEBUG => OutputInterface::VERBOSITY_DEBUG, Chris@17: ]; Chris@17: private $formatLevelMap = [ Chris@0: LogLevel::EMERGENCY => self::ERROR, Chris@0: LogLevel::ALERT => self::ERROR, Chris@0: LogLevel::CRITICAL => self::ERROR, Chris@0: LogLevel::ERROR => self::ERROR, Chris@0: LogLevel::WARNING => self::INFO, Chris@0: LogLevel::NOTICE => self::INFO, Chris@0: LogLevel::INFO => self::INFO, Chris@0: LogLevel::DEBUG => self::INFO, Chris@17: ]; Chris@0: private $errored = false; Chris@0: Chris@17: public function __construct(OutputInterface $output, array $verbosityLevelMap = [], array $formatLevelMap = []) Chris@0: { Chris@0: $this->output = $output; Chris@0: $this->verbosityLevelMap = $verbosityLevelMap + $this->verbosityLevelMap; Chris@0: $this->formatLevelMap = $formatLevelMap + $this->formatLevelMap; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@17: public function log($level, $message, array $context = []) Chris@0: { Chris@0: if (!isset($this->verbosityLevelMap[$level])) { Chris@0: throw new InvalidArgumentException(sprintf('The log level "%s" does not exist.', $level)); Chris@0: } Chris@0: Chris@0: $output = $this->output; Chris@0: Chris@0: // Write to the error output if necessary and available Chris@14: if (self::ERROR === $this->formatLevelMap[$level]) { Chris@0: if ($this->output instanceof ConsoleOutputInterface) { Chris@0: $output = $output->getErrorOutput(); Chris@0: } Chris@0: $this->errored = true; Chris@0: } Chris@0: Chris@0: // the if condition check isn't necessary -- it's the same one that $output will do internally anyway. Chris@0: // We only do it for efficiency here as the message formatting is relatively expensive. Chris@0: if ($output->getVerbosity() >= $this->verbosityLevelMap[$level]) { Chris@0: $output->writeln(sprintf('<%1$s>[%2$s] %3$s', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context)), $this->verbosityLevelMap[$level]); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns true when any messages have been logged at error levels. Chris@14: * Chris@14: * @return bool Chris@0: */ Chris@0: public function hasErrored() Chris@0: { Chris@0: return $this->errored; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Interpolates context values into the message placeholders. Chris@0: * Chris@0: * @author PHP Framework Interoperability Group Chris@0: * Chris@0: * @param string $message Chris@0: * @param array $context Chris@0: * Chris@0: * @return string Chris@0: */ Chris@0: private function interpolate($message, array $context) Chris@0: { Chris@14: if (false === strpos($message, '{')) { Chris@14: return $message; Chris@14: } Chris@14: Chris@17: $replacements = []; Chris@0: foreach ($context as $key => $val) { Chris@14: if (null === $val || is_scalar($val) || (\is_object($val) && method_exists($val, '__toString'))) { Chris@14: $replacements["{{$key}}"] = $val; Chris@14: } elseif ($val instanceof \DateTimeInterface) { Chris@14: $replacements["{{$key}}"] = $val->format(\DateTime::RFC3339); Chris@14: } elseif (\is_object($val)) { Chris@14: $replacements["{{$key}}"] = '[object '.\get_class($val).']'; Chris@14: } else { Chris@14: $replacements["{{$key}}"] = '['.\gettype($val).']'; Chris@0: } Chris@0: } Chris@0: Chris@14: return strtr($message, $replacements); Chris@0: } Chris@0: }