File modules/logger/Logger.class.php
Last commit: Fri Feb 26 00:04:49 2021 +0100 Jan Dankert New: Request may contain JSON,XML in POST data. This is good for API clients.
1 <?php 2 3 namespace logger; 4 5 use Exception; 6 use util\json\JSON; 7 use util\Text; 8 9 /** 10 * Writing log messages into a log file. 11 * 12 * @author Jan Dankert 13 */ 14 class Logger 15 { 16 const LEVEL_TRACE = 5; 17 const LEVEL_DEBUG = 4; 18 const LEVEL_INFO = 3; 19 const LEVEL_WARN = 2; 20 const LEVEL_ERROR = 1; 21 22 const OUTPUT_PLAIN = 1; 23 const OUTPUT_JSON = 2; 24 25 const LOG_TO_FILE = 1; 26 const LOG_TO_STDOUT = 2; 27 const LOG_TO_STDERR = 4; 28 const LOG_TO_ERROR_LOG = 8; 29 30 31 public static $level = self::LEVEL_ERROR; 32 public static $filename = null; 33 public static $logto = self::LOG_TO_ERROR_LOG; 34 35 public static $messageFormat = ['time','level','host','text']; 36 public static $dateFormat = 'r'; 37 public static $nsLookup = false; 38 /** 39 * @var null | callable 40 */ 41 public static $messageCallback = null; 42 public static $outputType = self::OUTPUT_PLAIN; 43 44 public static function init() 45 { 46 } 47 48 49 /** 50 * Writes a trace message to log 51 * 52 * @param string|Exception message text 53 */ 54 public static function trace($message) 55 { 56 Logger::doLog(self::LEVEL_TRACE, $message); 57 } 58 59 60 /** 61 * Is trace enabled? 62 * @return bool 63 */ 64 public static function isTraceEnabled() { 65 return Logger::$level >= self::LEVEL_TRACE; 66 } 67 68 /** 69 * Writes a debug message to log 70 * 71 * @param string|Exception message text 72 */ 73 public static function debug($message) 74 { 75 Logger::doLog(self::LEVEL_DEBUG, $message); 76 } 77 78 79 /** 80 * Writes a information message to log 81 * 82 * @param string|Exception message text 83 */ 84 public static function info($message) 85 { 86 Logger::doLog(self::LEVEL_INFO, $message); 87 } 88 89 90 /** 91 * Writes a warning message to log 92 * 93 * @param string|Exception message text 94 */ 95 public static function warn($message) 96 { 97 Logger::doLog(self::LEVEL_WARN, $message); 98 } 99 100 101 /** 102 * Writes an error message to log 103 * 104 * @param string|Exception message text 105 */ 106 public static function error($message) 107 { 108 Logger::doLog(self::LEVEL_ERROR, $message); 109 } 110 111 112 /** 113 * Writes a mesage into the log file 114 * 115 * @param string facility of log entry 116 * @param string|Throwable message text 117 */ 118 private static function doLog($facility, $message) 119 { 120 if ( Logger::$level < $facility ) 121 return; // log level not reached. 122 123 if ($facility == self::LEVEL_ERROR) 124 $levelName = 'ERROR'; 125 elseif ($facility == self::LEVEL_WARN) 126 $levelName = 'WARN'; 127 elseif ($facility == self::LEVEL_INFO) 128 $levelName = 'INFO'; 129 elseif ($facility == self::LEVEL_DEBUG) 130 $levelName = 'DEBUG'; 131 elseif ($facility == self::LEVEL_TRACE) 132 $levelName = 'TRACE'; 133 else 134 $levelName = ''; 135 136 if ($message instanceof Exception) 137 $message = $message->getMessage()."\n".$message->__toString(); 138 139 $values = array_map( function($key) use ($message, $levelName) { 140 switch( $key ) { 141 case 'host': 142 if (Logger::$nsLookup) 143 return gethostbyaddr(getenv('REMOTE_ADDR')); 144 else 145 return getenv('REMOTE_ADDR'); 146 147 case 'level': 148 return str_pad($levelName, 5); 149 case 'agent': 150 return getenv('HTTP_USER_AGENT'); 151 case 'time': 152 return date(Logger::$dateFormat); 153 case 'text': 154 return $message; 155 156 default: 157 if ( Logger::$messageCallback ) 158 return call_user_func(Logger::$messageCallback,$key); 159 return ''; 160 } 161 }, array_combine(Logger::$messageFormat,Logger::$messageFormat) ); 162 163 switch( self::$outputType ) { 164 case self::OUTPUT_PLAIN: 165 default: 166 167 $text = ''; 168 foreach( $values as $value ) { 169 if ( ! $value ) 170 $value = '-'; 171 172 if ( $text ) 173 $text = $text . ' '; 174 175 $text .= '"'.str_replace('"','\"',$value).'"'; 176 } 177 178 // Mehrzeilige Meldungen werden um 1 Spalte eingerueckt, um sie maschinell 179 // erkennen und auswerten zu koennen. 180 $text = str_replace("\n", "\n ", $text); 181 break; 182 183 case self::OUTPUT_JSON: 184 $text = JSON::encode( $values ); 185 $text = str_replace("\n", "", $text); 186 break; 187 } 188 189 $text .= "\n"; 190 191 if ( Logger::$logto & self::LOG_TO_FILE ) { 192 193 // Is the file writable? 194 // Exception: Streams (like php://stdout) are never 'writable' :/ 195 if ( Logger::$filename && is_writable( Logger::$filename ) ) { 196 // Writing to the logfile 197 $result = file_put_contents( Logger::$filename,$text, FILE_APPEND ); 198 199 if ( $result === FALSE ) 200 error_log('could not write to logfile ' . Logger::$filename ); 201 } else { 202 error_log('logfile ' . Logger::$filename . ' is not writable'); 203 } 204 } 205 206 if ( Logger::$logto & self::LOG_TO_ERROR_LOG ) { 207 error_log( $text ); 208 } 209 if ( Logger::$logto & self::LOG_TO_STDERR ) { 210 file_put_contents( 'php://stderr', $text, FILE_APPEND ); 211 } 212 if ( Logger::$logto & self::LOG_TO_STDOUT ) { 213 file_put_contents( 'php://stdout', $text, FILE_APPEND ); 214 } 215 216 } 217 218 }
Downloadmodules/logger/Logger.class.php
History Fri, 26 Feb 2021 00:04:49 +0100 Jan Dankert New: Request may contain JSON,XML in POST data. This is good for API clients. Thu, 19 Nov 2020 22:43:33 +0100 Jan Dankert New: Configure separate logging endpoints (file, syslog, stdout, stderr), so docker container may write directly to stdout. Thu, 19 Nov 2020 19:51:26 +0100 Jan Dankert Fix: Using a stream for log output (like php://stdout) Thu, 19 Nov 2020 17:59:57 +0100 Jan Dankert New: Control log level with environment variables. Mon, 26 Oct 2020 22:21:42 +0100 Jan Dankert Refactoring: Using TextMessage for creating Messages with user content. Sat, 26 Sep 2020 01:41:20 +0200 Jan Dankert Refactoring: Removing old require.php files. With class autoloading, they are not necessary any more. Fri, 25 Sep 2020 23:37:38 +0200 Jan Dankert Refactoring: The logger is able to output json format (for cloud installations) Tue, 18 Aug 2020 23:27:37 +0200 Jan Dankert Security: Sanitize user input while logging (no logfile injection with potentially dangerous data) Sun, 23 Feb 2020 00:03:40 +0100 Jan Dankert Refactoring: Namespaces for modules 'logger' and 'language' Sat, 1 Dec 2018 01:07:57 +0100 Jan Dankert Anzeige der Notices kann jetzt auch Stacktraces anzeigen. Fri, 29 Dec 2017 01:35:50 +0100 Jan Dankert Großes Refactoring: Neues Modul CMS-UI. Dieses enthält sämtliche Logik für die Bedienoberfläche. TODO: Modul CMS-API. Mon, 11 Dec 2017 23:19:39 +0100 Jan Dankert Den Logger in ein eigenes Modul verpackt. Der Logger hat nun keine Abhängigkeiten mehr zum CMS.