Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.
   1  <?php
   2  
   3  /*
   4   * This file is part of Mustache.php.
   5   *
   6   * (c) 2010-2017 Justin Hileman
   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  /**
  13   * A Mustache Stream Logger.
  14   *
  15   * The Stream Logger wraps a file resource instance (such as a stream) or a
  16   * stream URL. All log messages over the threshold level will be appended to
  17   * this stream.
  18   *
  19   * Hint: Try `php://stderr` for your stream URL.
  20   */
  21  class Mustache_Logger_StreamLogger extends Mustache_Logger_AbstractLogger
  22  {
  23      protected static $levels = array(
  24          self::DEBUG     => 100,
  25          self::INFO      => 200,
  26          self::NOTICE    => 250,
  27          self::WARNING   => 300,
  28          self::ERROR     => 400,
  29          self::CRITICAL  => 500,
  30          self::ALERT     => 550,
  31          self::EMERGENCY => 600,
  32      );
  33  
  34      protected $level;
  35      protected $stream = null;
  36      protected $url    = null;
  37  
  38      /**
  39       * @throws InvalidArgumentException if the logging level is unknown
  40       *
  41       * @param resource|string $stream Resource instance or URL
  42       * @param int             $level  The minimum logging level at which this handler will be triggered
  43       */
  44      public function __construct($stream, $level = Mustache_Logger::ERROR)
  45      {
  46          $this->setLevel($level);
  47  
  48          if (is_resource($stream)) {
  49              $this->stream = $stream;
  50          } else {
  51              $this->url = $stream;
  52          }
  53      }
  54  
  55      /**
  56       * Close stream resources.
  57       */
  58      public function __destruct()
  59      {
  60          if (is_resource($this->stream)) {
  61              fclose($this->stream);
  62          }
  63      }
  64  
  65      /**
  66       * Set the minimum logging level.
  67       *
  68       * @throws Mustache_Exception_InvalidArgumentException if the logging level is unknown
  69       *
  70       * @param int $level The minimum logging level which will be written
  71       */
  72      public function setLevel($level)
  73      {
  74          if (!array_key_exists($level, self::$levels)) {
  75              throw new Mustache_Exception_InvalidArgumentException(sprintf('Unexpected logging level: %s', $level));
  76          }
  77  
  78          $this->level = $level;
  79      }
  80  
  81      /**
  82       * Get the current minimum logging level.
  83       *
  84       * @return int
  85       */
  86      public function getLevel()
  87      {
  88          return $this->level;
  89      }
  90  
  91      /**
  92       * Logs with an arbitrary level.
  93       *
  94       * @throws Mustache_Exception_InvalidArgumentException if the logging level is unknown
  95       *
  96       * @param mixed  $level
  97       * @param string $message
  98       * @param array  $context
  99       */
 100      public function log($level, $message, array $context = array())
 101      {
 102          if (!array_key_exists($level, self::$levels)) {
 103              throw new Mustache_Exception_InvalidArgumentException(sprintf('Unexpected logging level: %s', $level));
 104          }
 105  
 106          if (self::$levels[$level] >= self::$levels[$this->level]) {
 107              $this->writeLog($level, $message, $context);
 108          }
 109      }
 110  
 111      /**
 112       * Write a record to the log.
 113       *
 114       * @throws Mustache_Exception_LogicException   If neither a stream resource nor url is present
 115       * @throws Mustache_Exception_RuntimeException If the stream url cannot be opened
 116       *
 117       * @param int    $level   The logging level
 118       * @param string $message The log message
 119       * @param array  $context The log context
 120       */
 121      protected function writeLog($level, $message, array $context = array())
 122      {
 123          if (!is_resource($this->stream)) {
 124              if (!isset($this->url)) {
 125                  throw new Mustache_Exception_LogicException('Missing stream url, the stream can not be opened. This may be caused by a premature call to close().');
 126              }
 127  
 128              $this->stream = fopen($this->url, 'a');
 129              if (!is_resource($this->stream)) {
 130                  // @codeCoverageIgnoreStart
 131                  throw new Mustache_Exception_RuntimeException(sprintf('The stream or file "%s" could not be opened.', $this->url));
 132                  // @codeCoverageIgnoreEnd
 133              }
 134          }
 135  
 136          fwrite($this->stream, self::formatLine($level, $message, $context));
 137      }
 138  
 139      /**
 140       * Gets the name of the logging level.
 141       *
 142       * @throws InvalidArgumentException if the logging level is unknown
 143       *
 144       * @param int $level
 145       *
 146       * @return string
 147       */
 148      protected static function getLevelName($level)
 149      {
 150          return strtoupper($level);
 151      }
 152  
 153      /**
 154       * Format a log line for output.
 155       *
 156       * @param int    $level   The logging level
 157       * @param string $message The log message
 158       * @param array  $context The log context
 159       *
 160       * @return string
 161       */
 162      protected static function formatLine($level, $message, array $context = array())
 163      {
 164          return sprintf(
 165              "%s: %s\n",
 166              self::getLevelName($level),
 167              self::interpolateMessage($message, $context)
 168          );
 169      }
 170  
 171      /**
 172       * Interpolate context values into the message placeholders.
 173       *
 174       * @param string $message
 175       * @param array  $context
 176       *
 177       * @return string
 178       */
 179      protected static function interpolateMessage($message, array $context = array())
 180      {
 181          if (strpos($message, '{') === false) {
 182              return $message;
 183          }
 184  
 185          // build a replacement array with braces around the context keys
 186          $replace = array();
 187          foreach ($context as $key => $val) {
 188              $replace['{' . $key . '}'] = $val;
 189          }
 190  
 191          // interpolate replacement values into the the message and return
 192          return strtr($message, $replace);
 193      }
 194  }