[ Index ] |
PHP Cross Reference of DokuWiki |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body