├── LICENSE ├── Logger.php └── README.md /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Lars 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Logger.php: -------------------------------------------------------------------------------- 1 | 'd-M-Y', 41 | 'logFormat' => 'H:i:s d-M-Y' 42 | ]; 43 | 44 | private static $instance; 45 | 46 | /** 47 | * Create the log file 48 | * @param string $log_file - path and filename of log 49 | * @param array $params - settable options 50 | */ 51 | public static function createLogFile() 52 | { 53 | $time = date(static::$options['dateFormat']); 54 | static::$log_file = __DIR__ . "/logs/log-{$time}.txt"; 55 | 56 | 57 | //Check if directory /logs exists 58 | if (!file_exists(__DIR__ . '/logs')) { 59 | mkdir(__DIR__ . '/logs', 0777, true); 60 | } 61 | 62 | //Create log file if it doesn't exist. 63 | if (!file_exists(static::$log_file)) { 64 | fopen(static::$log_file, 'w') or exit("Can't create {static::log_file}!"); 65 | } 66 | 67 | //Check permissions of file. 68 | if (!is_writable(static::$log_file)) { 69 | //throw exception if not writable 70 | throw new Exception("ERROR: Unable to write to file!", 1); 71 | } 72 | } 73 | 74 | /** 75 | * Set logging options (optional) 76 | * @param array $options Array of settable options 77 | * 78 | * Options: 79 | * [ 80 | * 'dateFormat' => 'value of the date format the .txt file should be saved int' 81 | * 'logFormat' => 'value of the date format each log event should be saved int' 82 | * ] 83 | */ 84 | public static function setOptions($options = []) 85 | { 86 | static::$options = array_merge(static::$options, $options); 87 | } 88 | 89 | /** 90 | * Info method (write info message) 91 | * 92 | * Used for e.g.: "The user example123 has created a post". 93 | * 94 | * @param string $message Descriptive text of the debug 95 | * @param string $context Array to expend the message's meaning 96 | * @return void 97 | */ 98 | public static function info($message, array $context = []) 99 | { 100 | // grab the line and file path where the log method has been executed ( for troubleshooting ) 101 | $bt = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1); 102 | 103 | //execute the writeLog method with passing the arguments 104 | static::writeLog([ 105 | 'message' => $message, 106 | 'bt' => $bt, 107 | 'severity' => 'INFO', 108 | 'context' => $context 109 | ]); 110 | } 111 | 112 | /** 113 | * Notice method (write notice message) 114 | * 115 | * Used for e.g.: "The user example123 has created a post". 116 | * 117 | * @param string $message Descriptive text of the debug 118 | * @param string $context Array to expend the message's meaning 119 | * @return void 120 | */ 121 | public static function notice($message, array $context = []) 122 | { 123 | // grab the line and file path where the log method has been executed ( for troubleshooting ) 124 | $bt = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1); 125 | 126 | //execute the writeLog method with passing the arguments 127 | static::writeLog([ 128 | 'message' => $message, 129 | 'bt' => $bt, 130 | 'severity' => 'NOTICE', 131 | 'context' => $context 132 | ]); 133 | } 134 | 135 | /** 136 | * Debug method (write debug message) 137 | * 138 | * Used for debugging, could be used instead of echo'ing values 139 | * 140 | * @param string $message Descriptive text of the debug 141 | * @param string $context Array to expend the message's meaning 142 | * @return void 143 | */ 144 | public static function debug($message, array $context = []) 145 | { 146 | 147 | // grab the line and file path where the log method has been executed ( for troubleshooting ) 148 | $bt = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1); 149 | 150 | //execute the writeLog method with passing the arguments 151 | static::writeLog([ 152 | 'message' => $message, 153 | 'bt' => $bt, 154 | 'severity' => 'DEBUG', 155 | 'context' => $context 156 | ]); 157 | } 158 | 159 | /** 160 | * Warning method (write warning message) 161 | * 162 | * Used for warnings which is not fatal to the current operation 163 | * 164 | * @param string $message Descriptive text of the warning 165 | * @param string $context Array to expend the message's meaning 166 | * @return void 167 | */ 168 | public static function warning($message, array $context = []) 169 | { 170 | // grab the line and file path where the log method has been executed ( for troubleshooting ) 171 | $bt = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1); 172 | 173 | //execute the writeLog method with passing the arguments 174 | static::writeLog([ 175 | 'message' => $message, 176 | 'bt' => $bt, 177 | 'severity' => 'WARNING', 178 | 'context' => $context 179 | ]); 180 | } 181 | 182 | /** 183 | * Error method (write error message) 184 | * 185 | * Used for e.g. file not found,... 186 | * 187 | * @param string $message Descriptive text of the error 188 | * @param string $context Array to expend the message's meaning 189 | * @return void 190 | */ 191 | public static function error($message, array $context = []) 192 | { 193 | // grab the line and file path where the log method has been executed ( for troubleshooting ) 194 | $bt = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1); 195 | 196 | //execute the writeLog method with passing the arguments 197 | static::writeLog([ 198 | 'message' => $message, 199 | 'bt' => $bt, 200 | 'severity' => 'ERROR', 201 | 'context' => $context 202 | ]); 203 | } 204 | 205 | /** 206 | * Fatal method (write fatal message) 207 | * 208 | * Used for e.g. database unavailable, system shutdown 209 | * 210 | * @param string $message Descriptive text of the error 211 | * @param string $context Array to expend the message's meaning 212 | * @return void 213 | */ 214 | public static function fatal($message, array $context = []) 215 | { 216 | // grab the line and file path where the log method has been executed ( for troubleshooting ) 217 | $bt = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1); 218 | 219 | //execute the writeLog method with passing the arguments 220 | static::writeLog([ 221 | 'message' => $message, 222 | 'bt' => $bt, 223 | 'severity' => 'FATAL', 224 | 'context' => $context 225 | ]); 226 | } 227 | 228 | /** 229 | * Write to log file 230 | * @param array $args Array of message (for log file), line (of log method execution), severity (for log file) and displayMessage (to display on frontend for the used) 231 | * @return void 232 | */ 233 | // public function writeLog($message, $line = null, $displayMessage = null, $severity) 234 | public static function writeLog($args = []) 235 | { 236 | //Create the log file 237 | static::createLogFile(); 238 | 239 | // open log file 240 | if (!is_resource(static::$file)) { 241 | static::openLog(); 242 | } 243 | 244 | // // grab the url path 245 | // $path = $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"]; 246 | 247 | //Grab time - based on the time format 248 | $time = date(static::$options['logFormat']); 249 | 250 | // Convert context to json 251 | $context = json_encode($args['context']); 252 | 253 | $caller = array_shift($args['bt']); 254 | $btLine = $caller['line']; 255 | $btPath = $caller['file']; 256 | 257 | // Convert absolute path to relative path (using UNIX directory seperators) 258 | $path = static::absToRelPath($btPath); 259 | 260 | // Create log variable = value pairs 261 | $timeLog = is_null($time) ? "[N/A] " : "[{$time}] "; 262 | $pathLog = is_null($path) ? "[N/A] " : "[{$path}] "; 263 | $lineLog = is_null($btLine) ? "[N/A] " : "[{$btLine}] "; 264 | $severityLog = is_null($args['severity']) ? "[N/A]" : "[{$args['severity']}]"; 265 | $messageLog = is_null($args['message']) ? "N/A" : "{$args['message']}"; 266 | $contextLog = empty($args['context']) ? "" : "{$context}"; 267 | 268 | // Write time, url, & message to end of file 269 | fwrite(static::$file, "{$timeLog}{$pathLog}{$lineLog}: {$severityLog} - {$messageLog} {$contextLog}" . PHP_EOL); 270 | 271 | // Close file stream 272 | static::closeFile(); 273 | } 274 | 275 | /** 276 | * Open log file 277 | * @return void 278 | */ 279 | private static function openLog() 280 | { 281 | $openFile = static::$log_file; 282 | // 'a' option = place pointer at end of file 283 | static::$file = fopen($openFile, 'a') or exit("Can't open $openFile!"); 284 | } 285 | 286 | /** 287 | * Close file stream 288 | */ 289 | public static function closeFile() 290 | { 291 | if (static::$file) { 292 | fclose(static::$file); 293 | } 294 | } 295 | 296 | /** 297 | * Convert absolute path to relative url (using UNIX directory seperators) 298 | * 299 | * E.g.: 300 | * Input: D:\development\htdocs\public\todo-list\index.php 301 | * Output: localhost/todo-list/index.php 302 | * 303 | * @param string Absolute directory/path of file which should be converted to a relative (url) path 304 | * @return string Relative path 305 | */ 306 | public static function absToRelPath($pathToConvert) 307 | { 308 | $pathAbs = str_replace(['/', '\\'], '/', $pathToConvert); 309 | $documentRoot = str_replace(['/', '\\'], '/', $_SERVER['DOCUMENT_ROOT']); 310 | return ($_SERVER['SERVER_NAME'] ?? 'cli') . str_replace($documentRoot, '', $pathAbs); 311 | } 312 | 313 | /** 314 | * The Singleton's constructor should always be private to prevent direct 315 | * construction calls with the `new` operator. 316 | */ 317 | protected function __construct() 318 | { } 319 | 320 | /** 321 | * Singletons should not be cloneable. 322 | */ 323 | protected function __clone() 324 | { } 325 | 326 | /** 327 | * Singletons should not be restorable from strings. 328 | */ 329 | public function __wakeup() 330 | { 331 | throw new \Exception("Cannot unserialize a singleton."); 332 | } 333 | 334 | public static function getInstance() 335 | { 336 | if (is_null(self::$instance)) { 337 | self::$instance = new self(); 338 | } 339 | return self::$instance; 340 | } 341 | 342 | /** 343 | * The Singleton's constructor should always be private to prevent direct 344 | * construction calls with the `new` operator. 345 | */ 346 | private function __destruct() 347 | { } 348 | } 349 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # :floppy_disk: Simple PHP Logger :floppy_disk: 2 | ![License MIT](https://img.shields.io/github/license/advename/Simple-PHP-Logger) 3 | 4 | *Simple php logger* is a single file PHP log writer which writes logs into a .txt file using one line of code, e.g. 5 | ```php 6 | Logger::info("I'm an info message"); 7 | ``` 8 | outputs inside a *log-28-nov-2019.txt*: 9 | ``` 10 | [22:50:35 28-Nov-2019] [localhost/test.php] [1] : [INFO] - I'm an info message 11 | ``` 12 | 13 | #### Features 14 | - single file 15 | - singleton pattern 16 | - six log levels (info, notice, debug, warning, error, fatal) 17 | - logs the line where the `Logger` method is executed (good for troubleshooting) 18 | - logs the relative filepath of the source file, not the required one (good for troubleshooting) 19 | 20 | ### :wrench: Motivation 21 | There are many PHP Logger's out there, but most of them are either very heavy or too basic. Sometimes, you simply want something in the middle, suitable for every situation and project size. Therefore, I've decided to create a simple PHP Logger, inspired by several other logging libraries. 22 | 23 | ### :white_check_mark: Installation 24 | Simply download the Logger.php file and require it wherever you need it. 25 | You can also insert it into a *Log* directory and add a namespace to it, for those who want to use it within an OOP project 26 | Make sure that the `logs/` directory exists and is writable, else the logger throws an error that it cant read/write/create the log files. 27 | 28 | ### :mag_right: Log levels 29 | The simple php logger uses six log levels: 30 | 31 | |Level |Description | Example | 32 | |---|---|---| 33 | | INFO | Used for general informations | "The server has been running X hours" | 34 | | NOTICE | Used for interesting events | "The user $userName has logged in." | 35 | | DEBUG | Used for debugging | Could be used instead of echo'ing values | 36 | | WARNING | Used for anything that might/ might not be a problem. | "The image XX is 30MB big. This can cause slow web performance" | 37 | | ERROR | Any error which is fatal to the operation, but not shutting down the application| Can't open a required file, missing data, etc. | 38 | | FATAL | Any error which is shutting down the application| Database unavailable | 39 | 40 | ### :books: How to use 41 | 42 | #### Basic example 43 | Here's a basic example how you could use simple php logger 44 | ```php 45 | getMessage()]); // <- Log a fatal error with details 60 | 61 | die("Oh snap, looks like something didn't work. Please retry again later"); // <- UX friendly die() message 62 | } 63 | } 64 | ``` 65 | 66 | #### Logging methods 67 | ```php 68 | 'Y-M-d H:i:s' 100 | ]); 101 | ``` 102 | 103 | **Logger outputs** 104 | ```codes 105 | [15:45:33 27-Nov-2019] [localhost/test.php] [4] : [INFO]- The article XX has YY comments 106 | [15:45:33 27-Nov-2019] [localhost/test.php] [8] : [NOTICE]- The user XX has created the YY article 107 | [15:45:33 27-Nov-2019] [localhost/test.php] [12] : [DEBUG]- This is where the code breaks 108 | [15:45:33 27-Nov-2019] [localhost/test.php] [16] : [WARNING]- The file XX is 100GB big 109 | [15:45:33 27-Nov-2019] [localhost/test.php] [19] : [ERROR]- The file XX is missing 110 | [15:45:33 27-Nov-2019] [localhost/test.php] [23] : [FATAL]- Database connection failed ["Very bad database","I didnt feed him"] 111 | ``` 112 | 113 | ##### Note 114 | **Big thanks to** reddit user [u/mferly](https://www.reddit.com/user/mferly) for his support and guidance! 115 | 116 | This logger is not a replacement for a PSR-3 compliant logger library such as [Monolog](https://github.com/Seldaek/monolog), [KLogger](https://github.com/katzgrau/KLogger) or [Analog](https://github.com/jbroadway/analog). This Logger should simply be used to quickly implement a simple logger with several methods. 117 | 118 | **Inspired by** 119 | - [Simple PHP Text Logging Class \| drew.d.lenhart](https://www.drewlenhart.com/blog/simple-php-logger-class) 120 | - [PSR-3](https://www.php-fig.org/psr/psr-3/) 121 | --------------------------------------------------------------------------------