123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- <?php
- namespace dokuwiki;
- use dokuwiki\Extension\Event;
- /**
- * Log messages to a daily log file
- */
- class Logger
- {
- const LOG_ERROR = 'error';
- const LOG_DEPRECATED = 'deprecated';
- const LOG_DEBUG = 'debug';
- /** @var Logger[] */
- static protected $instances;
- /** @var string what kind of log is this */
- protected $facility;
- protected $isLogging = true;
- /**
- * Logger constructor.
- *
- * @param string $facility The type of log
- */
- protected function __construct($facility)
- {
- global $conf;
- $this->facility = $facility;
- // Should logging be disabled for this facility?
- $dontlog = explode(',', $conf['dontlog']);
- $dontlog = array_map('trim', $dontlog);
- if (in_array($facility, $dontlog)) $this->isLogging = false;
- }
- /**
- * Return a Logger instance for the given facility
- *
- * @param string $facility The type of log
- * @return Logger
- */
- static public function getInstance($facility = self::LOG_ERROR)
- {
- if (empty(self::$instances[$facility])) {
- self::$instances[$facility] = new Logger($facility);
- }
- return self::$instances[$facility];
- }
- /**
- * Convenience method to directly log to the error log
- *
- * @param string $message The log message
- * @param mixed $details Any details that should be added to the log entry
- * @param string $file A source filename if this is related to a source position
- * @param int $line A line number for the above file
- * @return bool has a log been written?
- */
- static public function error($message, $details = null, $file = '', $line = 0)
- {
- return self::getInstance(self::LOG_ERROR)->log(
- $message, $details, $file, $line
- );
- }
- /**
- * Convenience method to directly log to the debug log
- *
- * @param string $message The log message
- * @param mixed $details Any details that should be added to the log entry
- * @param string $file A source filename if this is related to a source position
- * @param int $line A line number for the above file
- * @return bool has a log been written?
- */
- static public function debug($message, $details = null, $file = '', $line = 0)
- {
- return self::getInstance(self::LOG_DEBUG)->log(
- $message, $details, $file, $line
- );
- }
- /**
- * Convenience method to directly log to the deprecation log
- *
- * @param string $message The log message
- * @param mixed $details Any details that should be added to the log entry
- * @param string $file A source filename if this is related to a source position
- * @param int $line A line number for the above file
- * @return bool has a log been written?
- */
- static public function deprecated($message, $details = null, $file = '', $line = 0)
- {
- return self::getInstance(self::LOG_DEPRECATED)->log(
- $message, $details, $file, $line
- );
- }
- /**
- * Log a message to the facility log
- *
- * @param string $message The log message
- * @param mixed $details Any details that should be added to the log entry
- * @param string $file A source filename if this is related to a source position
- * @param int $line A line number for the above file
- * @triggers LOGGER_DATA_FORMAT can be used to change the logged data or intercept it
- * @return bool has a log been written?
- */
- public function log($message, $details = null, $file = '', $line = 0)
- {
- global $EVENT_HANDLER;
- if (!$this->isLogging) return false;
- $datetime = time();
- $data = [
- 'facility' => $this->facility,
- 'datetime' => $datetime,
- 'message' => $message,
- 'details' => $details,
- 'file' => $file,
- 'line' => $line,
- 'loglines' => [],
- 'logfile' => $this->getLogfile($datetime),
- ];
- if ($EVENT_HANDLER !== null) {
- $event = new Event('LOGGER_DATA_FORMAT', $data);
- if ($event->advise_before()) {
- $data['loglines'] = $this->formatLogLines($data);
- }
- $event->advise_after();
- } else {
- // The event system is not yet available, to ensure the log isn't lost even on
- // fatal errors, the default action is executed
- $data['loglines'] = $this->formatLogLines($data);
- }
- // only log when any data available
- if (count($data['loglines'])) {
- return $this->writeLogLines($data['loglines'], $data['logfile']);
- } else {
- return false;
- }
- }
- /**
- * Is this logging instace actually logging?
- *
- * @return bool
- */
- public function isLogging()
- {
- return $this->isLogging;
- }
- /**
- * Formats the given data as loglines
- *
- * @param array $data Event data from LOGGER_DATA_FORMAT
- * @return string[] the lines to log
- */
- protected function formatLogLines($data)
- {
- extract($data);
- // details are logged indented
- if ($details) {
- if (!is_string($details)) {
- $details = json_encode($details, JSON_PRETTY_PRINT);
- }
- $details = explode("\n", $details);
- $loglines = array_map(function ($line) {
- return ' ' . $line;
- }, $details);
- } elseif ($details) {
- $loglines = [$details];
- } else {
- $loglines = [];
- }
- // datetime, fileline, message
- $logline = gmdate('Y-m-d H:i:s', $datetime) . "\t";
- if ($file) {
- $logline .= $file;
- if ($line) $logline .= "($line)";
- }
- $logline .= "\t" . $message;
- array_unshift($loglines, $logline);
- return $loglines;
- }
- /**
- * Construct the log file for the given day
- *
- * @param false|string|int $date Date to access, false for today
- * @return string
- */
- public function getLogfile($date = false)
- {
- global $conf;
- if ($date !== null && !is_numeric($date)) {
- $date = strtotime($date);
- }
- if (!$date) $date = time();
- return $conf['logdir'] . '/' . $this->facility . '/' . date('Y-m-d', $date) . '.log';
- }
- /**
- * Write the given lines to today's facility log
- *
- * @param string[] $lines the raw lines to append to the log
- * @param string $logfile where to write to
- * @return bool true if the log was written
- */
- protected function writeLogLines($lines, $logfile)
- {
- if (defined('DOKU_UNITTEST')) {
- fwrite(STDERR, "\n[" . $this->facility . '] ' . join("\n", $lines) . "\n");
- }
- return io_saveFile($logfile, join("\n", $lines) . "\n", true);
- }
- }
|