Signed-off-by: Patrick Niebeling <patrick.niebeling@adacor.com>
This commit is contained in:
Patrick Niebeling
2022-03-10 09:36:09 +01:00
commit 54b3776313
3 changed files with 483 additions and 0 deletions

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Lars
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

349
Logger.php Normal file
View File

@ -0,0 +1,349 @@
<?php
/**
* @author gnilebein
* @since March 10, 2022
* @link https://gitea.gnilebein.de/gnilebein/Simple-PHP-Logger
* @license MIT
* @version 1.0.0
*
* Description:
* The simple php logger is a single-file logwriter with the features of:
* - single file
* - singleton pattern
* - six log levels (info, notice, debug, warning, error, fatal)
* - logs the line where the Logger method is executed (good for troubleshooting)
* - logs the relative filepath of the source file, not the required one (good for troubleshooting)
*
*/
class Logger
{
/**
* $log_file - path and log file name
* @var string
*/
protected static $log_file;
/**
* $file - file
* @var string
*/
protected static $file;
/**
* $options - settable options
* @var array $dateFormat of the format used for the log.txt file; $logFormat used for the time of a single log event
*/
protected static $options = [
'dateFormat' => 'd-M-Y',
'logFormat' => 'H:i:s d-M-Y',
'logFile' => '/logs/log-{$time}.txt'
];
private static $instance;
/**
* Create the log file
* @param string $log_file - path and filename of log
* @param array $params - settable options
*/
public static function createLogFile()
{
$time = date(static::$options['dateFormat']);
static::$log_file = __DIR__ . static::$options['logFile'];
//Check if directory /logs exists
if (!file_exists(__DIR__ . '/logs')) {
mkdir(__DIR__ . '/logs', 0777, true);
}
//Create log file if it doesn't exist.
if (!file_exists(static::$log_file)) {
fopen(static::$log_file, 'w') or exit("Can't create {static::log_file}!");
}
//Check permissions of file.
if (!is_writable(static::$log_file)) {
//throw exception if not writable
throw new Exception("ERROR: Unable to write to file!", 1);
}
}
/**
* Set logging options (optional)
* @param array $options Array of settable options
*
* Options:
* [
* 'dateFormat' => 'value of the date format the .txt file should be saved int'
* 'logFormat' => 'value of the date format each log event should be saved int'
* ]
*/
public static function setOptions($options = [])
{
static::$options = array_merge(static::$options, $options);
}
/**
* Info method (write info message)
*
* Used for e.g.: "The user example123 has created a post".
*
* @param string $message Descriptive text of the debug
* @param string $context Array to expend the message's meaning
* @return void
*/
public static function info($message, array $context = [])
{
// grab the line and file path where the log method has been executed ( for troubleshooting )
$bt = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1);
//execute the writeLog method with passing the arguments
static::writeLog([
'message' => $message,
'bt' => $bt,
'severity' => 'INFO',
'context' => $context
]);
}
/**
* Notice method (write notice message)
*
* Used for e.g.: "The user example123 has created a post".
*
* @param string $message Descriptive text of the debug
* @param string $context Array to expend the message's meaning
* @return void
*/
public static function notice($message, array $context = [])
{
// grab the line and file path where the log method has been executed ( for troubleshooting )
$bt = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1);
//execute the writeLog method with passing the arguments
static::writeLog([
'message' => $message,
'bt' => $bt,
'severity' => 'NOTICE',
'context' => $context
]);
}
/**
* Debug method (write debug message)
*
* Used for debugging, could be used instead of echo'ing values
*
* @param string $message Descriptive text of the debug
* @param string $context Array to expend the message's meaning
* @return void
*/
public static function debug($message, array $context = [])
{
// grab the line and file path where the log method has been executed ( for troubleshooting )
$bt = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1);
//execute the writeLog method with passing the arguments
static::writeLog([
'message' => $message,
'bt' => $bt,
'severity' => 'DEBUG',
'context' => $context
]);
}
/**
* Warning method (write warning message)
*
* Used for warnings which is not fatal to the current operation
*
* @param string $message Descriptive text of the warning
* @param string $context Array to expend the message's meaning
* @return void
*/
public static function warning($message, array $context = [])
{
// grab the line and file path where the log method has been executed ( for troubleshooting )
$bt = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1);
//execute the writeLog method with passing the arguments
static::writeLog([
'message' => $message,
'bt' => $bt,
'severity' => 'WARNING',
'context' => $context
]);
}
/**
* Error method (write error message)
*
* Used for e.g. file not found,...
*
* @param string $message Descriptive text of the error
* @param string $context Array to expend the message's meaning
* @return void
*/
public static function error($message, array $context = [])
{
// grab the line and file path where the log method has been executed ( for troubleshooting )
$bt = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1);
//execute the writeLog method with passing the arguments
static::writeLog([
'message' => $message,
'bt' => $bt,
'severity' => 'ERROR',
'context' => $context
]);
}
/**
* Fatal method (write fatal message)
*
* Used for e.g. database unavailable, system shutdown
*
* @param string $message Descriptive text of the error
* @param string $context Array to expend the message's meaning
* @return void
*/
public static function fatal($message, array $context = [])
{
// grab the line and file path where the log method has been executed ( for troubleshooting )
$bt = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1);
//execute the writeLog method with passing the arguments
static::writeLog([
'message' => $message,
'bt' => $bt,
'severity' => 'FATAL',
'context' => $context
]);
}
/**
* Write to log file
* @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)
* @return void
*/
// public function writeLog($message, $line = null, $displayMessage = null, $severity)
public static function writeLog($args = [])
{
//Create the log file
static::createLogFile();
// open log file
if (!is_resource(static::$file)) {
static::openLog();
}
// // grab the url path
// $path = $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"];
//Grab time - based on the time format
$time = date(static::$options['logFormat']);
// Convert context to json
$context = json_encode($args['context']);
$caller = array_shift($args['bt']);
$btLine = $caller['line'];
$btPath = $caller['file'];
// Convert absolute path to relative path (using UNIX directory seperators)
$path = static::absToRelPath($btPath);
// Create log variable = value pairs
$timeLog = is_null($time) ? "[N/A] " : "[{$time}] ";
$pathLog = is_null($path) ? "[N/A] " : "[{$path}] ";
$lineLog = is_null($btLine) ? "[N/A] " : "[{$btLine}] ";
$severityLog = is_null($args['severity']) ? "[N/A]" : "[{$args['severity']}]";
$messageLog = is_null($args['message']) ? "N/A" : "{$args['message']}";
$contextLog = empty($args['context']) ? "" : "{$context}";
// Write time, url, & message to end of file
fwrite(static::$file, "{$timeLog}{$pathLog}{$lineLog}: {$severityLog} - {$messageLog} {$contextLog}" . PHP_EOL);
// Close file stream
static::closeFile();
}
/**
* Open log file
* @return void
*/
private static function openLog()
{
$openFile = static::$log_file;
// 'a' option = place pointer at end of file
static::$file = fopen($openFile, 'a') or exit("Can't open $openFile!");
}
/**
* Close file stream
*/
public static function closeFile()
{
if (static::$file) {
fclose(static::$file);
}
}
/**
* Convert absolute path to relative url (using UNIX directory seperators)
*
* E.g.:
* Input: D:\development\htdocs\public\todo-list\index.php
* Output: localhost/todo-list/index.php
*
* @param string Absolute directory/path of file which should be converted to a relative (url) path
* @return string Relative path
*/
public static function absToRelPath($pathToConvert)
{
$pathAbs = str_replace(['/', '\\'], '/', $pathToConvert);
$documentRoot = str_replace(['/', '\\'], '/', $_SERVER['DOCUMENT_ROOT']);
return $_SERVER['SERVER_NAME'] . str_replace($documentRoot, '', $pathAbs);
}
/**
* The Singleton's constructor should always be private to prevent direct
* construction calls with the `new` operator.
*/
protected function __construct()
{ }
/**
* Singletons should not be cloneable.
*/
protected function __clone()
{ }
/**
* Singletons should not be restorable from strings.
*/
public function __wakeup()
{
throw new \Exception("Cannot unserialize a singleton.");
}
public static function getInstance()
{
if (is_null(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
/**
* The Singleton's constructor should always be private to prevent direct
* construction calls with the `new` operator.
*/
private function __destruct()
{ }
}

113
README.md Normal file
View File

@ -0,0 +1,113 @@
# :floppy_disk: Simple PHP Logger :floppy_disk:
*Simple php logger* is a single file PHP log writer which writes logs into a .txt file using one line of code, e.g.
```php
Logger::info("I'm an info message");
```
outputs inside a *log-28-nov-2019.txt*:
```
[22:50:35 28-Nov-2019] [localhost/test.php] [1] : [INFO] - I'm an info message
```
#### Features
- single file
- singleton pattern
- six log levels (info, notice, debug, warning, error, fatal)
- logs the line where the `Logger` method is executed (good for troubleshooting)
- logs the relative filepath of the source file, not the required one (good for troubleshooting)
### :wrench: Motivation
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.
### :white_check_mark: Installation
Simply download the Logger.php file and require it wherever you need it.
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
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.
### :mag_right: Log levels
The simple php logger uses six log levels:
|Level |Description | Example |
|---|---|---|
| INFO | Used for general informations | "The server has been running X hours" |
| NOTICE | Used for interesting events | "The user $userName has logged in." |
| DEBUG | Used for debugging | Could be used instead of echo'ing values |
| WARNING | Used for anything that might/ might not be a problem. | "The image XX is 30MB big. This can cause slow web performance" |
| ERROR | Any error which is fatal to the operation, but not shutting down the application| Can't open a required file, missing data, etc. |
| FATAL | Any error which is shutting down the application| Database unavailable |
### :books: How to use
#### Basic example
Here's a basic example how you could use simple php logger
```php
<?php
include_once(Logger.php');
function connectToDatabase()
{
$dbhost = 'localhost';
$dbname = 'post_website';
$dbuser = 'root';
$dbport = '3306';
$dbpass = '';
try {
$pdo = new PDO("mysql:host=$dbhost;port=$dbport;dbname=$dbname", $dbuser, $dbpass);
} catch (PDOException $e) {
Logger::fatal("Database connection failed", [$e->getMessage()]); // <- Log a fatal error with details
die('Oh snap, looks like something didn't work. Please retry again later'); // <- UX friendly die() message
}
}
```
#### Logging methods
```php
<?php
// Info log
Logger::info("The article XX has YY comments");
// Notice log
Logger::notice("The user XX has created the YY article");
// Debug log
Logger::debug("This is where the code breaks");
// Warning log
// $file would be a e.g. data about an image received from a POST request
Logger::debug("The file XX is 100GB big", $file);
// Error log
Logger::error("The file XX is missing");
// Fatal log
$information = ["Very bad database", "I didnt feed him"];
Logger::error("Database connection failed", $information);
```
### :book: Log output
The simple php logger outputs the logs in the following blueprint:
```
[Hour:Minutes:Seconds Date-Month-Yearh] [file-path] [line-of-execution] : [Log level] Descriptive message (optional = The array/object of additional information)
```
You can change the default time output using the `setOptions()` method.
```codes
Logger::setOptions([
'logFormat' => 'Y-M-d H:i:s'
]);
```
**Logger outputs**
```codes
[15:45:33 27-Nov-2019] [localhost/test.php] [4] : [INFO]- The article XX has YY comments
[15:45:33 27-Nov-2019] [localhost/test.php] [8] : [NOTICE]- The user XX has created the YY article
[15:45:33 27-Nov-2019] [localhost/test.php] [12] : [DEBUG]- This is where the code breaks
[15:45:33 27-Nov-2019] [localhost/test.php] [16] : [WARNING]- The file XX is 100GB big
[15:45:33 27-Nov-2019] [localhost/test.php] [19] : [ERROR]- The file XX is missing
[15:45:33 27-Nov-2019] [localhost/test.php] [23] : [FATAL]- Database connection failed ["Very bad database","I didnt feed him"]
```
##### Note
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.