[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/inc/ -> Logger.php (source)

   1  <?php
   2  
   3  namespace dokuwiki;
   4  
   5  use dokuwiki\Extension\Event;
   6  
   7  /**
   8   * Log messages to a daily log file
   9   */
  10  class Logger
  11  {
  12      const LOG_ERROR = 'error';
  13      const LOG_DEPRECATED = 'deprecated';
  14      const LOG_DEBUG = 'debug';
  15  
  16      /** @var Logger[] */
  17      static protected $instances;
  18  
  19      /** @var string what kind of log is this */
  20      protected $facility;
  21  
  22      protected $isLogging = true;
  23  
  24      /**
  25       * Logger constructor.
  26       *
  27       * @param string $facility The type of log
  28       */
  29      protected function __construct($facility)
  30      {
  31          global $conf;
  32          $this->facility = $facility;
  33  
  34          // Should logging be disabled for this facility?
  35          $dontlog = explode(',', $conf['dontlog']);
  36          $dontlog = array_map('trim', $dontlog);
  37          if (in_array($facility, $dontlog)) $this->isLogging = false;
  38      }
  39  
  40      /**
  41       * Return a Logger instance for the given facility
  42       *
  43       * @param string $facility The type of log
  44       * @return Logger
  45       */
  46      static public function getInstance($facility = self::LOG_ERROR)
  47      {
  48          if (empty(self::$instances[$facility])) {
  49              self::$instances[$facility] = new Logger($facility);
  50          }
  51          return self::$instances[$facility];
  52      }
  53  
  54      /**
  55       * Convenience method to directly log to the error log
  56       *
  57       * @param string $message The log message
  58       * @param mixed $details Any details that should be added to the log entry
  59       * @param string $file A source filename if this is related to a source position
  60       * @param int $line A line number for the above file
  61       * @return bool has a log been written?
  62       */
  63      static public function error($message, $details = null, $file = '', $line = 0)
  64      {
  65          return self::getInstance(self::LOG_ERROR)->log(
  66              $message, $details, $file, $line
  67          );
  68      }
  69  
  70      /**
  71       * Convenience method to directly log to the debug log
  72       *
  73       * @param string $message The log message
  74       * @param mixed $details Any details that should be added to the log entry
  75       * @param string $file A source filename if this is related to a source position
  76       * @param int $line A line number for the above file
  77       * @return bool has a log been written?
  78       */
  79      static public function debug($message, $details = null, $file = '', $line = 0)
  80      {
  81          return self::getInstance(self::LOG_DEBUG)->log(
  82              $message, $details, $file, $line
  83          );
  84      }
  85  
  86      /**
  87       * Convenience method to directly log to the deprecation log
  88       *
  89       * @param string $message The log message
  90       * @param mixed $details Any details that should be added to the log entry
  91       * @param string $file A source filename if this is related to a source position
  92       * @param int $line A line number for the above file
  93       * @return bool has a log been written?
  94       */
  95      static public function deprecated($message, $details = null, $file = '', $line = 0)
  96      {
  97          return self::getInstance(self::LOG_DEPRECATED)->log(
  98              $message, $details, $file, $line
  99          );
 100      }
 101  
 102      /**
 103       * Log a message to the facility log
 104       *
 105       * @param string $message The log message
 106       * @param mixed $details Any details that should be added to the log entry
 107       * @param string $file A source filename if this is related to a source position
 108       * @param int $line A line number for the above file
 109       * @triggers LOGGER_DATA_FORMAT can be used to change the logged data or intercept it
 110       * @return bool has a log been written?
 111       */
 112      public function log($message, $details = null, $file = '', $line = 0)
 113      {
 114          global $EVENT_HANDLER;
 115          if (!$this->isLogging) return false;
 116  
 117          $datetime = time();
 118          $data = [
 119              'facility' => $this->facility,
 120              'datetime' => $datetime,
 121              'message' => $message,
 122              'details' => $details,
 123              'file' => $file,
 124              'line' => $line,
 125              'loglines' => [],
 126              'logfile' => $this->getLogfile($datetime),
 127          ];
 128  
 129          if ($EVENT_HANDLER !== null) {
 130              $event = new Event('LOGGER_DATA_FORMAT', $data);
 131              if ($event->advise_before()) {
 132                  $data['loglines'] = $this->formatLogLines($data);
 133              }
 134              $event->advise_after();
 135          } else {
 136              // The event system is not yet available, to ensure the log isn't lost even on
 137              // fatal errors, the default action is executed
 138              $data['loglines'] = $this->formatLogLines($data);
 139          }
 140  
 141          // only log when any data available
 142          if (count($data['loglines'])) {
 143              return $this->writeLogLines($data['loglines'], $data['logfile']);
 144          } else {
 145              return false;
 146          }
 147      }
 148  
 149      /**
 150       * Is this logging instace actually logging?
 151       *
 152       * @return bool
 153       */
 154      public function isLogging()
 155      {
 156          return $this->isLogging;
 157      }
 158  
 159      /**
 160       * Formats the given data as loglines
 161       *
 162       * @param array $data Event data from LOGGER_DATA_FORMAT
 163       * @return string[] the lines to log
 164       */
 165      protected function formatLogLines($data)
 166      {
 167          extract($data);
 168  
 169          // details are logged indented
 170          if ($details) {
 171              if (!is_string($details)) {
 172                  $details = json_encode($details, JSON_PRETTY_PRINT);
 173              }
 174              $details = explode("\n", $details);
 175              $loglines = array_map(function ($line) {
 176                  return '  ' . $line;
 177              }, $details);
 178          } elseif ($details) {
 179              $loglines = [$details];
 180          } else {
 181              $loglines = [];
 182          }
 183  
 184          // datetime, fileline, message
 185          $logline = gmdate('Y-m-d H:i:s', $datetime) . "\t";
 186          if ($file) {
 187              $logline .= $file;
 188              if ($line) $logline .= "($line)";
 189          }
 190          $logline .= "\t" . $message;
 191          array_unshift($loglines, $logline);
 192  
 193          return $loglines;
 194      }
 195  
 196      /**
 197       * Construct the log file for the given day
 198       *
 199       * @param false|string|int $date Date to access, false for today
 200       * @return string
 201       */
 202      public function getLogfile($date = false)
 203      {
 204          global $conf;
 205  
 206          if ($date !== null && !is_numeric($date)) {
 207              $date = strtotime($date);
 208          }
 209          if (!$date) $date = time();
 210  
 211          return $conf['logdir'] . '/' . $this->facility . '/' . date('Y-m-d', $date) . '.log';
 212      }
 213  
 214      /**
 215       * Write the given lines to today's facility log
 216       *
 217       * @param string[] $lines the raw lines to append to the log
 218       * @param string $logfile where to write to
 219       * @return bool true if the log was written
 220       */
 221      protected function writeLogLines($lines, $logfile)
 222      {
 223          if (defined('DOKU_UNITTEST')) {
 224              fwrite(STDERR, "\n[" . $this->facility . '] ' . join("\n", $lines) . "\n");
 225          }
 226          return io_saveFile($logfile, join("\n", $lines) . "\n", true);
 227      }
 228  }