Refactored Project, various changes and bug fixes. Implemented file logging

This commit is contained in:
Netkas 2022-12-22 18:02:41 -05:00
parent 55ec27903f
commit 09141f3d10
16 changed files with 1007 additions and 316 deletions

4
.idea/php.xml generated
View file

@ -11,8 +11,10 @@
</component>
<component name="PhpIncludePathManager">
<include_path>
<path value="/usr/share/php" />
<path value="/etc/ncc" />
<path value="/var/ncc/packages/net.nosial.optslib=1.0.0" />
<path value="/var/ncc/packages/net.nosial.optslib=1.0.1" />
<path value="/var/ncc/packages/net.nosial.properties=1.0.1" />
</include_path>
</component>
<component name="PhpProjectSharedConfiguration" php_language_level="8.2" />

View file

@ -5,10 +5,10 @@ release:
ncc build --config="release"
install:
ncc package install --package="build/release/net.nosial.loglib.ncc"
ncc package install --package="build/release/net.nosial.loglib.ncc" --skip-dependencies --reinstall -y
install-debug:
ncc package install --package="build/debug/net.nosial.loglib.ncc"
ncc package install --package="build/debug/net.nosial.loglib.ncc" --skip-dependencies --reinstall -y
uninstall:
ncc package uninstall -y --package="net.nosial.loglib"

View file

@ -1,3 +1,29 @@
# LogLib
A logging library for PHP.
A logging library for PHP/ncc, this was quickly thrown together
to provide a simple logging interface and to test out
NCC's capabilities for PHP.
## Getting started
First
### building
```bash
$ git clone https://git.n64.cc/nosial/libs/loglib.git
$ cd loglib
$ ncc build --config release
# or
$ make release
```
### installing
```bash
$ sudo ncc install -p="build/release/net.nosial.loglib.ncc"
# or
$ sudo make install
```

View file

@ -5,6 +5,15 @@
"minimum_version": "8.0",
"maximum_version": "8.2"
},
"update_source": {
"source": "nosial/libs.log@n64",
"repository": {
"name": "n64",
"type": "gitlab",
"host": "git.n64.cc",
"ssl": true
}
},
"options": []
},
"assembly": {
@ -24,6 +33,20 @@
"ASSEMBLY_VERSION": "%ASSEMBLY.VERSION%",
"ASSEMBLY_UID": "%ASSEMBLY.UID%"
},
"dependencies": [
{
"name": "net.nosial.optslib",
"version": "latest",
"source_type": "remote",
"source": "nosial/libs.opts=latest@n64"
},
{
"name": "net.nosial.properties",
"version": "latest",
"source_type": "remote",
"source": "nosial/libs.properties=latest@n64"
}
],
"configurations": [
{
"name": "debug",

View file

@ -40,4 +40,15 @@
self::LightGray,
self::White
];
/**
* A list of random usable bright colors
*/
const BrightColors = [
self::LightBlue,
self::LightGreen,
self::LightCyan,
self::LightRed,
self::LightPurple,
];
}

View file

@ -6,6 +6,7 @@
use LogLib\Abstracts\ConsoleColors;
use LogLib\Abstracts\LevelType;
use LogLib\Log;
use LogLib\Objects\Event;
use LogLib\Objects\Options;
@ -24,13 +25,17 @@
*/
private static function formatAppColor(string $application): string
{
if(!Log::getRuntimeOptions()->isDisplayAnsi())
return $application;
if(!isset(self::$ApplicationColors[$application]))
{
$colors = ConsoleColors::All;
$colors = ConsoleColors::BrightColors;
$color = $colors[array_rand($colors)];
self::$ApplicationColors[$application] = $color;
}
return self::$ApplicationColors[$application];
return self::color($application, self::$ApplicationColors[$application]);
}
/**
@ -42,7 +47,10 @@
*/
private static function color(string $text, string $color): string
{
return "\033[{$color}m$text\033[0m";
if(!Log::getRuntimeOptions()->isDisplayAnsi())
return $text;
return "\033[" . $color . "m" . $text . "\033[0m";
}
/**
@ -54,6 +62,9 @@
*/
private static function colorize(Event $event, string $text): string
{
if(!Log::getRuntimeOptions()->isDisplayAnsi())
return Utilities::levelToString($text);
$color = null;
switch($event->Level)
{
@ -83,46 +94,6 @@
return self::color(Utilities::levelToString($text), $color);
}
/**
* Returns the formatted backtrace
*
* @param Event $event
* @return string|null
*/
private static function parseBacktrace(Event $event): ?string
{
$backtrace = null;
if($event->Backtrace !== null && count($event->Backtrace) > 0)
{
foreach($event->Backtrace as $item)
{
if($item->Class !== 'LogLib\\Log')
{
$backtrace = $item;
break;
}
}
}
$backtrace_output = null;
if($backtrace !== null)
{
if($backtrace->Class !== null)
{
$backtrace_output = $backtrace->Class . $backtrace->Type . $backtrace->Function . '()';
}
else
{
$backtrace_output = $backtrace->Function . '()';
}
if($backtrace->Line !== null)
$backtrace_output .= ':' . $backtrace->Line;
}
return $backtrace_output;
}
/**
* Regular console output for the event object
*
@ -132,61 +103,35 @@
*/
public static function out(Options $options, Event $event): void
{
// If the current level is verbose or higher, then we need to output the backtrace
if(Validate::checkLevelType(LevelType::Verbose, $options->getOutputLevel()))
{
$backtrace_output = self::parseBacktrace($event);
if(!Utilities::runningInCli())
return;
if($options->isConsoleAnsiColors())
{
print(sprintf(
"%s [%s] [%s] (%s) - %s" . PHP_EOL,
$event->getTimestamp(),
self::formatAppColor($options->getApplicationName()),
self::colorize($event, $event->Level),
$backtrace_output !== null ? $backtrace_output : 'λ',
$event->Message
));
}
else
{
print(sprintf(
"%s [%s] [%s] - %s - %s" . PHP_EOL,
$event->getTimestamp(), $options->getApplicationName(), $event->Level,
$backtrace_output !== null ? $backtrace_output : 'lambda',
$event->Message
));
}
if(Validate::checkLevelType(LevelType::Verbose, Log::getRuntimeOptions()->getLogLevel()))
{
$backtrace_output = Utilities::parseBacktrace($event);
print(sprintf(
"%s [%s] [%s] (%s) - %s" . PHP_EOL,
$event->getTimestamp(),
self::formatAppColor($options->getApplicationName()),
self::colorize($event, $event->Level),
$backtrace_output !== null ? $backtrace_output : 'λ',
$event->Message
));
if($event->Exception !== null)
self::outException($event->Exception);
}
elseif(!Validate::checkLevelType(LevelType::Fatal, $options->getOutputLevel()))
{
if($options->isConsoleAnsiColors())
{
print(sprintf(
"%s [%s] [%s] - %s" . PHP_EOL,
$event->getTimestamp(),
self::formatAppColor($options->getApplicationName()),
self::colorize($event, $event->Level),
$event->Message
));
}
else
{
print(sprintf(
"%s [%s] [%s] - %s" . PHP_EOL,
$event->getTimestamp(), $options->getApplicationName(), $event->Level,
$event->Message
));
}
if($event->Exception !== null)
self::outException($event->Exception);
return;
}
print(sprintf(
"%s [%s] [%s] - %s" . PHP_EOL,
$event->getTimestamp(),
self::formatAppColor($options->getApplicationName()),
self::colorize($event, $event->Level),
$event->Message
));
}
/**

View file

@ -0,0 +1,84 @@
<?php
namespace LogLib\Classes;
use LogLib\Abstracts\LevelType;
use LogLib\Log;
use LogLib\Objects\Event;
use LogLib\Objects\FileLogging\FileHandle;
use LogLib\Objects\Options;
use ncc\Utilities\Functions;
class FileLogging
{
/**
* Writes the event to the file log
*
* @param Options $options
* @param Event $event
* @param FileHandle|null $fileHandle
* @return void
*/
public static function out(Options $options, Event $event, ?FileHandle $fileHandle=null): void
{
$backtrace_output = Utilities::parseBacktrace($event);
$handle = $fileHandle ?? $options->getFileHandle();
switch($event->Level)
{
// Only process Debug/Verbose events if the log level is set to Debug/Verbose
// otherwise omit it because it could be a performance hit if there are a lot of
// debug/verbose events being logged.
case LevelType::Debug:
case LevelType::Verbose:
if(!Validate::checkLevelType($event->Level, Log::getRuntimeOptions()->getLogLevel()))
return;
break;
default:
break;
}
$handle->fwrite(sprintf(
"%s [%s] [%s] (%s) - %s" . PHP_EOL,
$event->getTimestamp(),
$options->getApplicationName(),
Utilities::levelToString($event->Level),
$backtrace_output !== null ? $backtrace_output : 'lambda',
$event->Message
));
if($event->Exception !== null)
self::dumpException($options, $event);
if($fileHandle == null && Log::getRuntimeOptions()->getOutputLogHandle() !== null)
self::out($options, $event, Log::getRuntimeOptions()->getOutputLogHandle());
}
/**
* Dumps an exception to a file
*
* @param Options $options
* @param Event $event
* @return string|null
*/
public static function dumpException(Options $options, Event $event): ?string
{
if($options->dumpExceptionsEnabled() && $options->getPackageDataPath() !== null)
return null;
$exceptions_path = $options->getPackageDataPath() . DIRECTORY_SEPARATOR . 'logs' . DIRECTORY_SEPARATOR . 'exceptions';
if(!is_dir($exceptions_path))
mkdir($exceptions_path, 0777, true);
$exception_type = str_replace('\\', '_', strtolower($event->Exception['type']));
$exception_file = sprintf('%s_%s_%s.json', date('Y-m-d'), $exception_type, Functions::randomString(12));
$handle = fopen($exception_file, 'w');
fwrite($handle, json_encode($event->Exception, JSON_PRETTY_PRINT));
fclose($handle);
return $exception_file;
}
}

View file

@ -4,6 +4,9 @@
use LogLib\Abstracts\LevelType;
use LogLib\Objects\Backtrace;
use LogLib\Objects\Event;
use OptsLib\Parse;
use Properties\Prop;
use Throwable;
class Utilities
@ -23,7 +26,7 @@
foreach($backtrace as $trace)
{
$results[] = Backtrace::fromArray($trace);
$results[] = Prop::fromArray($trace);
}
return $results;
@ -36,6 +39,8 @@
public static function exceptionToArray(Throwable $e): array
{
$results = [
'hash' => spl_object_hash($e),
'type' => get_class($e),
'message' => $e->getMessage(),
'code' => $e->getCode(),
'file' => $e->getFile(),
@ -71,4 +76,188 @@
};
}
/**
* A simple method to determine if the current environment is a CLI environment
*
* @return bool
*/
public static function runningInCli(): bool
{
if(function_exists('php_sapi_name'))
{
return strtolower(php_sapi_name()) === 'cli';
}
if(defined('PHP_SAPI'))
{
return strtolower(PHP_SAPI) === 'cli';
}
return false;
}
/**
* Attempts to determine the current log level from the command line arguments
*
* @return int
*/
public static function getLogLevel(): int
{
$args = Parse::getArguments();
$selected_level = ($args['log'] ?? $args['log-level'] ?? null);
if($selected_level === null)
return LevelType::Info;
switch(strtolower($selected_level))
{
case LevelType::Debug:
case 'debug':
case '6':
case 'dbg':
return LevelType::Debug;
case LevelType::Verbose:
case 'verbose':
case '5':
case 'vrb':
return LevelType::Verbose;
case LevelType::Info:
case 'info':
case '4':
case 'inf':
return LevelType::Info;
case LevelType::Warning:
case 'warning':
case '3':
case 'wrn':
return LevelType::Warning;
case LevelType::Error:
case 'error':
case '2':
case 'err':
return LevelType::Error;
case LevelType::Fatal:
case 'fatal':
case '1':
case 'crt':
return LevelType::Fatal;
case LevelType::Silent:
case 'silent':
case '0':
case 'sil':
return LevelType::Silent;
default:
return LevelType::Info;
}
}
/**
* Returns the output log path from the command line arguments
*
* @return string|null
*/
public static function getOutputLogPath(): ?string
{
$args = Parse::getArguments();
$path = ($args['log-path'] ?? $args['log-file'] ?? null);
if($path === null)
return null;
return $path;
}
/**
* @return bool
*/
public static function getDisplayAnsi(): bool
{
$args = Parse::getArguments();
$display_ansi = ($args['display-ansi'] ?? $args['ansi'] ?? null);
if($display_ansi === null)
return true;
// Strict boolean response
return strtolower($display_ansi) === 'true' || $display_ansi === '1';
}
/**
* Returns the current active log file name, the current value can
* change depending on the date/time, if it has changed; close the
* old file and open a new one.
*
* @return string
*/
public static function getLogFilename()
{
return date('Y-m-d') . '.log';
}
/**
* Returns the formatted backtrace
*
* @param Event $event
* @return string|null
*/
public static function parseBacktrace(Event $event): ?string
{
$backtrace = null;
if ($event->Backtrace !== null && count($event->Backtrace) > 0)
{
foreach ($event->Backtrace as $item)
{
if ($item->Class !== 'LogLib\\Log')
{
$backtrace = $item;
break;
}
}
}
$backtrace_output = null;
if ($backtrace !== null)
{
if ($backtrace->Class !== null)
{
$backtrace_output = $backtrace->Class . $backtrace->Type . $backtrace->Function . '()';
}
else
{
$backtrace_output = $backtrace->Function . '()';
}
if ($backtrace->Line !== null)
$backtrace_output .= ':' . $backtrace->Line;
}
return $backtrace_output;
}
/**
* Returns a random string of characters
*
* @param int $length
* @return string
*/
public static function randomString(int $length = 32): string
{
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$charactersLength = strlen($characters);
$randomString = '';
for ($i = 0; $i < $length; $i++)
{
$randomString .= $characters[rand(0, $charactersLength - 1)];
}
return $randomString;
}
}

View file

@ -0,0 +1,21 @@
<?php
namespace LogLib\Exceptions;
use Exception;
use Throwable;
class ConfigurationException extends Exception
{
/**
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
$this->message = $message;
$this->code = $code;
}
}

231
src/LogLib/Log.php Normal file
View file

@ -0,0 +1,231 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace LogLib;
use InvalidArgumentException;
use LogLib\Abstracts\LevelType;
use LogLib\Classes\Console;
use LogLib\Classes\FileLogging;
use LogLib\Classes\Validate;
use LogLib\Objects\Event;
use LogLib\Objects\Options;
use LogLib\Objects\RuntimeOptions;
use Throwable;
class Log
{
/**
* @var Options[]
*/
private static $Applications;
/**
* @var RuntimeOptions
*/
private static $RuntimeOptions;
/**
* Registers a new application logger
*
* @param Options $options The options for the application
* @return bool
*/
public static function register(Options $options): bool
{
if(self::isRegistered($options->getApplicationName()))
return false;
self::$Applications[$options->getApplicationName()] = $options;
return true;
}
/**
* Removes a registered application logger
*
* @param string $application The name of the application
* @return void
*/
public static function unregister(string $application): void
{
if(isset(self::$Applications[$application]))
unset(self::$Applications[$application]);
}
/**
* Determines if the given application is registered
*
* @param string $application
* @return bool
*/
private static function isRegistered(string $application): bool
{
return isset(self::$Applications[$application]);
}
/**
* @param string $application
* @return Options
*/
public static function getApplication(string $application): Options
{
if(!self::isRegistered($application))
throw new InvalidArgumentException("The application '$application' is not registered");
return self::$Applications[$application];
}
/**
* @param string $application_name The name of the application
* @return Options The options for the application
*/
public static function getOptions(string $application_name): Options
{
if(!self::isRegistered($application_name))
{
self::register(new Options($application_name));
}
return self::$Applications[$application_name];
}
/**
* @param string $application_name The name of the application
* @param string $level The level of the event
* @param string|null $message The message of the event
* @param Throwable|null $throwable The exception that was thrown, if any
* @return void
*/
private static function log(string $application_name, string $level=LevelType::Info, ?string $message=null, ?Throwable $throwable=null): void
{
$application = self::getOptions($application_name);
if(!Validate::checkLevelType($level, self::getRuntimeOptions()->getLogLevel()))
return;
if($message == null)
throw new InvalidArgumentException('Message cannot be null');
if($level == null || !Validate::levelType($level))
throw new InvalidArgumentException('Invalid logging level');
$event = new Event();
$event->Level = $level;
$event->Message = $message;
$event->Exception = $throwable;
if(self::getRuntimeOptions()->isConsoleOutput())
Console::out($application, $event);
if($application->writeToPackageData())
FileLogging::out($application, $event);
foreach($application->getHandlers() as $event_level => $handlers)
{
if(Validate::checkLevelType($event_level, $level))
{
foreach($handlers as $handler)
$handler->handle($event);
}
}
}
/**
* @param string $application_name The name of the application
* @param string $message The message of the event
* @return void
*/
public static function info(string $application_name, string $message): void
{
self::log($application_name, LevelType::Info, $message);
}
/**
* @param string $application_name The name of the application
* @param string $message The message of the event
* @return void
*/
public static function verbose(string $application_name, string $message): void
{
self::log($application_name, LevelType::Verbose, $message);
}
/**
* @param string $application_name The name of the application
* @param string $message The message of the event
* @return void
*/
public static function debug(string $application_name, string $message): void
{
self::log($application_name, LevelType::Debug, $message);
}
/**
* @param string $application_name The name of the application
* @param string $message The message of the event
* @param Throwable|null $throwable The exception that was thrown, if any
* @return void
*/
public static function warning(string $application_name, string $message, ?Throwable $throwable=null): void
{
self::log($application_name, LevelType::Warning, $message, $throwable);
}
/**
* @param string $application_name The name of the application
* @param string $message The message of the event
* @param Throwable|null $throwable The exception that was thrown, if any
* @return void
*/
public static function error(string $application_name, string $message, ?Throwable $throwable=null): void
{
self::log($application_name, LevelType::Error, $message, $throwable);
}
/**
* @param string $application_name The name of the application
* @param string $message The message of the event
* @param Throwable|null $throwable The exception that was thrown, if any
* @return void
*/
public static function fatal(string $application_name, string $message, ?Throwable $throwable=null): void
{
self::log($application_name, LevelType::Fatal, $message, $throwable);
}
/**
* Registers LogLib as a exception handler
*
* @return void
*/
public static function registerExceptionHandler(): void
{
set_exception_handler(function(Throwable $throwable) {
self::error('Exception', $throwable->getMessage(), $throwable);
});
}
/**
* Unregisters all applications
*
* @return void
*/
public static function unregisterExceptionHandler(): void
{
set_exception_handler(null);
}
/**
* @return RuntimeOptions
*/
public static function getRuntimeOptions(): RuntimeOptions
{
if(self::$RuntimeOptions == null)
{
self::$RuntimeOptions = new RuntimeOptions();
}
return self::$RuntimeOptions;
}
}

View file

@ -10,6 +10,7 @@
* The function name of the backtrace
*
* @var string|null
* @property_name function
*/
public $Function;
@ -17,6 +18,7 @@
* The line number of the backtrace
*
* @var int|null
* @property_name line
*/
public $Line;
@ -24,6 +26,7 @@
* The file name of the backtrace
*
* @var string|null
* @property_name file
*/
public $File;
@ -31,6 +34,7 @@
* The class name, if any, of the backtrace
*
* @var string|null
* @property_name class
*/
public $Class;
@ -41,6 +45,7 @@
*
* @see CallType
* @var string|null
* @property_name type
*/
public $Type;
@ -49,41 +54,7 @@
* an included file, this lists the included file name(s).
*
* @var array|null
* @property_name args
*/
public $Args;
/**
* Returns an array representation of the backtrace
*
* @return array
*/
public function toArray(): array
{
return [
'function' => $this->Function,
'line' => $this->Line,
'file' => $this->File,
'class' => $this->Class,
'type' => $this->Type,
'args' => $this->Args
];
}
/**
* Constructs a new DebugBacktrace object from an array representation
*
* @param array $array
* @return Backtrace
*/
public static function fromArray(array $array): Backtrace
{
$backtrace = new Backtrace();
$backtrace->Function = ($array['function'] ?? null);
$backtrace->Line = ($array['line'] ?? null);
$backtrace->File = ($array['file'] ?? null);
$backtrace->Class = ($array['class'] ?? null);
$backtrace->Type = ($array['type'] ?? null);
$backtrace->Args = ($array['args'] ?? null);
return $backtrace;
}
}

View file

@ -15,6 +15,7 @@
*
* @see LevelType
* @var string
* @property_name level
*/
public $Level;
@ -22,6 +23,7 @@
* The Unix Timestamp of when the event was created
*
* @var string
* @property_name timestamp
*/
private $Timestamp;
@ -29,6 +31,7 @@
* An array of backtraces, if any, that were created when the event was created
*
* @var Backtrace[]|null
* @property_name backtrace
*/
public $Backtrace;
@ -36,6 +39,7 @@
* The exception that was thrown, if any
*
* @var array|null
* @property_name exception
*/
public $Exception;
@ -43,6 +47,7 @@
* The message of the event
*
* @var string
* @property_name message
*/
public $Message;
@ -62,39 +67,6 @@
$this->Exception = Utilities::exceptionToArray($e);
}
/**
* Returns an array representation of the event
*
* @return array
*/
public function toArray(): array
{
return [
'level' => ($this->Level ?? null),
'timestamp' => ($this->Timestamp ?? null),
'backtrace' => $this->Backtrace,
'exception' => $this->Exception,
'message' => ($this->Message ?? null)
];
}
/**
* Constructs a new event from an array representation
*
* @param array $data
* @return Event
*/
public static function fromArray(array $data): Event
{
$event = new Event();
$event->Level = ($data['level'] ?? null);
$event->Timestamp = ($data['timestamp'] ?? null);
$event->Backtrace = ($data['backtrace'] ?? null);
$event->Exception = ($data['exception'] ?? null);
$event->Message = ($data['message'] ?? null);
return $event;
}
/**
* @return string
*/

View file

@ -0,0 +1,99 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace LogLib\Objects\FileLogging;
use InvalidArgumentException;
use LogLib\Classes\Utilities;
class FileHandle
{
/**
* The file handle of the file
*
* @var resource
*/
private $resource;
/**
* The current out path where all the logs are being written to
*
* @var string
*/
private $path;
/**
* The current file path of the log file
*
* @var string
*/
private $current_file;
/**
* Public constructor
*
* @param string $path
*/
public function __construct(string $path)
{
if(is_writable($path) === false)
throw new InvalidArgumentException(sprintf('The path "%s" is not writable', $path));
$this->path = $path . DIRECTORY_SEPARATOR . 'logs';
$this->current_file = Utilities::getLogFilename();
if(!file_exists($this->current_file))
{
touch($this->current_file);
chmod($this->current_file, 0777);
}
$this->resource = fopen($this->path . DIRECTORY_SEPARATOR . $this->current_file, 'a');
if(!is_dir($this->path))
mkdir($this->path, 0777, true);
}
/**
* Writes to the file
*
* @param string $string
* @return int
*/
public function fwrite(string $string): int
{
$current_file = Utilities::getLogFilename();
if ($current_file !== $this->current_file)
{
fclose($this->resource);
$this->current_file = $current_file;
if(!file_exists($this->current_file))
{
touch($this->current_file);
chmod($this->current_file, 0777);
}
$this->resource = fopen($this->current_file, 'a');
}
return fwrite($this->resource, $string);
}
/**
* Closes the file handle
*/
public function __destruct()
{
fclose($this->resource);
}
/**
* @return false|resource
*/
public function resource()
{
return $this->resource;
}
}

View file

@ -5,9 +5,13 @@
namespace LogLib\Objects;
use InvalidArgumentException;
use LogLib\Abstracts\LevelType;
use LogLib\Classes\Validate;
use LogLib\Interfaces\HandlerInterface;
use LogLib\Objects\FileLogging\FileHandle;
use ncc\Exceptions\InvalidPackageNameException;
use ncc\Exceptions\InvalidScopeException;
use ncc\Exceptions\PackageLockException;
use ncc\Managers\PackageLockManager;
class Options
{
@ -15,62 +19,19 @@
* The name of the application
*
* @var string
* @property_name application_name
*/
private $ApplicationName;
/**
* The name of the NCC package that is using LogLib (eg; com.example.package)
*
* @var string|null
*/
private $PackageName;
/**
* The current output level of the logger, anything below this level will not be logged
*
* @see LevelType
* @var string
*/
private $OutputLevel;
/**
* Indicates whether the log should be written to the console or not.
*
* @var bool
*/
private $ConsoleOutput;
/**
* Indicates whether ansi colors should be used in the console output.
*
* @var bool
*/
private $ConsoleAnsiColors;
/**
* Writes the log to a file located at the package data path provided by NCC's API
* under a "logs" directory.
*
* @var bool
* @property_name write_to_package_data
*/
private $WriteToPackageData;
/**
* Indicates whether the log should be split into different files based on the file size.
* Only applies if WriteToPackageData is true.
*
* @var bool
*/
private $SplitFiles;
/**
* The maximum size of a log file before it is split into a new file.
* Only applies if WriteToPackageData is true.
*
* @var int
*/
private $MaxFileSize;
/**
* An array of handlers that wil be used to handle the log events
* if applications want to handle the log events themselves.
@ -79,136 +40,78 @@
*/
private $Handlers;
/**
* The file handle to write the log to if WriteToPackageData is true
*
* @var FileHandle|null
*/
private $FileHandle;
/**
* @var string|null
*/
private $PackageDataPath;
/**
* @var bool
*/
private $DumpExceptions;
/**
* Options constructor.
*/
public function __construct(string $application_name)
{
$this->ApplicationName = $application_name;
$this->WriteToPackageData = true;
$this->SplitFiles = true;
$this->MaxFileSize = 1073741824; // 1GB
$this->OutputLevel = LevelType::Info;
$this->ConsoleOutput = true;
$this->ConsoleAnsiColors = true;
$this->WriteToPackageData = false;
$this->DumpExceptions = false;
$this->Handlers = [];
}
/**
* @return string|null
*/
public function getPackageName(): ?string
{
return $this->PackageName;
}
/**
* @param string|null $PackageName
*/
public function setPackageName(?string $PackageName): void
{
$this->PackageName = $PackageName;
}
/**
* @return string
*/
public function getOutputLevel(): string
{
return $this->OutputLevel;
}
/**
* @param string $OutputLevel
*/
public function setOutputLevel(string $OutputLevel): void
{
if(!in_array($OutputLevel, LevelType::All))
throw new InvalidArgumentException("Invalid output level provided");
$this->OutputLevel = $OutputLevel;
}
/**
* @return bool
*/
public function isConsoleOutput(): bool
{
return $this->ConsoleOutput;
}
/**
* @param bool $ConsoleOutput
*/
public function setConsoleOutput(bool $ConsoleOutput): void
{
$this->ConsoleOutput = $ConsoleOutput;
}
/**
* @return bool
*/
public function isConsoleAnsiColors(): bool
{
return $this->ConsoleAnsiColors;
}
/**
* @param bool $ConsoleAnsiColors
*/
public function setConsoleAnsiColors(bool $ConsoleAnsiColors): void
{
$this->ConsoleAnsiColors = $ConsoleAnsiColors;
}
/**
* @return bool
*/
public function isWriteToPackageData(): bool
public function writeToPackageData(): bool
{
return $this->WriteToPackageData;
}
/**
* @param bool $WriteToPackageData
* Enables the writing of the log to a file located at the package data path provided by NCC's API
*
* @return void
* @throws InvalidPackageNameException
* @throws InvalidScopeException
* @throws PackageLockException
*/
public function setWriteToPackageData(bool $WriteToPackageData): void
public function enableWriteToPackageData(): void
{
$this->WriteToPackageData = $WriteToPackageData;
if($this->WriteToPackageData)
return;
$package_lock = new PackageLockManager();
$package = $package_lock->getPackageLock()->getPackage($this->ApplicationName);
if($package == null)
throw new InvalidArgumentException("The package data path could not be found for the package '{$this->ApplicationName}'");
$this->WriteToPackageData = true;
$this->PackageDataPath = $package->getDataPath();
if($this->FileHandle !== null)
unset($this->FileHandle);
$this->FileHandle = new FileHandle($this->PackageDataPath);
}
/**
* @return bool
* Disables the writing of the log to the package data path
*
* @return void
*/
public function isSplitFiles(): bool
public function disableWriteToPackageData(): void
{
return $this->SplitFiles;
}
/**
* @param bool $SplitFiles
*/
public function setSplitFiles(bool $SplitFiles): void
{
$this->SplitFiles = $SplitFiles;
}
/**
* @return int
*/
public function getMaxFileSize(): int
{
return $this->MaxFileSize;
}
/**
* @param int $MaxFileSize
*/
public function setMaxFileSize(int $MaxFileSize): void
{
if($MaxFileSize < 1)
throw new InvalidArgumentException("Max file size must be greater than 0");
$this->MaxFileSize = $MaxFileSize;
$this->WriteToPackageData = false;
$this->PackageDataPath = null;
unset($this->FileHandle);
}
/**
@ -243,10 +146,52 @@
}
/**
* Returns the name of the Application
*
* @return string
*/
public function getApplicationName(): string
{
return $this->ApplicationName;
}
/**
* Indicates if exceptions should be dumped to a file
*
* @return bool
*/
public function dumpExceptionsEnabled(): bool
{
return $this->DumpExceptions;
}
/**
* Enables/Disables the dumping of exceptions to the /exceptions folder of the package data path
* WriteToPackageData must be enabled for this to work properly
*
* @param bool $DumpExceptions
*/
public function setDumpExceptions(bool $DumpExceptions): void
{
if(!$this->WriteToPackageData)
throw new InvalidArgumentException('Cannot dump exceptions if WriteToPackageData is disabled');
$this->DumpExceptions = $DumpExceptions;
}
/**
* @return FileHandle|null
*/
public function getFileHandle(): ?FileHandle
{
return $this->FileHandle;
}
/**
* @return string|null
*/
public function getPackageDataPath(): ?string
{
return $this->PackageDataPath;
}
}

View file

@ -0,0 +1,153 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace LogLib\Objects;
use InvalidArgumentException;
use LogLib\Abstracts\LevelType;
use LogLib\Classes\Utilities;
use LogLib\Objects\FileLogging\FileHandle;
class RuntimeOptions
{
/**
* Indicates if the console output is enabled
*
* @var bool
* @property_name console_output
*/
private $ConsoleOutput;
/**
* Indicates if ANSI colors should be used in the console output
*
* @var bool
* @property_name display_ansi
*/
private $DisplayAnsi;
/**
* Indicates if LogLib should handle uncaught exceptions
*
* @var bool
* @property_name handle_exceptions
*/
private $HandleExceptions;
/**
* Optional. The file to write the log to.
*
* @var string|null
* @property_name output_log
*/
private $OutputLog;
/**
* The current log level
*
* @var int
* @see LevelType
*/
private $LogLevel;
/**
* @var FileHandle
*/
private $OutputLogHandle;
/**
* Public Constructor
*/
public function __construct()
{
$this->ConsoleOutput = Utilities::runningInCli();
$this->DisplayAnsi = Utilities::getDisplayAnsi();
$this->HandleExceptions = true;
$this->OutputLog = Utilities::getOutputLogPath();
$this->LogLevel = Utilities::getLogLevel();
}
/**
* @return bool
*/
public function isConsoleOutput(): bool
{
return $this->ConsoleOutput;
}
/**
* @param bool $ConsoleOutput
*/
public function setConsoleOutput(bool $ConsoleOutput): void
{
$this->ConsoleOutput = $ConsoleOutput;
}
/**
* @return bool
*/
public function isDisplayAnsi(): bool
{
return $this->DisplayAnsi;
}
/**
* @param bool $DisplayAnsi
*/
public function setDisplayAnsi(bool $DisplayAnsi): void
{
$this->DisplayAnsi = $DisplayAnsi;
}
/**
* @return bool
*/
public function isHandleExceptions(): bool
{
return $this->HandleExceptions;
}
/**
* @param bool $HandleExceptions
*/
public function setHandleExceptions(bool $HandleExceptions): void
{
$this->HandleExceptions = $HandleExceptions;
}
/**
* @return int
*/
public function getLogLevel(): int
{
return $this->LogLevel;
}
/**
* @param int $LogLevel
*/
public function setLogLevel(int $LogLevel): void
{
$this->LogLevel = $LogLevel;
}
/**
* @return ?FileHandle
*/
public function getOutputLogHandle(): ?FileHandle
{
if($this->OutputLogHandle == null)
{
if($this->OutputLog == null)
return null;
if(is_writable($this->OutputLog) === false)
throw new InvalidArgumentException(sprintf('The path "%s" is not writable', $this->OutputLog));
$this->OutputLogHandle = new FileHandle($this->OutputLog);
}
return $this->OutputLogHandle;
}
}

19
tests/logging.php Normal file
View file

@ -0,0 +1,19 @@
<?php
use LogLib\Abstracts\LevelType;
use LogLib\Log;
use LogLib\Objects\Options;
require('ncc');
import('net.nosial.loglib', 'latest');
$options = new Options('net.nosial.optslib');
$options->enableWriteToPackageData();
Log::register($options);
Log::debug('net.nosial.optslib', 'This is a debug message');
Log::verbose('net.nosial.optslib', 'This is a verbose message');
Log::info('net.nosial.optslib', 'This is an info message');
Log::warning('net.nosial.optslib', 'This is a warning message');
Log::error('net.nosial.optslib', 'This is an error message');
Log::fatal('net.nosial.optslib', 'This is a fatal message');