diff --git a/.idea/php.xml b/.idea/php.xml index ede6265..09cee4f 100644 --- a/.idea/php.xml +++ b/.idea/php.xml @@ -11,8 +11,10 @@ + - + + diff --git a/Makefile b/Makefile index b5a49de..633c80c 100644 --- a/Makefile +++ b/Makefile @@ -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" \ No newline at end of file diff --git a/README.md b/README.md index f49546f..f3f0f68 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,29 @@ # LogLib -A logging library for PHP. \ No newline at end of file +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 +``` \ No newline at end of file diff --git a/project.json b/project.json index 393e3d2..6e0d264 100644 --- a/project.json +++ b/project.json @@ -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", diff --git a/src/LogLib/Abstracts/ConsoleColors.php b/src/LogLib/Abstracts/ConsoleColors.php index c5db91f..648c549 100644 --- a/src/LogLib/Abstracts/ConsoleColors.php +++ b/src/LogLib/Abstracts/ConsoleColors.php @@ -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, + ]; } \ No newline at end of file diff --git a/src/LogLib/Classes/Console.php b/src/LogLib/Classes/Console.php index 755c1bf..50be148 100644 --- a/src/LogLib/Classes/Console.php +++ b/src/LogLib/Classes/Console.php @@ -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 + )); } /** diff --git a/src/LogLib/Classes/FileLogging.php b/src/LogLib/Classes/FileLogging.php new file mode 100644 index 0000000..a115480 --- /dev/null +++ b/src/LogLib/Classes/FileLogging.php @@ -0,0 +1,84 @@ +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; + } + } \ No newline at end of file diff --git a/src/LogLib/Classes/Utilities.php b/src/LogLib/Classes/Utilities.php index c8f7a22..dd614f5 100644 --- a/src/LogLib/Classes/Utilities.php +++ b/src/LogLib/Classes/Utilities.php @@ -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; + } + } \ No newline at end of file diff --git a/src/LogLib/Exceptions/ConfigurationException.php b/src/LogLib/Exceptions/ConfigurationException.php new file mode 100644 index 0000000..7a829fc --- /dev/null +++ b/src/LogLib/Exceptions/ConfigurationException.php @@ -0,0 +1,21 @@ +message = $message; + $this->code = $code; + } + } \ No newline at end of file diff --git a/src/LogLib/Log.php b/src/LogLib/Log.php new file mode 100644 index 0000000..058fee0 --- /dev/null +++ b/src/LogLib/Log.php @@ -0,0 +1,231 @@ +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; + } + + } \ No newline at end of file diff --git a/src/LogLib/Objects/Backtrace.php b/src/LogLib/Objects/Backtrace.php index cbb4dd7..fb49dac 100644 --- a/src/LogLib/Objects/Backtrace.php +++ b/src/LogLib/Objects/Backtrace.php @@ -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; - } } \ No newline at end of file diff --git a/src/LogLib/Objects/Event.php b/src/LogLib/Objects/Event.php index ea24c1a..a8c6067 100644 --- a/src/LogLib/Objects/Event.php +++ b/src/LogLib/Objects/Event.php @@ -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 */ diff --git a/src/LogLib/Objects/FileLogging/FileHandle.php b/src/LogLib/Objects/FileLogging/FileHandle.php new file mode 100644 index 0000000..1d9f11a --- /dev/null +++ b/src/LogLib/Objects/FileLogging/FileHandle.php @@ -0,0 +1,99 @@ +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; + } + } \ No newline at end of file diff --git a/src/LogLib/Objects/Options.php b/src/LogLib/Objects/Options.php index a2acc05..7451f96 100644 --- a/src/LogLib/Objects/Options.php +++ b/src/LogLib/Objects/Options.php @@ -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; + } + } \ No newline at end of file diff --git a/src/LogLib/Objects/RuntimeOptions.php b/src/LogLib/Objects/RuntimeOptions.php new file mode 100644 index 0000000..ced3eff --- /dev/null +++ b/src/LogLib/Objects/RuntimeOptions.php @@ -0,0 +1,153 @@ +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; + } + } \ No newline at end of file diff --git a/tests/logging.php b/tests/logging.php new file mode 100644 index 0000000..96df4c6 --- /dev/null +++ b/tests/logging.php @@ -0,0 +1,19 @@ +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'); \ No newline at end of file