--- /dev/null
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\Log;
+
+use Psr\Log\AbstractLogger;
+use Psr\Log\InvalidArgumentException;
+use Psr\Log\LogLevel;
+
+/**
+ * Minimalist PSR-3 logger designed to write in stderr or any other stream.
+ *
+ * @author Kévin Dunglas <dunglas@gmail.com>
+ */
+class Logger extends AbstractLogger
+{
+ private static $levels = array(
+ LogLevel::DEBUG => 0,
+ LogLevel::INFO => 1,
+ LogLevel::NOTICE => 2,
+ LogLevel::WARNING => 3,
+ LogLevel::ERROR => 4,
+ LogLevel::CRITICAL => 5,
+ LogLevel::ALERT => 6,
+ LogLevel::EMERGENCY => 7,
+ );
+
+ private $minLevelIndex;
+ private $formatter;
+ private $handle;
+
+ public function __construct($minLevel = null, $output = 'php://stderr', callable $formatter = null)
+ {
+ if (null === $minLevel) {
+ $minLevel = LogLevel::WARNING;
+
+ if (isset($_ENV['SHELL_VERBOSITY']) || isset($_SERVER['SHELL_VERBOSITY'])) {
+ switch ((int) (isset($_ENV['SHELL_VERBOSITY']) ? $_ENV['SHELL_VERBOSITY'] : $_SERVER['SHELL_VERBOSITY'])) {
+ case -1: $minLevel = LogLevel::ERROR; break;
+ case 1: $minLevel = LogLevel::NOTICE; break;
+ case 2: $minLevel = LogLevel::INFO; break;
+ case 3: $minLevel = LogLevel::DEBUG; break;
+ }
+ }
+ }
+
+ if (!isset(self::$levels[$minLevel])) {
+ throw new InvalidArgumentException(sprintf('The log level "%s" does not exist.', $minLevel));
+ }
+
+ $this->minLevelIndex = self::$levels[$minLevel];
+ $this->formatter = $formatter ?: array($this, 'format');
+ if (false === $this->handle = is_resource($output) ? $output : @fopen($output, 'a')) {
+ throw new InvalidArgumentException(sprintf('Unable to open "%s".', $output));
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function log($level, $message, array $context = array())
+ {
+ if (!isset(self::$levels[$level])) {
+ throw new InvalidArgumentException(sprintf('The log level "%s" does not exist.', $level));
+ }
+
+ if (self::$levels[$level] < $this->minLevelIndex) {
+ return;
+ }
+
+ $formatter = $this->formatter;
+ fwrite($this->handle, $formatter($level, $message, $context));
+ }
+
+ /**
+ * @param string $level
+ * @param string $message
+ * @param array $context
+ *
+ * @return string
+ */
+ private function format($level, $message, array $context)
+ {
+ if (false !== strpos($message, '{')) {
+ $replacements = array();
+ foreach ($context as $key => $val) {
+ if (null === $val || is_scalar($val) || (\is_object($val) && method_exists($val, '__toString'))) {
+ $replacements["{{$key}}"] = $val;
+ } elseif ($val instanceof \DateTimeInterface) {
+ $replacements["{{$key}}"] = $val->format(\DateTime::RFC3339);
+ } elseif (\is_object($val)) {
+ $replacements["{{$key}}"] = '[object '.\get_class($val).']';
+ } else {
+ $replacements["{{$key}}"] = '['.\gettype($val).']';
+ }
+ }
+
+ $message = strtr($message, $replacements);
+ }
+
+ return sprintf('%s [%s] %s', date(\DateTime::RFC3339), $level, $message).\PHP_EOL;
+ }
+}