From 7522e2206dc3593f3314d6c132c4c8a8cb9a164b Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Fri, 30 Nov 2012 19:01:47 -0800 Subject: [PATCH] Update loging to match (proposed) logging PSR. --- src/Mustache/Engine.php | 10 +- src/Mustache/Logger.php | 138 ++++++++++++----- src/Mustache/Logger/AbstractLogger.php | 120 --------------- src/Mustache/Logger/MonologLogger.php | 47 ------ src/Mustache/Logger/StreamLogger.php | 204 ++++++++++++++++++++++++- 5 files changed, 307 insertions(+), 212 deletions(-) delete mode 100644 src/Mustache/Logger/AbstractLogger.php delete mode 100644 src/Mustache/Logger/MonologLogger.php diff --git a/src/Mustache/Engine.php b/src/Mustache/Engine.php index b5b7b22..43ac4f6 100644 --- a/src/Mustache/Engine.php +++ b/src/Mustache/Engine.php @@ -341,17 +341,21 @@ class Mustache_Engine /** * Set the Mustache Logger instance. * - * @param Mustache_Logger $logger + * @param Mustache_Logger|Psr\Log\LoggerInterface $logger */ - public function setLogger(Mustache_Logger $logger) + public function setLogger($logger = null) { + if ($logger !== null && !($logger instanceof Mustache_Logger || is_a($logger, 'Psr\\Log\\LoggerInterface'))) { + throw new InvalidArgumentException('Expected an instance of Mustache_Logger or Psr\\Log\\LoggerInterface.'); + } + $this->logger = $logger; } /** * Get the current Mustache Logger instance. * - * @return Mustache_Logger + * @return Mustache_Logger|Psr\Log\LoggerInterface */ public function getLogger() { diff --git a/src/Mustache/Logger.php b/src/Mustache/Logger.php index 0200970..0a6b027 100644 --- a/src/Mustache/Logger.php +++ b/src/Mustache/Logger.php @@ -10,66 +10,126 @@ */ /** - * The Mustache Logger interface. + * Describes a Mustache logger instance + * + * This is identical to the Psr\Log\LoggerInterface. + * + * The message MUST be a string or object implementing __toString(). + * + * The message MAY contain placeholders in the form: %foo% where foo + * will be replaced by the context data in key "foo". + * + * The context array can contain arbitrary data, the only assumption that + * can be made by implementors is that if an Exception instance is given + * to produce a stack trace, it MUST be in a key named "exception". + * + * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md + * for the full interface specification. */ interface Mustache_Logger { /** - * Detailed debug information + * Psr\Log compatible log levels */ - const DEBUG = 100; + const EMERGENCY = 'emergency'; + const ALERT = 'alert'; + const CRITICAL = 'critical'; + const ERROR = 'error'; + const WARNING = 'warning'; + const NOTICE = 'notice'; + const INFO = 'info'; + const DEBUG = 'debug'; /** - * Interesting events + * System is unusable. * - * Examples: User logs in, SQL logs. + * @param string $message + * @param array $context + * @return null */ - const INFO = 200; + public function emergency($message, array $context = array()); /** - * Uncommon events - */ - const NOTICE = 250; - - /** - * Exceptional occurrences that are not errors + * Action must be taken immediately. * - * Examples: Use of deprecated APIs, poor use of an API, - * undesirable things that are not necessarily wrong. + * Example: Entire website down, database unavailable, etc. This should + * trigger the SMS alerts and wake you up. + * + * @param string $message + * @param array $context + * @return null */ - const WARNING = 300; + public function alert($message, array $context = array()); /** - * Runtime errors - */ - const ERROR = 400; - - /** - * Critical conditions + * Critical conditions. * * Example: Application component unavailable, unexpected exception. - */ - const CRITICAL = 500; - - /** - * Action must be taken immediately * - * Example: Entire website down, database unavailable, etc. - * This should trigger the SMS alerts and wake you up. + * @param string $message + * @param array $context + * @return null */ - const ALERT = 550; + public function critical($message, array $context = array()); /** - * Urgent alert. - */ - const EMERGENCY = 600; - - /** - * Adds a log record. + * Runtime errors that do not require immediate action but should typically + * be logged and monitored. * - * @param integer $level The logging level - * @param string $message The log message - * @param array $context The log context + * @param string $message + * @param array $context + * @return null + */ + public function error($message, array $context = array()); + + /** + * Exceptional occurrences that are not errors. + * + * Example: Use of deprecated APIs, poor use of an API, undesirable things + * that are not necessarily wrong. + * + * @param string $message + * @param array $context + * @return null + */ + public function warning($message, array $context = array()); + + /** + * Normal but significant events. + * + * @param string $message + * @param array $context + * @return null + */ + public function notice($message, array $context = array()); + + /** + * Interesting events. + * + * Example: User logs in, SQL logs. + * + * @param string $message + * @param array $context + * @return null + */ + public function info($message, array $context = array()); + + /** + * Detailed debug information. + * + * @param string $message + * @param array $context + * @return null + */ + public function debug($message, array $context = array()); + + /** + * Logs with an arbitrary level. + * + * @param mixed $level + * @param string $message + * @param array $context + * @return null */ public function log($level, $message, array $context = array()); -} +} \ No newline at end of file diff --git a/src/Mustache/Logger/AbstractLogger.php b/src/Mustache/Logger/AbstractLogger.php deleted file mode 100644 index 498cdce..0000000 --- a/src/Mustache/Logger/AbstractLogger.php +++ /dev/null @@ -1,120 +0,0 @@ - 'DEBUG', - 200 => 'INFO', - 250 => 'NOTICE', - 300 => 'WARNING', - 400 => 'ERROR', - 500 => 'CRITICAL', - 550 => 'ALERT', - 600 => 'EMERGENCY', - ); - - /** - * Abstract Logger constructor. - * - * @throws InvalidArgumentException if the logging level is unknown. - * - * @param integer $level The minimum logging level which will be written - */ - public function __construct($level = self::ERROR) - { - $this->setLevel($level); - } - - /** - * Set the minimum logging level. - * - * @throws InvalidArgumentException if the logging level is unknown. - * - * @param integer $level The minimum logging level which will be written - */ - public function setLevel($level) - { - if (!array_key_exists($level, self::$levels)) { - throw new InvalidArgumentException('Unexpected logging level: ' . $level); - } - - $this->level = $level; - } - - /** - * Get the current minimum logging level. - * - * @return integer - */ - public function getLevel() - { - return $this->level; - } - - /** - * Adds a log record. - * - * @see Mustache_Logger_AbstractLogger::write - * - * @param integer $level The logging level - * @param string $message The log message - * @param array $context The log context - */ - public function log($level, $message, array $context = array()) - { - if ($level >= $this->level) { - $this->writeLog($level, $message, $context); - } - } - - /** - * Gets the name of the logging level. - * - * @throws InvalidArgumentException if the logging level is unknown. - * - * @param integer $level - * - * @return string - */ - public static function getLevelName($level) - { - if (!array_key_exists($level, self::$levels)) { - throw new InvalidArgumentException('Unexpected logging level: ' . $level); - } - - return self::$levels[$level]; - } - - /** - * Format a log line for output. - * - * @param integer $level The logging level - * @param string $message The log message - * @param array $context The log context - */ - public static function formatLine($level, $message, array $context = array()) - { - return sprintf('%s: %s %s', self::getLevelName($level), (string) $message, json_encode($context)); - } - - /** - * Write a record to the log. Implemented by subclasses. - * - * @param integer $level The logging level - * @param string $message The log message - * @param array $context The log context - */ - abstract protected function write($level, $message, array $context = array()); -} diff --git a/src/Mustache/Logger/MonologLogger.php b/src/Mustache/Logger/MonologLogger.php deleted file mode 100644 index a6a9ea0..0000000 --- a/src/Mustache/Logger/MonologLogger.php +++ /dev/null @@ -1,47 +0,0 @@ -logger = $logger; - } - - /** - * Adds a log record. - * - * Overload the AbstractLogger::log method, because all log messages should - * be passed through to Monolog regardless of the log level. Monolog will - * handle ignoring the messages it doesn't care about. - * - * @param integer $level The logging level - * @param string $message The log message - * @param array $context The log context - */ - public function log($level, $message, array $context = array()) - { - $this->logger->addRecord($level, $message, $context); - } -} diff --git a/src/Mustache/Logger/StreamLogger.php b/src/Mustache/Logger/StreamLogger.php index 727a626..57e90f3 100644 --- a/src/Mustache/Logger/StreamLogger.php +++ b/src/Mustache/Logger/StreamLogger.php @@ -18,8 +18,19 @@ * * Hint: Try `php://stderr` for your stream URL. */ -class StreamLogger extends Mustache_Logger_AbstractLogger +class StreamLogger implements Mustache_Logger { + protected static $levels = array( + self::DEBUG => 100, + self::INFO => 200, + self::NOTICE => 250, + self::WARNING => 300, + self::ERROR => 400, + self::CRITICAL => 500, + self::ALERT => 550, + self::EMERGENCY => 600, + ); + protected $stream = null; protected $url = null; @@ -29,7 +40,7 @@ class StreamLogger extends Mustache_Logger_AbstractLogger */ public function __construct($stream, $level = Mustache_Logger::ERROR) { - parent::__construct($level); + $this->setLevel($level); if (is_resource($stream)) { $this->stream = $stream; @@ -38,6 +49,158 @@ class StreamLogger extends Mustache_Logger_AbstractLogger } } + /** + * Set the minimum logging level. + * + * @throws InvalidArgumentException if the logging level is unknown. + * + * @param integer $level The minimum logging level which will be written + */ + public function setLevel($level) + { + if (!array_key_exists($level, self::$levels)) { + throw new InvalidArgumentException('Unexpected logging level: ' . $level); + } + + $this->level = $level; + } + + /** + * Get the current minimum logging level. + * + * @return integer + */ + public function getLevel() + { + return $this->level; + } + + /** + * System is unusable. + * + * @param string $message + * @param array $context + * @return null + */ + public function emergency($message, array $context = array()) + { + $this->log(self::EMERGENCY, $message, $context); + } + + /** + * Action must be taken immediately. + * + * Example: Entire website down, database unavailable, etc. This should + * trigger the SMS alerts and wake you up. + * + * @param string $message + * @param array $context + * @return null + */ + public function alert($message, array $context = array()) + { + $this->log(self::ALERT, $message, $context); + } + + /** + * Critical conditions. + * + * Example: Application component unavailable, unexpected exception. + * + * @param string $message + * @param array $context + * @return null + */ + public function critical($message, array $context = array()) + { + $this->log(self::CRITICAL, $message, $context); + } + + /** + * Runtime errors that do not require immediate action but should typically + * be logged and monitored. + * + * @param string $message + * @param array $context + * @return null + */ + public function error($message, array $context = array()) + { + $this->log(self::ERROR, $message, $context); + } + + /** + * Exceptional occurrences that are not errors. + * + * Example: Use of deprecated APIs, poor use of an API, undesirable things + * that are not necessarily wrong. + * + * @param string $message + * @param array $context + * @return null + */ + public function warning($message, array $context = array()) + { + $this->log(self::WARNING, $message, $context); + } + + /** + * Normal but significant events. + * + * @param string $message + * @param array $context + * @return null + */ + public function notice($message, array $context = array()) + { + $this->log(self::NOTICE, $message, $context); + } + + /** + * Interesting events. + * + * Example: User logs in, SQL logs. + * + * @param string $message + * @param array $context + * @return null + */ + public function info($message, array $context = array()) + { + $this->log(self::INFO, $message, $context); + } + + /** + * Detailed debug information. + * + * @param string $message + * @param array $context + * @return null + */ + public function debug($message, array $context = array()) + { + $this->log(self::DEBUG, $message, $context); + } + + /** + * Logs with an arbitrary level. + * + * @param mixed $level + * @param string $message + * @param array $context + * @return null + */ + public function log($level, $message, array $context = array()) + { + if (!array_key_exists($level, self::$levels)) { + throw new InvalidArgumentException('Unexpected logging level: ' . $level); + } + + if (self::$levels[$level] >= $this->level) { + $this->writeLog($level, $message, $context); + } + } + /** * Write a record to the log. * @@ -45,7 +208,7 @@ class StreamLogger extends Mustache_Logger_AbstractLogger * @param string $message The log message * @param array $context The log context */ - protected function write($level, $message, array $context = array()) + protected function writeLog($level, $message, array $context = array()) { if (!is_resource($this->stream)) { if (!isset($this->url)) { @@ -60,4 +223,39 @@ class StreamLogger extends Mustache_Logger_AbstractLogger fwrite($this->stream, self::formatLine($level, $message, $context)); } + + /** + * Gets the name of the logging level. + * + * @throws InvalidArgumentException if the logging level is unknown. + * + * @param integer $level + * + * @return string + */ + protected static function getLevelName($level) + { + if (!array_key_exists($level, self::$levels)) { + throw new InvalidArgumentException('Unexpected logging level: ' . $level); + } + + return strtoupper($level); + } + + /** + * Format a log line for output. + * + * @param integer $level The logging level + * @param string $message The log message + * @param array $context The log context + */ + protected static function formatLine($level, $message, array $context = array()) + { + $message = (string) $message; + foreach ($context as $key => $val) { + $message = str_replace('%'.$key.'%', $val, $message); + } + + return sprintf('%s: %s %s', self::getLevelName($level), (string) $message, json_encode($context)); + } }