Added initial codebase
This commit is contained in:
parent
493a86bc9b
commit
80a6af74ed
41 changed files with 5676 additions and 29 deletions
1
.idea/LogLib2.iml
generated
1
.idea/LogLib2.iml
generated
|
@ -4,6 +4,7 @@
|
|||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/examples" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
|
|
5
.idea/php.xml
generated
5
.idea/php.xml
generated
|
@ -10,6 +10,11 @@
|
|||
<option name="highlightLevel" value="WARNING" />
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PhpIncludePathManager">
|
||||
<include_path>
|
||||
<path value="/var/ncc/packages/net.nosial.optslib=1.1.2" />
|
||||
</include_path>
|
||||
</component>
|
||||
<component name="PhpProjectSharedConfiguration" php_language_level="8.3" />
|
||||
<component name="PhpStanOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
|
|
14
LICENSE
Normal file
14
LICENSE
Normal file
|
@ -0,0 +1,14 @@
|
|||
Copyright 2022-2025 Nosial All Rights Reserved.
|
||||
|
||||
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.
|
713
README.md
Normal file
713
README.md
Normal file
|
@ -0,0 +1,713 @@
|
|||
# LogLib2
|
||||
|
||||
LogLib2 is a lightweight logging library for php/ncc projects. This is the successor of the original LogLib library, due
|
||||
to the many changes in the project structure, it is recommended to use this library instead of the original one.
|
||||
|
||||
With LogLib2 you can log events from your application to several different handlers built into the library such as
|
||||
|
||||
- Console Logging: Logs events to `stdout` and `stderr` streams.
|
||||
- Descriptor Logging: Logs events to a file descriptor.
|
||||
- File Logging: Logs events to a file using a file locking mechanism.
|
||||
- HTTP Logging: Logs events to a remote server using HTTP POST requests.
|
||||
- TCP Logging: Logs events to a remote TCP server
|
||||
- UDP Logging: Logs events to a remote UDP server
|
||||
|
||||
Aside from Console logging, all other handlers supports up to 5 different log formats, which are:
|
||||
|
||||
- JSON Lines
|
||||
- CSV
|
||||
- TXT
|
||||
- XML
|
||||
- HTML
|
||||
|
||||
LogLib2 is designed to be silent-failing, this means that if an error occurs while logging an event, the library will
|
||||
silently fail and continue to log events, this is to prevent the application from crashing due to a logging error.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
<!-- TOC -->
|
||||
* [LogLib2](#loglib2)
|
||||
* [Table of Contents](#table-of-contents)
|
||||
* [Installation](#installation)
|
||||
* [Compiling](#compiling)
|
||||
* [Documentation](#documentation)
|
||||
* [Environment Variables](#environment-variables)
|
||||
* [Console Variables](#console-variables)
|
||||
* [Descriptor Variables](#descriptor-variables)
|
||||
* [File Variables](#file-variables)
|
||||
* [HTTP Variables](#http-variables)
|
||||
* [TCP Variables](#tcp-variables)
|
||||
* [UDP Variables](#udp-variables)
|
||||
* [Log Levels](#log-levels)
|
||||
* [Log Filtering](#log-filtering)
|
||||
* [Command-Line Override](#command-line-override)
|
||||
* [Environment Variable Override](#environment-variable-override)
|
||||
* [Creating a Logger](#creating-a-logger)
|
||||
* [Logging Events](#logging-events)
|
||||
* [Changing Default Configuration](#changing-default-configuration)
|
||||
* [Changing Logger Configuration](#changing-logger-configuration)
|
||||
* [TCP/UDP Logging Server (python)](#tcpudp-logging-server-python)
|
||||
* [Usage:](#usage)
|
||||
* [Formatters](#formatters)
|
||||
* [AnsiFormat](#ansiformat)
|
||||
* [LogFormat](#logformat)
|
||||
* [TimestampFormat](#timestampformat)
|
||||
* [TraceFormat](#traceformat)
|
||||
* [Object Types](#object-types)
|
||||
* [Event](#event)
|
||||
* [StackTrace](#stacktrace)
|
||||
* [ExceptionDetails](#exceptiondetails)
|
||||
* [CallTypes](#calltypes)
|
||||
* [Log Formats](#log-formats)
|
||||
* [JSONL](#jsonl)
|
||||
* [CSV](#csv)
|
||||
* [TXT](#txt)
|
||||
* [XML](#xml)
|
||||
* [License](#license)
|
||||
<!-- TOC -->
|
||||
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
To install LogLib2, you can add the project as a dependency to your project.json file, for example
|
||||
|
||||
From the n64 repository
|
||||
```json
|
||||
{
|
||||
"name": "net.nosial.loglib2",
|
||||
"version": "latest",
|
||||
"source": "nosial/libs.log2=latest@n64"
|
||||
}
|
||||
```
|
||||
|
||||
From the github repository
|
||||
```json
|
||||
{
|
||||
"name": "net.nosial.loglib2",
|
||||
"version": "latest",
|
||||
"source": "nosial/loglib2=latest@github"
|
||||
}
|
||||
```
|
||||
|
||||
To install the library from the command line, you can use the following command, use the appropriate source for the
|
||||
repository you want to install from, you may also use the `--build-source` flag to force ncc to build the package from
|
||||
source rather than downloading a pre-built package if one is available.
|
||||
|
||||
```bash
|
||||
ncc package install --package=nosial/loglib2=latest@github
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Compiling
|
||||
|
||||
To compile the library, you can use the Makefile provided in the project, the Makefile provides several targets for
|
||||
compiling the library, the default target is `all` which compiles both the `release` and `debug` versions of the library.
|
||||
|
||||
To compile the library, you can use the following command
|
||||
|
||||
```bash
|
||||
make all
|
||||
```
|
||||
|
||||
To compile the library in `release` mode, you can use the following command
|
||||
|
||||
```bash
|
||||
make release
|
||||
```
|
||||
|
||||
You may also compile manually using the following commands
|
||||
|
||||
```bash
|
||||
ncc build --config=release
|
||||
```
|
||||
|
||||
To install the library, you can use the following command
|
||||
|
||||
```bash
|
||||
ncc package install --package=build/release/net.nosial.loglib2.ncc --skip-dependencies --build-source --reinstall -y
|
||||
```
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
# Documentation
|
||||
|
||||
The LogLib2 library provides a simple and easy-to-use logging interface for logging events from your application to
|
||||
several different handlers built into the library such as Console Logging, Descriptor Logging, File Logging, HTTP Logging,
|
||||
TCP Logging, and UDP Logging. This documentation will provide an overview of the library and how to use it in your
|
||||
application.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
Environment Variables can be used to configure the default configuration properties of the library, this is useful when
|
||||
you want to configure the library without needing to declare the default properties at the start of your application.
|
||||
|
||||
### Console Variables
|
||||
|
||||
The following environment variables can be used to configure the console logging handler, these variables are used to
|
||||
configure the console logging handler for all logger instances.
|
||||
|
||||
|
||||
| Variable Name | Excepted Value | Default Value | Description |
|
||||
|--------------------------------|-------------------------|---------------|----------------------------------------------------------------------|
|
||||
| `LOGLIB_CONSOLE_ENABLED` | `true`, `false` | `true` | Enable or disable console logging |
|
||||
| `LOGLIB_CONSOLE_DISPLAY_NAME` | `true`, `false` | `true` | Enable or disable display name of the application in console logging |
|
||||
| `LOGLIB_CONSOLE_DISPLAY_LEVEL` | `true`, `false` | `true` | Enable or disable display level of the log event in console logging |
|
||||
| `LOGLIB_CONSOLE_ANSI_FORMAT` | `basic`, `none` | `basic` | Enable or disable ANSI formatting in console logging |
|
||||
| `LOGLIB_CONSOLE_TRACE_FORMAT` | `none`, `basic`, `full` | `basic` | Enable or disable trace formatting |
|
||||
|
||||
### Descriptor Variables
|
||||
|
||||
The following environment variables can be used to configure the descriptor logging handler, these variables are used to
|
||||
configure the descriptor logging handler for all logger instances.
|
||||
|
||||
| Variable Name | Excepted Value | Default Value | Description |
|
||||
|--------------------------------------|---------------------------------------------------------------------------------------------------------|----------------|--------------------------------------------------------|
|
||||
| `LOGLIB_DESCRIPTOR_ENABLED` | `true`, `false` | `false` | Enable or disable descriptor logging |
|
||||
| `LOGLIB_DESCRIPTOR_PATH` | `string` | `php://stdout` | The path to the descriptor file |
|
||||
| `LOGLIB_DESCRIPTOR_APPEND_NEWLINE` | `true`, `false` | `true` | Enable or disable appending a newline to the log entry |
|
||||
| `LOGLIB_DESCRIPTOR_LOG_FORMAT` | `jsonl`, `csv`, `txt`, `xml`, `html` | `jsonl` | The format of the log entry |
|
||||
| `LOGLIB_DESCRIPTOR_TIMESTAMP_FORMAT` | `none`, `time_only`, `time_only_millis`, `date_only`, `date_time`. `date_time_millis`, `unix_timestamp` | `date_time` | The format of the timestamp |
|
||||
| `LOGLIB_DESCRIPTOR_TRACE_FORMAT` | `none`, `basic`, `full` | `basic` | Enable or disable trace formatting |
|
||||
|
||||
### File Variables
|
||||
|
||||
The following environment variables can be used to configure the file logging handler, these variables are used to
|
||||
configure the file logging handler for all logger instances.
|
||||
|
||||
| Variable Name | Excepted Value | Default Value | Description |
|
||||
|-----------------------------------|---------------------------------------------------------------------------------------------------------|---------------|--------------------------------------------------------|
|
||||
| `LOGLIB_FILE_ENABLED` | `true`, `false` | `false` | Enable or disable file logging |
|
||||
| `LOGLIB_FILE_DEFAULT_PERMISSIONS` | `octal` | `0777` | The default permissions for the log file |
|
||||
| `LOGLIB_FILE_PATH` | `string` | `(tmp)` | The path to the log file |
|
||||
| `LOGLIB_FILE_APPEND_NEWLINE` | `true`, `false` | `true` | Enable or disable appending a newline to the log entry |
|
||||
| `LOGLIB_FILE_LOG_FORMAT` | `jsonl`, `csv`, `txt`, `xml`, `html` | `jsonl` | The format of the log entry |
|
||||
| `LOGLIB_FILE_TIMESTAMP_FORMAT` | `none`, `time_only`, `time_only_millis`, `date_only`, `date_time`. `date_time_millis`, `unix_timestamp` | `date_time` | The format of the timestamp |
|
||||
| `LOGLIB_FILE_TRACE_FORMAT` | `none`, `basic`, `full` | `basic` | Enable or disable trace formatting |
|
||||
|
||||
|
||||
### HTTP Variables
|
||||
|
||||
The following environment variables can be used to configure the HTTP logging handler, these variables are used to
|
||||
configure the HTTP logging handler for all logger instances.
|
||||
|
||||
| Variable Name | Excepted Value | Default Value | Description |
|
||||
|--------------------------------|---------------------------------------------------------------------------------------------------------|-----------------------|--------------------------------------------------------|
|
||||
| `LOGLIB_HTTP_ENABLED` | `true`, `false` | `false` | Enable or disable HTTP logging |
|
||||
| `LOGLIB_HTTP_ENDPOINT` | `string` | `http://0.0.0.0:5131` | The URL to the HTTP endpoint |
|
||||
| `LOGLIB_HTTP_APPEND_NEWLINE` | `true`, `false` | `true` | Enable or disable appending a newline to the log entry |
|
||||
| `LOGLIB_HTTP_LOG_FORMAT` | `jsonl`, `csv`, `txt`, `xml`, `html` | `jsonl` | The format of the log entry |
|
||||
| `LOGLIB_HTTP_TIMESTAMP_FORMAT` | `none`, `time_only`, `time_only_millis`, `date_only`, `date_time`. `date_time_millis`, `unix_timestamp` | `date_time` | The format of the timestamp |
|
||||
| `LOGLIB_HTTP_TRACE_FORMAT` | `none`, `basic`, `full` | `basic` | Enable or disable trace formatting |
|
||||
|
||||
### TCP Variables
|
||||
|
||||
The following environment variables can be used to configure the TCP logging handler, these variables are used to
|
||||
configure the TCP logging handler for all logger instances.
|
||||
|
||||
| Variable Name | Excepted Value | Default Value | Description |
|
||||
|-------------------------------|---------------------------------------------------------------------------------------------------------|---------------|--------------------------------------------------------|
|
||||
| `LOGLIB_TCP_ENABLED` | `true`, `false` | `false` | Enable or disable TCP logging |
|
||||
| `LOGLIB_TCP_HOST` | `string` | ` | |
|
||||
| `LOGLIB_TCP_PORT` | `integer` | `5131` | The port to the TCP server |
|
||||
| `LOGLIB_TCP_APPEND_NEWLINE` | `true`, `false` | `true` | Enable or disable appending a newline to the log entry |
|
||||
| `LOGLIB_TCP_LOG_FORMAT` | `jsonl`, `csv`, `txt`, `xml`, `html` | `jsonl` | The format of the log entry |
|
||||
| `LOGLIB_TCP_TIMESTAMP_FORMAT` | `none`, `time_only`, `time_only_millis`, `date_only`, `date_time`. `date_time_millis`, `unix_timestamp` | `date_time` | The format of the timestamp |
|
||||
| `LOGLIB_TCP_TRACE_FORMAT` | `none`, `basic`, `full` | `basic` | Enable or disable trace formatting |
|
||||
|
||||
### UDP Variables
|
||||
|
||||
The following environment variables can be used to configure the UDP logging handler, these variables are used to
|
||||
configure the UDP logging handler for all logger instances.
|
||||
|
||||
| Variable Name | Excepted Value | Default Value | Description |
|
||||
|-------------------------------|---------------------------------------------------------------------------------------------------------|---------------|--------------------------------------------------------|
|
||||
| `LOGLIB_UDP_ENABLED` | `true`, `false` | `false` | Enable or disable UDP logging |
|
||||
| `LOGLIB_UDP_HOST` | `string` | ` | |
|
||||
| `LOGLIB_UDP_PORT` | `integer` | `5131` | The port to the UDP server |
|
||||
| `LOGLIB_UDP_APPEND_NEWLINE` | `true`, `false` | `true` | Enable or disable appending a newline to the log entry |
|
||||
| `LOGLIB_UDP_LOG_FORMAT` | `jsonl`, `csv`, `txt`, `xml`, `html` | `jsonl` | The format of the log entry |
|
||||
| `LOGLIB_UDP_TIMESTAMP_FORMAT` | `none`, `time_only`, `time_only_millis`, `date_only`, `date_time`. `date_time_millis`, `unix_timestamp` | `date_time` | The format of the timestamp |
|
||||
| `LOGLIB_UDP_TRACE_FORMAT` | `none`, `basic`, `full` | `basic` | Enable or disable trace formatting |
|
||||
|
||||
|
||||
## Log Levels
|
||||
|
||||
The LogLevel enumeration in the LogLib2 namespace provides five distinct log levels for logging events, each log level
|
||||
Depending on the log level, the log entry may be handled differently by the logging handler and or extra information may
|
||||
be added to the log event, for example, the `WARNING`, `ERROR`, and `CRITICAL` log levels may include an exception object
|
||||
in the log event.
|
||||
|
||||
| Level | Standard Value | Possible Values | Description | Contains Exception |
|
||||
|----------|----------------|-----------------------------------|----------------------------------------------------------------------------------------------------------|--------------------|
|
||||
| DEBUG | `DBG` | `debug`, `dbg`, `d`, 0 | A debugging event, reserved for being extra verbose about states and events happening in the application | No |
|
||||
| VERBOSE | `VRB` | `verbose`, `verb`, `vrb`, `v`, 1 | A verbose event, reserved for being verbose about states and events happening in the application | No |
|
||||
| INFO | `INF` | `info`, `inf`, `i`, 2 | An informational event, reserved for logging general information about the application | No |
|
||||
| WARNING | `WRN` | `warning`, `warn`, `wrn`, `w`, 3 | A warning event, reserved for logging events that may indicate a potential problem in the application | Yes |
|
||||
| ERROR | `ERR` | `error`, `err`, `e`, 4 | An error event, reserved for logging events that indicate an error in the application | Yes |
|
||||
| CRITICAL | `CRT` | `critical`, `crit`, `crt`, `c`, 5 | A critical event, reserved for logging events that indicate a critical error in the application | Yes |
|
||||
|
||||
The values are used to allow the user to specify the log level in a more human-readable format, for example, if you were
|
||||
to use command-line arguments or environment variables to specify the log level to `debug`, the values `debug`, `dbg`, `d`,
|
||||
and `0` would all be valid values to specify the log level.
|
||||
|
||||
### Log Filtering
|
||||
|
||||
By default application's log level filter is set to `INFO`, this means that only log events with a log level of `INFO` or
|
||||
higher will be processed but everything below `INFO` will be ignored. The filter can easily be overridden by the
|
||||
command-line arguments or environment variables to enforce all loggers to use a specific log level.
|
||||
|
||||
#### Command-Line Override
|
||||
|
||||
The log level filter can be overridden by the command-line arguments, for example, if LogLib2 can access the command-line
|
||||
arguments, it will check for the `--log-level` argument, if the argument is present, it will override the default log
|
||||
level filter with the value provided in the argument.
|
||||
|
||||
```bash
|
||||
./myapp --log-level=debug
|
||||
```
|
||||
|
||||
#### Environment Variable Override
|
||||
|
||||
The log level filter can also be overridden by the environment variable `LOG_LEVEL`, if the environment variable is set,
|
||||
it will override the default log level filter with the value provided in the environment variable.
|
||||
|
||||
```bash
|
||||
export LOG_LEVEL=debug
|
||||
./myapp
|
||||
```
|
||||
|
||||
## Creating a Logger
|
||||
|
||||
To create a logger, you can use the `Logger` class in the LogLib2 namespace, all loggers require an application name to
|
||||
be specified, this is used to identify the application that generated the log event.
|
||||
|
||||
```php
|
||||
$logger = new \LogLib2\Logger('com.example.myapp');
|
||||
|
||||
// Or specify the log level filter
|
||||
$logger = new \LogLib2\Logger('com.example.myapp', \LogLib2\LogLevel::DEBUG);
|
||||
```
|
||||
|
||||
The logger instance is designed to be statically defined, this means that you can define the logger instance as a static
|
||||
variable in your application and use it throughout your application, this is to prevent the need to create a new logger
|
||||
instance every time you want to log an event.
|
||||
|
||||
```php
|
||||
class MyApp {
|
||||
private static ?\LogLib2\Logger $logger=null;
|
||||
|
||||
public static function getLogger() {
|
||||
if (self::$logger === null) {
|
||||
self::$logger = new \LogLib2\Logger('com.example.myapp');
|
||||
}
|
||||
|
||||
return self::$logger;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Logging Events
|
||||
|
||||
To log an event, you can use the `log` method on the logger instance, you can specify the method to use by using the
|
||||
appropriate method on the logger instance, for example, to log a debug event, you can use the `debug` method, to log a
|
||||
verbose event, you can use the `verbose` method, and so on.
|
||||
|
||||
`warning`, `error`, and `critical` log levels may include an exception object in the log event, this is to provide more
|
||||
information about the error that occurred, for example, the exception object may contain the exception name, message,
|
||||
and stack trace.
|
||||
|
||||
```php
|
||||
$logger = new \LogLib2\Logger('com.example.myapp');
|
||||
$exception = new \Exception('An error occurred');
|
||||
|
||||
$logger->debug('A debugging event occurred');
|
||||
$logger->verbose('A verbose event occurred');
|
||||
$logger->info('An informational event occurred');
|
||||
$logger->warning('A warning event occurred', $exception);
|
||||
$logger->error('An error event occurred', $exception);
|
||||
$logger->critical('A critical event occurred', $exception);
|
||||
```
|
||||
|
||||
## Changing Default Configuration
|
||||
|
||||
The default configuration can be altered before the rest of the code-base begins to utilize the library, for example
|
||||
while by default UDP logging is disabled, it can be enabled by altering the default configuration before any logging is
|
||||
initiated, when libraries/applications begin to initialize their own logging instances, they would inherit the default
|
||||
configuration that was altered unless they are explicitly configured to be overridden by their own configurations.
|
||||
|
||||
```php
|
||||
\LogLib2\Logger::getDefaultUdpConfiguration()->setEnabled(true);
|
||||
\LogLib2\Logger::getDefaultUdpConfiguration()->setHost('0.0.0.0');
|
||||
\LogLib2\Logger::getDefaultUdpConfiguration()->setPort(5131);
|
||||
|
||||
\LogLib2\Logger::getDefaultTcpConfiguration()->setEnabled(true);
|
||||
\LogLib2\Logger::getDefaultTcpConfiguration()->setHost('0.0.0.0');
|
||||
\LogLib2\Logger::getDefaultTcpConfiguration()->setPort(5131);
|
||||
|
||||
\LogLib2\Logger::getDefaultHttpConfiguration()->setEnabled(true);
|
||||
\LogLib2\Logger::getDefaultHttpConfiguration()->setUrl('http://0.0.0.0/log');
|
||||
|
||||
// This will use the default configuration that was altered above
|
||||
$logger = new \LogLib2\Logger('com.example.myapp');
|
||||
$logger->info('An informational event occurred');
|
||||
```
|
||||
|
||||
> Note: The recommended way to alter the default configuration is to do so before any logging is initiated, or
|
||||
> alternatively you can use environment variables to skip the need to alter the default configuration manually.
|
||||
|
||||
## Changing Logger Configuration
|
||||
|
||||
The logger configuration can be altered by the logger instance, this is useful when you want to override the default
|
||||
configuration for a specific logger instance, for example, you may want to enable UDP logging for a specific logger
|
||||
instance but not for the rest of the application.
|
||||
|
||||
```php
|
||||
$logger = new \LogLib2\Logger('com.example.myapp');
|
||||
$logger->getUdpConfiguration()->setEnabled(true);
|
||||
$logger->getUdpConfiguration()->setHost('0.0.0.0');
|
||||
$logger->getUdpConfiguration()->setPort(5131);
|
||||
|
||||
$logger->info('An informational event occurred');
|
||||
```
|
||||
|
||||
> Note: This would override the default configuration for the logger instance only, other logger instances would still
|
||||
> use the default configuration unless they are explicitly configured to be overridden by their own configurations.
|
||||
|
||||
## TCP/UDP Logging Server (python)
|
||||
|
||||
While no fully-fledged logging server is provided with the library, a simple TCP/UDP logging server is provided
|
||||
with this project which is written in Python without requiring pip dependencies, the server is listens on both
|
||||
TCP & UDP connections and is only designed to receive JSON formatted log entries with the Unix Timestamp being the
|
||||
format timestamp. Contributions to improve this server are welcomed.
|
||||
|
||||
> See [server.py](server.py) for the server implementation.
|
||||
|
||||
### Usage:
|
||||
|
||||
The server can be started by using python to run [server.py](server.py), by default the server listens on port 5131 and
|
||||
writes log entries to the current working directory under the 'logs' directory. This can be configured using command-line
|
||||
arguments
|
||||
|
||||
```bash
|
||||
python server.py --port=5131 --working-directory=/path/to/logs
|
||||
```
|
||||
|
||||
Once running, you can configure the UDP configuration of your loggers to use this server, or alternatively use
|
||||
environment variables to configure the server for all loggers.
|
||||
|
||||
```bash
|
||||
export LOGLIB_UDP_ENABLED=true
|
||||
export LOGLIB_UDP_HOST=0.0.0.0
|
||||
export LOGLIB_UDP_PORT=5131
|
||||
```
|
||||
|
||||
And once any logging events have been fired, you should see the server receiving the log entries in real-time. If for
|
||||
any reason that LogLib fails to send these entries to the server, it will fail silently and re-try next time.
|
||||
|
||||
## Formatters
|
||||
|
||||
Formatters are used in LogLib to specify the type of format for a log entry property or log format entirely. Some
|
||||
formats are only applicable to some handlers for example AnsiFormat is only applicable to ConsoleHandler
|
||||
|
||||
### AnsiFormat
|
||||
|
||||
The AnsiFormat enumeration in the LogLib2 namespace provides two distinct formats for ANSI formatting in console logging,
|
||||
these formats are used to specify the type of ANSI formatting to use in console logging.
|
||||
|
||||
| Format Name | Value | Description |
|
||||
|-------------|---------|---------------------------------------------------------------------------------|
|
||||
| `NONE` | `none` | (Default) Displays regular console output without any ANSI formatting or colors |
|
||||
| `BASIC` | `basic` | Displays regular console output with ANSI formatting and colors |
|
||||
|
||||
|
||||
### LogFormat
|
||||
|
||||
The LogFormat enumeration allows you to dictate the log output format, some formats has different behaviors but
|
||||
they all try to follow a compatible format.
|
||||
|
||||
| Format Name | Value | |
|
||||
|-------------|-----------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `JSONL` | `json`, `jsonl` | JSON Lines format, each log entry is JSON encoded intended to be used for JSONL files or storage mediums |
|
||||
| `CSV` | `csv` | CSV Format, when using a File handler; if the file doesn't exist a new one will be created with CSV headers included, in other cases CSV rows are simply used instead |
|
||||
| `TXT` | `txt` | TXT Format, a human-readable format that is intended to be used for TXT files or storage mediums |
|
||||
| `XML` | `xml` | XML Format, intended to be used for XML files or storage mediums |
|
||||
| `HTML` | `html` | HTML Format, intended to be used for HTML files or storage mediums |
|
||||
|
||||
|
||||
### TimestampFormat
|
||||
|
||||
The TimestampFormat enumeration allows you to dictate the timestamp format for the log entry, this is used to specify the
|
||||
type of format to use for the timestamp in the log entry.
|
||||
|
||||
| Format Name | Value | Description |
|
||||
|--------------------|-------------------------|-------------------------------------------------------------------------------------|
|
||||
| `NONE` | `none`, `0` | (Default) No timestamp is included in the log entry |
|
||||
| `TIME_ONLY` | `time_only`, `1` | Only the time is included in the log entry (`H:i:s`) |
|
||||
| `TIME_ONLY_MILLIS` | `time_only_millis`, `2` | Only the time is included in the log entry with milliseconds (`H:i:s.u`) |
|
||||
| `DATE_ONLY` | `date_only`, `3` | Only the date is included in the log entry (`Y-m-d`) |
|
||||
| `DATE_TIME` | `date_time`, `4` | The date and time are included in the log entry (`Y-m-d H:i:s`) |
|
||||
| `DATE_TIME_MILLIS` | `date_time_millis`, `5` | The date and time are included in the log entry with milliseconds (`Y-m-d H:i:s.u`) |
|
||||
| `UNIX_TIMESTAMP` | `unix_timestamp`, `6` | The Unix timestamp is included in the log entry (`U`) |
|
||||
|
||||
### TraceFormat
|
||||
|
||||
The TraceFormat enumeration allows you to dictate the trace format for the log entry, this is used to specify the type of
|
||||
format to use for the trace in the log
|
||||
|
||||
| Format Name | Value | Description |
|
||||
|-------------|---------|-----------------------------------------------------------------------------|
|
||||
| `NONE` | `none` | (Default) No trace is included in the log entry |
|
||||
| `BASIC` | `basic` | Only the class and method name are included in the log entry trace |
|
||||
| `FULL` | `full` | The full trace is included in the log entry, including the class and method |
|
||||
|
||||
|
||||
## Object Types
|
||||
|
||||
The LogLib2 library provides simplified object types for logging events, exceptions and stack traces. These object types
|
||||
are designed to be used for serialization for log formats, for example JSON would show an object representation of the
|
||||
log entry, while TXT would show a human-readable representation of the log entry.
|
||||
|
||||
### Event
|
||||
|
||||
The Event object type is used to represent a log event, it contains the following properties:
|
||||
|
||||
| Property Name | Value Type | Optional | Description |
|
||||
|------------------|------------------------------------------------|----------|-------------------------------------------------------------------------------------|
|
||||
| application_name | `string` | No | The name of the application that created the event |
|
||||
| timestamp | `string` | No | The timestamp of the event, formatted using the [TimestampFormat](#timestampformat) |
|
||||
| level | [`LogLevel`](#log-levels) (See standard value) | No | The level of the logging event, eg; `INF` |
|
||||
| message | `string` | No | The message of the event |
|
||||
| trace | `string` | Yes | The trace of the executed caller that created the event |
|
||||
| stack_trace | [`StackTrace[]`](#stacktrace) | Yes | The stack traces of the executed caller that created the event |
|
||||
| exception | [`ExceptionDetails`](#exceptiondetails) | Yes | The exception object of the event |
|
||||
|
||||
### StackTrace
|
||||
|
||||
The StackTrace object type is used to represent a stack trace, it contains the following properties:
|
||||
|
||||
| Property Name | Value Type | Optional | Description |
|
||||
|---------------|-------------------------|----------|-----------------------------------------|
|
||||
| file | `string` | Yes | The executing file of the caller |
|
||||
| line | `integer` | Yes | The executing line of the caller |
|
||||
| function | `string` | Yes | The executing function of the caller |
|
||||
| args | `mixed[]` | Yes | The arguments of the executing function |
|
||||
| class | `string` | Yes | The executing class of the caller |
|
||||
| call_type | [`CallType`](#calltype) | Yes | The call type of the caller |
|
||||
|
||||
|
||||
### ExceptionDetails
|
||||
|
||||
The ExceptionDetails object type is used to represent an exception object, it contains the following properties:
|
||||
|
||||
| Property Name | Value Type | Optional | Description |
|
||||
|---------------|-----------------------------------------|----------|-----------------------------------------|
|
||||
| name | `string` | No | The name of the exception |
|
||||
| message | `string` | No | The message of the exception |
|
||||
| code | `integer` | Yes | The code of the exception |
|
||||
| file | `string` | Yes | The file of the exception |
|
||||
| line | `integer` | Yes | The line of the exception |
|
||||
| trace | [`StackTrace[]`](#stacktrace) | Yes | The stack trace of the exception |
|
||||
| previous | [`ExceptionDetails`](#exceptiondetails) | Yes | The previous exception of the exception |
|
||||
|
||||
## CallTypes
|
||||
|
||||
CallTypes are used to specify the type of call that was made when the log event was created, this is used to provide more
|
||||
information about the call that was made when the log event was created.
|
||||
|
||||
| Call Type | Value | Description |
|
||||
|-----------------|----------|--------------------------------------------------------------|
|
||||
| `METHOD_CALL` | `->` | A method call was made when the log event was created |
|
||||
| `STATIC_CALL` | `::` | A static method call was made when the log event was created |
|
||||
| `FUNCTION_CALL` | `()` | A function >call was made when the log event was created |
|
||||
| `LAMBDA_CALL` | `λ` | A lambda call was made when the log event was created |
|
||||
| `EVAL_CALL` | `eval()` | An eval call was made when the log event was created |
|
||||
|
||||
## Log Formats
|
||||
|
||||
The LogFormat enumeration in the LogLib2 namespace provides five distinct formats for serializing log entries.
|
||||
Each format is designed to suit different logging needs and use cases, such as machine-readable formats (JSONL, XML),
|
||||
human-readable formats (TXT, HTML), or structured formats (CSV).
|
||||
|
||||
These log formats are designed to be used for the following handlers:
|
||||
|
||||
- Descriptor Logging
|
||||
- File Logging
|
||||
- HTTP Logging
|
||||
- TCP Logging
|
||||
- UDP Logging
|
||||
|
||||
But note the common behavior of each handler when serializing log entries:
|
||||
|
||||
- File Logging: Appends a newline (\n) to the serialized log entry automatically.
|
||||
- HTTP, UDP, TCP, Descriptor Logging: Does not append a newline (\n) to the serialized log entry.
|
||||
|
||||
### JSONL
|
||||
|
||||
Produces a single-line JSON representation of the log entry. This format is highly efficient for processing large
|
||||
volumes of logs as each log entry occupies a single line.
|
||||
|
||||
```json
|
||||
{"timestamp":"16:00:23","level":"ERROR","message":"An error occurred","trace":"Some trace details","exception":{"name":"ExceptionName","message":"Error details"}}
|
||||
```
|
||||
|
||||
JSON Objects follows the same object structure format as the [Event](#event) object type.
|
||||
|
||||
### CSV
|
||||
|
||||
Produces a CSV representation of the log entry. This format is useful for exporting log entries to a spreadsheet or
|
||||
database for further analysis.
|
||||
|
||||
> Note: Only the File handler will use CSV headers, this only happens when trying to create a .csv file that doesn't
|
||||
> exist, LogLib will automatically create the file with the headers included.
|
||||
|
||||
The CSV format is as follows:
|
||||
|
||||
```csv
|
||||
timestamp,level,message,trace,exception
|
||||
16:00:23,ERROR,An error occurred,<trace>,<json encoded exception details>
|
||||
```
|
||||
|
||||
- `timestamp`: The timestamp of the log entry, formatted using the [TimestampFormat](#timestampformat).
|
||||
- `level`: The level of the log entry, eg; `INF`.
|
||||
- `message`: The message of the log entry.
|
||||
- `trace`: The trace of the event, formatted using the [TraceFormat](#traceformat).
|
||||
- `exception`: JSON encoded exception details, formatted using the [ExceptionDetails](#exceptiondetails) object type.
|
||||
|
||||
|
||||
### TXT
|
||||
|
||||
Produces a human-readable text representation of the log entry. This format is useful for viewing log entries in a
|
||||
text editor or terminal.
|
||||
|
||||
The TXT format is as follows:
|
||||
|
||||
```
|
||||
05:45:38 [INFO] This is an example log message.
|
||||
05:45:38 [INFO] This is an example log message.
|
||||
05:45:38 [INFO] This is an example log message.
|
||||
05:45:38 [INFO] This is an example log message.
|
||||
05:45:38 [INFO] This is an example log message.
|
||||
05:45:38 [INFO] This is an example log message.
|
||||
05:45:38 [INFO] This is an example log message.
|
||||
05:45:38 [INFO] This is an example log message.
|
||||
05:45:39 [INFO] This is an example log message.
|
||||
05:45:39 [INFO] This is an example log message.
|
||||
05:45:39 [ERR] test
|
||||
Exception: This is an example exception. (0)
|
||||
File: LogLib2/examples/example1.php:22
|
||||
05:45:39 [INFO] ExampleClass::sleepExample Sleeping for 5 seconds...
|
||||
05:45:44 [INFO] ExampleClass::sleepExample Finished sleeping for 5 seconds.
|
||||
05:45:39 [WRN] LogLib2\Logger::LogLib2\{closure} Undefined array key "foo"
|
||||
Runtime: Undefined array key "foo" (2)
|
||||
File: LogLib2/examples/example1.php:20
|
||||
05:45:44 [ERR] LogLib2\Logger::LogLib2\{closure} this is a new exception
|
||||
Exception: this is a new exception (0)
|
||||
File: LogLib2/examples/example_class.php:32
|
||||
ExampleClassthrowDoubleException (LogLib2/examples/example1.php:29)
|
||||
Exception: This is an example exception. (0)
|
||||
File: LogLib2/examples/example_class.php:22
|
||||
ExampleClassthrowException (LogLib2/examples/example_class.php:28)
|
||||
ExampleClassthrowDoubleException (LogLib2/examples/example1.php:29)
|
||||
```
|
||||
|
||||
### XML
|
||||
|
||||
Produces an XML representation of the log entry. This format is useful for exporting log entries to an XML file or
|
||||
The XML structure follows the same object structure as [Event](#event)
|
||||
|
||||
```xml
|
||||
<event>
|
||||
<application_name>Runtime</application_name>
|
||||
<timestamp>05:52:58</timestamp>
|
||||
<level>WRN</level>
|
||||
<message>WRN</message>
|
||||
<trace>LogLib2\Logger::LogLib2\{closure}</trace>
|
||||
<stack_trace>
|
||||
<trace>
|
||||
<file>LogLib2/examples/example1.php</file>
|
||||
<line>20</line>
|
||||
<function>LogLib2\{closure}</function>
|
||||
<class>LogLib2\Logger</class>
|
||||
<arguments>
|
||||
<argument>"2"</argument>
|
||||
<argument>"Undefined array key \"foo\""</argument>
|
||||
<argument>"LogLib2/examples/example1.php"</argument>
|
||||
<argument>"20"</argument>
|
||||
</arguments>
|
||||
</trace>
|
||||
</stack_trace>
|
||||
<exception>
|
||||
<name>Runtime</name>
|
||||
<message>Undefined array key "foo"</message>
|
||||
<code>2</code>
|
||||
<file>LogLib2/examples/example1.php</file>
|
||||
<line>20</line>
|
||||
</exception>
|
||||
</event>
|
||||
```
|
||||
|
||||
```xml
|
||||
|
||||
<event>
|
||||
<application_name>Runtime</application_name>
|
||||
<timestamp>05:53:03</timestamp>
|
||||
<level>ERR</level>
|
||||
<message>ERR</message>
|
||||
<trace>LogLib2\Logger::LogLib2\{closure}</trace>
|
||||
<stack_trace>
|
||||
<trace>
|
||||
<function>LogLib2\{closure}</function>
|
||||
<class>LogLib2\Logger</class>
|
||||
<arguments>
|
||||
<argument>"[OBJECT]"</argument>
|
||||
</arguments>
|
||||
</trace>
|
||||
</stack_trace>
|
||||
<exception>
|
||||
<name>Exception</name>
|
||||
<message>this is a new exception</message>
|
||||
<code>0</code>
|
||||
<file>LogLib2/examples/example_class.php</file>
|
||||
<line>32</line>
|
||||
<stack_trace>
|
||||
<trace>
|
||||
<file>LogLib2/examples/example1.php</file>
|
||||
<line>29</line>
|
||||
<function>throwDoubleException</function>
|
||||
<class>ExampleClass</class>
|
||||
</trace>
|
||||
</stack_trace>
|
||||
<previous>
|
||||
<name>Exception</name>
|
||||
<message>This is an example exception.</message>
|
||||
<code>0</code>
|
||||
<file>LogLib2/examples/example_class.php</file>
|
||||
<line>22</line>
|
||||
<stack_trace>
|
||||
<trace>
|
||||
<file>LogLib2/examples/example_class.php</file>
|
||||
<line>28</line>
|
||||
<function>throwException</function>
|
||||
<class>ExampleClass</class>
|
||||
</trace>
|
||||
<trace>
|
||||
<file>LogLib2/examples/example1.php</file>
|
||||
<line>29</line>
|
||||
<function>throwDoubleException</function>
|
||||
<class>ExampleClass</class>
|
||||
</trace>
|
||||
</stack_trace>
|
||||
</previous>
|
||||
</exception>
|
||||
</event>
|
||||
```
|
||||
|
||||
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
# License
|
||||
|
||||
The LogLib2 library is licensed under the MIT License, see the [LICENSE](LICENSE) file for more information.
|
29
examples/example1.php
Normal file
29
examples/example1.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
require 'ncc';
|
||||
require 'example_class.php';
|
||||
|
||||
import('net.nosial.loglib2');
|
||||
|
||||
\LogLib2\Logger::setBacktraceLevel(3);
|
||||
\LogLib2\Logger::registerHandlers();
|
||||
$logger = new \LogLib2\Logger('Example');
|
||||
|
||||
// Iterate 10 times
|
||||
for($i = 0; $i < 10; $i++)
|
||||
{
|
||||
// Log a message with a random log level
|
||||
$logger->info('This is an example log message.');
|
||||
}
|
||||
|
||||
$a = [];
|
||||
$b = $a['foo']; // <-- This will throw a notice that will be caught by the logger
|
||||
|
||||
$exception = new \Exception('This is an example exception.');
|
||||
$logger->error("test", $exception);
|
||||
|
||||
|
||||
|
||||
$example = new ExampleClass($logger);
|
||||
$example->sleepExample(5);
|
||||
$example->throwDoubleException();
|
39
examples/example_class.php
Normal file
39
examples/example_class.php
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
class ExampleClass {
|
||||
|
||||
private \LogLib2\Logger $logger;
|
||||
|
||||
public function __construct(\LogLib2\Logger $logger) {
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
public function getLogger(): \LogLib2\Logger {
|
||||
return $this->logger;
|
||||
}
|
||||
|
||||
public function sleepExample(int $seconds): void {
|
||||
$this->logger->info("Sleeping for $seconds seconds...");
|
||||
sleep($seconds);
|
||||
$this->logger->info("Finished sleeping for $seconds seconds.");
|
||||
}
|
||||
|
||||
public function throwException(): void {
|
||||
throw new \Exception("This is an example exception.");
|
||||
}
|
||||
|
||||
public function throwDoubleException(): void {
|
||||
try
|
||||
{
|
||||
$this->throwException();
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
throw new Exception("this is a new exception", 0, $e);
|
||||
}
|
||||
}
|
||||
|
||||
public function warningExceptionExample(): void {
|
||||
$this->logger->warning("Throwing a warning exception...", new \Exception("This is an example warning exception."));
|
||||
}
|
||||
}
|
10
project.json
10
project.json
|
@ -4,9 +4,6 @@
|
|||
"extension": "php",
|
||||
"minimum_version": "8.0",
|
||||
"maximum_version": "8.2"
|
||||
},
|
||||
"options": {
|
||||
"create_symlink": true
|
||||
}
|
||||
},
|
||||
"assembly": {
|
||||
|
@ -24,6 +21,13 @@
|
|||
"ASSEMBLY_VERSION": "%ASSEMBLY.VERSION%",
|
||||
"ASSEMBLY_UID": "%ASSEMBLY.UID%"
|
||||
},
|
||||
"dependencies": [
|
||||
{
|
||||
"name": "net.nosial.optslib",
|
||||
"version": "latest",
|
||||
"source": "nosial/libs.opts=latest@n64"
|
||||
}
|
||||
],
|
||||
"configurations": [
|
||||
{
|
||||
"name": "release",
|
||||
|
|
358
server.py
Normal file
358
server.py
Normal file
|
@ -0,0 +1,358 @@
|
|||
# This is a simple server that listens on both TCP and UDP ports and logs incoming messages to a file & console.
|
||||
# To use this with LogLib, simply start the server and configure the LogLib client to send logs to the server.
|
||||
# The following environment variables can be used to configure LogLib to send logs to the server:
|
||||
#
|
||||
# - LOGLIB_UDP_ENABLED=true (enable UDP logging)
|
||||
# - LOGLIB_UDP_HOST=0.0.0.0 (UDP host)
|
||||
# - LOGLIB_UDP_PORT=5131 (UDP port, default 5131)
|
||||
#
|
||||
# This server is designed to only accept JSON-formatted log messages using the UnixTimestamp for the Timestamps,
|
||||
# TraceLevels can be anything.
|
||||
#
|
||||
# After configuring the environment variables, start the server & run your program. Logging events should be
|
||||
# sent to the server and logged to the console and a file in the specified working directory.
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import socket
|
||||
import threading
|
||||
from datetime import datetime
|
||||
from queue import Queue, Empty
|
||||
from enum import Enum
|
||||
from typing import Optional, Dict, Any, List
|
||||
from dataclasses import dataclass
|
||||
import colorama
|
||||
from colorama import Fore, Back, Style
|
||||
|
||||
colorama.init()
|
||||
|
||||
|
||||
class LogLevel(str, Enum):
|
||||
DEBUG = "DBG"
|
||||
VERBOSE = "VRB"
|
||||
INFO = "INFO"
|
||||
WARNING = "WRN"
|
||||
ERROR = "ERR"
|
||||
CRITICAL = "CRT"
|
||||
|
||||
@classmethod
|
||||
def to_python_level(cls, level: str) -> int:
|
||||
return {
|
||||
cls.DEBUG: logging.DEBUG,
|
||||
cls.VERBOSE: logging.DEBUG,
|
||||
cls.INFO: logging.INFO,
|
||||
cls.WARNING: logging.WARNING,
|
||||
cls.ERROR: logging.ERROR,
|
||||
cls.CRITICAL: logging.CRITICAL
|
||||
}.get(level, logging.INFO)
|
||||
|
||||
@classmethod
|
||||
def get_color(cls, level: str) -> str:
|
||||
return {
|
||||
cls.DEBUG: Fore.CYAN,
|
||||
cls.VERBOSE: Fore.BLUE,
|
||||
cls.INFO: Fore.GREEN,
|
||||
cls.WARNING: Fore.YELLOW,
|
||||
cls.ERROR: Fore.RED,
|
||||
cls.CRITICAL: Fore.RED + Back.WHITE
|
||||
}.get(level, Fore.WHITE)
|
||||
|
||||
|
||||
@dataclass
|
||||
class StackFrame:
|
||||
file: Optional[str]
|
||||
line: Optional[int]
|
||||
function: Optional[str]
|
||||
args: Optional[List[Any]]
|
||||
class_name: Optional[str]
|
||||
call_type: str = 'static'
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: Dict[str, Any]) -> 'StackFrame':
|
||||
return cls(
|
||||
file=str(data.get('file')) if data.get('file') else None,
|
||||
line=int(data['line']) if data.get('line') is not None else None,
|
||||
function=str(data.get('function')) if data.get('function') else None,
|
||||
args=data.get('args'),
|
||||
class_name=str(data.get('class')) if data.get('class') else None,
|
||||
call_type=str(data.get('callType', 'static'))
|
||||
)
|
||||
|
||||
def format(self) -> str:
|
||||
location = f"{self.file or '?'}:{self.line or '?'}"
|
||||
if self.class_name:
|
||||
call = f"{self.class_name}{self.call_type}{self.function or ''}"
|
||||
else:
|
||||
call = self.function or ''
|
||||
|
||||
args_str = ""
|
||||
if self.args:
|
||||
args_str = f"({', '.join(str(arg) for arg in self.args)})"
|
||||
|
||||
return f"{Fore.BLUE}{call}{Style.RESET_ALL}{args_str} in {Fore.CYAN}{location}{Style.RESET_ALL}"
|
||||
|
||||
|
||||
class ExceptionDetails:
|
||||
def __init__(self, name: str, message: str, code: Optional[int],
|
||||
file: Optional[str], line: Optional[int],
|
||||
trace: List[StackFrame], previous: Optional['ExceptionDetails']):
|
||||
self.name = name
|
||||
self.message = message
|
||||
self.code = code
|
||||
self.file = file
|
||||
self.line = line
|
||||
self.trace = trace
|
||||
self.previous = previous
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: Dict[str, Any]) -> Optional['ExceptionDetails']:
|
||||
if not data:
|
||||
return None
|
||||
|
||||
trace = []
|
||||
if 'trace' in data and isinstance(data['trace'], list):
|
||||
trace = [StackFrame.from_dict(frame) for frame in data['trace']
|
||||
if isinstance(frame, dict)]
|
||||
|
||||
previous = None
|
||||
if 'previous' in data and isinstance(data['previous'], dict):
|
||||
previous = cls.from_dict(data['previous'])
|
||||
|
||||
return cls(
|
||||
name=str(data.get('name', '')),
|
||||
message=str(data.get('message', '')),
|
||||
code=int(data['code']) if data.get('code') is not None else None,
|
||||
file=str(data.get('file')) if data.get('file') else None,
|
||||
line=int(data['line']) if data.get('line') is not None else None,
|
||||
trace=trace,
|
||||
previous=previous
|
||||
)
|
||||
|
||||
def format(self, level: int = 0) -> str:
|
||||
indent = " " * level
|
||||
parts = []
|
||||
|
||||
# Exception header
|
||||
header = f"{indent}{Fore.RED}{self.name}"
|
||||
if self.code is not None and 0:
|
||||
header += f" {Fore.YELLOW}:{self.code}{Style.RESET_ALL}"
|
||||
|
||||
# Message
|
||||
header += f"{Fore.WHITE}:{Style.RESET_ALL} {self.message}"
|
||||
|
||||
# Location
|
||||
if self.file and self.line:
|
||||
header += f"{Fore.WHITE} at {Style.RESET_ALL}{self.file}:{self.line}"
|
||||
|
||||
parts.append(header)
|
||||
|
||||
# Stack trace
|
||||
if self.trace:
|
||||
parts.append(f"{indent}{Fore.WHITE}Stack trace:{Style.RESET_ALL}")
|
||||
for frame in self.trace:
|
||||
parts.append(f"{indent} → {frame.format()}")
|
||||
|
||||
# Previous exception
|
||||
if self.previous:
|
||||
parts.append(f"{indent}{Fore.YELLOW}Caused by:{Style.RESET_ALL}")
|
||||
parts.append(self.previous.format(level + 1))
|
||||
|
||||
return "\n".join(parts)
|
||||
|
||||
|
||||
class ColoredLogger(logging.Logger):
|
||||
def __init__(self, name: str):
|
||||
super().__init__(name)
|
||||
self.formatter = logging.Formatter(
|
||||
f'%(asctime)s {Fore.WHITE}[%(levelname)s]{Style.RESET_ALL} %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
|
||||
console_handler = logging.StreamHandler()
|
||||
console_handler.setFormatter(self.formatter)
|
||||
self.addHandler(console_handler)
|
||||
|
||||
|
||||
class MultiProtocolServer:
|
||||
def __init__(self, host: str, port: int, working_directory: str):
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.working_directory = working_directory
|
||||
self.log_queue: Queue = Queue()
|
||||
self.current_date = datetime.now().strftime('%Y-%m-%d')
|
||||
self.log_file = None
|
||||
self.stop_event = threading.Event()
|
||||
|
||||
os.makedirs(self.working_directory, exist_ok=True)
|
||||
|
||||
# Set up colored logging
|
||||
logging.setLoggerClass(ColoredLogger)
|
||||
self.logger = logging.getLogger("MultiProtocolServer")
|
||||
self.logger.setLevel(logging.DEBUG)
|
||||
|
||||
def _handle_log_event(self, data: Dict[str, Any], address: tuple) -> None:
|
||||
"""Process and format a structured log event with colors and proper formatting."""
|
||||
try:
|
||||
app_name = data.get('application_name', 'Unknown')
|
||||
timestamp = data.get('timestamp')
|
||||
if timestamp:
|
||||
try:
|
||||
timestamp = datetime.fromtimestamp(int(timestamp))
|
||||
timestamp = timestamp.strftime('%Y-%m-%d %H:%M:%S')
|
||||
except (ValueError, TypeError):
|
||||
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
else:
|
||||
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
|
||||
level = data.get('level', 'INFO')
|
||||
message = data.get('message', '')
|
||||
|
||||
# Format the log message with colors
|
||||
color = LogLevel.get_color(level)
|
||||
log_message = f"{color}[{app_name}]{Style.RESET_ALL} {message}"
|
||||
|
||||
# Handle exception if present
|
||||
exception_data = data.get('exception')
|
||||
if exception_data:
|
||||
exception = ExceptionDetails.from_dict(exception_data)
|
||||
if exception:
|
||||
log_message += f"\n{exception.format()}"
|
||||
|
||||
# Log with appropriate level
|
||||
python_level = LogLevel.to_python_level(level)
|
||||
self.logger.log(python_level, log_message)
|
||||
|
||||
# Add to log queue for file logging
|
||||
self.log_queue.put({
|
||||
"timestamp": timestamp,
|
||||
"address": address,
|
||||
"data": data
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error processing log event: {e}", exc_info=True)
|
||||
|
||||
def _handle_data(self, data: bytes, address: tuple) -> None:
|
||||
"""Process incoming data and attempt to parse as JSON."""
|
||||
try:
|
||||
decoded_data = data.decode('utf-8').strip()
|
||||
|
||||
try:
|
||||
json_data = json.loads(decoded_data)
|
||||
# Handle structured log event
|
||||
self._handle_log_event(json_data, address)
|
||||
except json.JSONDecodeError:
|
||||
# Log raw data if not valid JSON
|
||||
self.logger.info(f"Received non-JSON data from {address}: {decoded_data}")
|
||||
self.log_queue.put({
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"address": address,
|
||||
"data": decoded_data
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Data handling error: {e}")
|
||||
|
||||
# Rest of the class remains the same...
|
||||
def _get_log_file(self):
|
||||
date = datetime.now().strftime('%Y-%m-%d')
|
||||
if date != self.current_date or self.log_file is None:
|
||||
if self.log_file:
|
||||
self.log_file.close()
|
||||
self.current_date = date
|
||||
filename = os.path.join(self.working_directory, f"log{date}.jsonl")
|
||||
self.log_file = open(filename, 'a')
|
||||
return self.log_file
|
||||
|
||||
def _log_writer(self):
|
||||
while not self.stop_event.is_set() or not self.log_queue.empty():
|
||||
try:
|
||||
data = self.log_queue.get(timeout=1)
|
||||
log_file = self._get_log_file()
|
||||
json.dump(data, log_file)
|
||||
log_file.write('\n')
|
||||
log_file.flush()
|
||||
except Empty:
|
||||
continue
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error writing to log file: {e}")
|
||||
|
||||
def _handle_tcp_client(self, client_socket, address):
|
||||
self.logger.info(f"TCP connection established from {address}")
|
||||
try:
|
||||
with client_socket:
|
||||
while True:
|
||||
data = client_socket.recv(4096)
|
||||
if not data:
|
||||
break
|
||||
self._handle_data(data, address)
|
||||
except Exception as e:
|
||||
self.logger.error(f"TCP client error: {e}")
|
||||
self.logger.info(f"TCP connection closed from {address}")
|
||||
|
||||
def _handle_udp_client(self, data, address):
|
||||
try:
|
||||
self._handle_data(data, address)
|
||||
except Exception as e:
|
||||
self.logger.error(f"UDP client error: {e}")
|
||||
|
||||
def _start_tcp_server(self):
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as tcp_socket:
|
||||
tcp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
tcp_socket.bind((self.host, self.port))
|
||||
tcp_socket.listen(5)
|
||||
self.logger.debug(f"TCP server running on {self.host}:{self.port}")
|
||||
|
||||
while not self.stop_event.is_set():
|
||||
try:
|
||||
client_socket, address = tcp_socket.accept()
|
||||
threading.Thread(target=self._handle_tcp_client,
|
||||
args=(client_socket, address),
|
||||
daemon=True).start()
|
||||
except Exception as e:
|
||||
self.logger.error(f"TCP server error: {e}")
|
||||
|
||||
def _start_udp_server(self):
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as udp_socket:
|
||||
udp_socket.bind((self.host, self.port))
|
||||
self.logger.debug(f"UDP server running on {self.host}:{self.port}")
|
||||
|
||||
while not self.stop_event.is_set():
|
||||
try:
|
||||
data, address = udp_socket.recvfrom(4096)
|
||||
self._handle_udp_client(data, address)
|
||||
except Exception as e:
|
||||
self.logger.error(f"UDP server error: {e}")
|
||||
|
||||
def start(self):
|
||||
self.logger.info("Starting MultiProtocolServer...")
|
||||
threading.Thread(target=self._log_writer, daemon=True).start()
|
||||
tcp_thread = threading.Thread(target=self._start_tcp_server, daemon=True)
|
||||
udp_thread = threading.Thread(target=self._start_udp_server, daemon=True)
|
||||
tcp_thread.start()
|
||||
udp_thread.start()
|
||||
|
||||
try:
|
||||
tcp_thread.join()
|
||||
udp_thread.join()
|
||||
except KeyboardInterrupt:
|
||||
self.stop()
|
||||
|
||||
def stop(self):
|
||||
self.logger.info("Stopping MultiProtocolServer...")
|
||||
self.stop_event.set()
|
||||
if self.log_file:
|
||||
self.log_file.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="MultiProtocol Server")
|
||||
parser.add_argument("-p", "--port", type=int, default=5131,
|
||||
help="Port to listen on")
|
||||
parser.add_argument("-w", "--working-directory", type=str,
|
||||
default="./logs", help="Directory to store log files")
|
||||
args = parser.parse_args()
|
||||
|
||||
server = MultiProtocolServer("0.0.0.0", args.port, args.working_directory)
|
||||
server.start()
|
133
src/LogLib2/Classes/FileLock.php
Normal file
133
src/LogLib2/Classes/FileLock.php
Normal file
|
@ -0,0 +1,133 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Classes;
|
||||
|
||||
use LogLib2\Exceptions\IOException;
|
||||
|
||||
class FileLock
|
||||
{
|
||||
private $fileHandle;
|
||||
private int $permissions;
|
||||
private string $filePath;
|
||||
private int $retryInterval; // in microseconds
|
||||
private int $confirmationInterval; // in microseconds
|
||||
|
||||
/**
|
||||
* Constructor for FileLock.
|
||||
*
|
||||
* @param string $filePath Path to the file.
|
||||
* @param int $permissions
|
||||
* @param int $retryInterval Time to wait between retries (in microseconds).
|
||||
* @param int $confirmationInterval Time to wait before double confirmation (in microseconds).
|
||||
* @throws IOException if unable to create the file or set the permissions.
|
||||
*/
|
||||
public function __construct(string $filePath, int $permissions, int $retryInterval=100000, int $confirmationInterval=50000)
|
||||
{
|
||||
$this->filePath = $filePath;
|
||||
$this->permissions = $permissions;
|
||||
$this->retryInterval = $retryInterval;
|
||||
$this->confirmationInterval = $confirmationInterval;
|
||||
|
||||
// Create the file if it doesn't exist
|
||||
if (!file_exists($filePath))
|
||||
{
|
||||
// Create the file
|
||||
if(!@touch($filePath))
|
||||
{
|
||||
throw new IOException("Unable to create the file: " . $filePath);
|
||||
}
|
||||
|
||||
if(!@chmod($filePath, $this->permissions))
|
||||
{
|
||||
throw new IOException("Unable to set the file permissions: " . $filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks the file.
|
||||
*
|
||||
* @throws IOException if unable to open or lock the file.
|
||||
*/
|
||||
private function lock(): bool
|
||||
{
|
||||
$this->fileHandle = @fopen($this->filePath, 'a');
|
||||
if ($this->fileHandle === false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Keep trying to acquire the lock until it succeeds
|
||||
while (!flock($this->fileHandle, LOCK_EX))
|
||||
{
|
||||
usleep($this->retryInterval); // Wait for the specified interval before trying again
|
||||
}
|
||||
|
||||
// Double confirmation
|
||||
usleep($this->confirmationInterval); // Wait for the specified confirmation interval
|
||||
if (!flock($this->fileHandle, LOCK_EX | LOCK_NB))
|
||||
{
|
||||
// If the lock cannot be re-acquired, release the current lock and retry
|
||||
flock($this->fileHandle, LOCK_UN);
|
||||
$this->lock();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks the file after performing write operations.
|
||||
*/
|
||||
private function unlock(): void
|
||||
{
|
||||
if ($this->fileHandle !== null)
|
||||
{
|
||||
flock($this->fileHandle, LOCK_UN); // Release the lock
|
||||
fclose($this->fileHandle); // Close the file handle
|
||||
$this->fileHandle = null; // Reset the file handle
|
||||
|
||||
// Check if write permissions have changed
|
||||
if (!is_writable($this->filePath))
|
||||
{
|
||||
// Set the file permissions to the default
|
||||
chmod($this->filePath, $this->permissions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends data to the file.
|
||||
*
|
||||
* @param string $data Data to append.
|
||||
* @throws IOException if unable to write to the file.
|
||||
*/
|
||||
public function append(string $data): void
|
||||
{
|
||||
if(!$this->lock())
|
||||
{
|
||||
// Do not proceed if the file cannot be locked
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->fileHandle !== false)
|
||||
{
|
||||
if (fwrite($this->fileHandle, $data) === false)
|
||||
{
|
||||
throw new IOException("Unable to write to the file: " . $this->filePath);
|
||||
}
|
||||
}
|
||||
|
||||
$this->unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor to ensure the file handle is closed.
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
if ($this->fileHandle)
|
||||
{
|
||||
fclose($this->fileHandle);
|
||||
}
|
||||
}
|
||||
}
|
309
src/LogLib2/Classes/LogHandlers/ConsoleHandler.php
Normal file
309
src/LogLib2/Classes/LogHandlers/ConsoleHandler.php
Normal file
|
@ -0,0 +1,309 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Classes\LogHandlers;
|
||||
|
||||
use LogLib2\Enums\AnsiFormat;
|
||||
use LogLib2\Enums\ConsoleColor;
|
||||
use LogLib2\Enums\LogLevel;
|
||||
use LogLib2\Enums\TimestampFormat;
|
||||
use LogLib2\Enums\TraceFormat;
|
||||
use LogLib2\Interfaces\LogHandlerInterface;
|
||||
use LogLib2\Objects\Application;
|
||||
use LogLib2\Objects\Event;
|
||||
use LogLib2\Objects\ExceptionDetails;
|
||||
use Random\RandomException;
|
||||
|
||||
class ConsoleHandler implements LogHandlerInterface
|
||||
{
|
||||
private static array $applicationColors = [];
|
||||
|
||||
/**
|
||||
* Checks if the current PHP environment is available for execution in CLI mode.
|
||||
*
|
||||
* @return bool True if the PHP environment is running in CLI mode, false otherwise.
|
||||
*/
|
||||
public static function isAvailable(Application $application): bool
|
||||
{
|
||||
return php_sapi_name() === 'cli';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function handleEvent(Application $application, Event $event): void
|
||||
{
|
||||
// Output the event to the console based on the ANSI style.
|
||||
$output = match($application->getConsoleConfiguration()->getAnsiFormat())
|
||||
{
|
||||
AnsiFormat::NONE => self::noAnsi($application, $event),
|
||||
AnsiFormat::BASIC => self::basicOutput($application, $event),
|
||||
};
|
||||
|
||||
// Output the event to the appropriate console stream based on the LogLevel.
|
||||
switch($event->getLevel())
|
||||
{
|
||||
case LogLevel::DEBUG:
|
||||
case LogLevel::VERBOSE:
|
||||
case LogLevel::INFO:
|
||||
fwrite(STDOUT, $output);
|
||||
break;
|
||||
|
||||
case LogLevel::WARNING:
|
||||
case LogLevel::ERROR:
|
||||
case LogLevel::CRITICAL:
|
||||
fwrite(STDERR, $output);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the event to the console.
|
||||
*
|
||||
* @param Application $application The application that generated the event.
|
||||
* @param Event $event The event to output.
|
||||
*/
|
||||
private static function noAnsi(Application $application, Event $event): string
|
||||
{
|
||||
$output = (string)null;
|
||||
|
||||
if($application->getConsoleConfiguration()->getTimestampFormat() !== TimestampFormat::NONE)
|
||||
{
|
||||
$output .= $application->getConsoleConfiguration()->getTimestampFormat()->format($event->getTimestamp());
|
||||
}
|
||||
|
||||
if($application->getConsoleConfiguration()->isDisplayName())
|
||||
{
|
||||
if($output !== (string)null)
|
||||
{
|
||||
$output .= ' ';
|
||||
}
|
||||
|
||||
$output .= $application->getName();
|
||||
}
|
||||
|
||||
if($application->getConsoleConfiguration()->isDisplayLevel())
|
||||
{
|
||||
if($output !== (string)null)
|
||||
{
|
||||
$output .= ' ';
|
||||
}
|
||||
|
||||
$output .= sprintf('[%s]', $event->getLevel()->value);
|
||||
}
|
||||
|
||||
if($application->getConsoleConfiguration()->getTraceFormat() !== TraceFormat::NONE && $event->getFirstTrace() !== null)
|
||||
{
|
||||
if($output !== (string)null)
|
||||
{
|
||||
$output .= ' ';
|
||||
}
|
||||
|
||||
$output .= $application->getConsoleConfiguration()->getTraceFormat()->format($event->getFirstTrace());
|
||||
}
|
||||
|
||||
if($output !== (string)null)
|
||||
{
|
||||
$output .= $event->getMessage();
|
||||
}
|
||||
|
||||
|
||||
if($event->getException() !== null)
|
||||
{
|
||||
$output .= self::noAnsiException($event->getException());
|
||||
}
|
||||
|
||||
return $output . "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the exception details in a basic format.
|
||||
*
|
||||
* @param ExceptionDetails $exception The exception details to output.
|
||||
* @param bool $previous If this is a previous exception in the chain.
|
||||
* @return string The formatted exception details.
|
||||
*/
|
||||
private static function noAnsiException(ExceptionDetails $exception, bool $previous=false): string
|
||||
{
|
||||
if($previous)
|
||||
{
|
||||
$output = sprintf("%s", $exception->getName());
|
||||
}
|
||||
else
|
||||
{
|
||||
$output = sprintf("\n%s", $exception->getName());
|
||||
}
|
||||
|
||||
if($exception->getCode() !== 0 && $exception->getCode() !== null)
|
||||
{
|
||||
$output .= sprintf(" (%d)", $exception->getCode());
|
||||
}
|
||||
|
||||
if($exception->getMessage() !== null)
|
||||
{
|
||||
$output .= sprintf(": %s", $exception->getMessage());
|
||||
}
|
||||
|
||||
if($exception->getFile() !== null)
|
||||
{
|
||||
$output .= sprintf(" File: %s", $exception->getFile());
|
||||
|
||||
if($exception->getLine() !== null && $exception->getLine() !== 0)
|
||||
{
|
||||
$output .= sprintf(":%d", $exception->getLine());
|
||||
}
|
||||
}
|
||||
|
||||
if($exception->getTrace() !== null)
|
||||
{
|
||||
$output .= "\n Stack Trace:\n";
|
||||
foreach($exception->getTrace() as $trace)
|
||||
{
|
||||
$output .= sprintf(" - %s\n", TraceFormat::FULL->format($trace));
|
||||
}
|
||||
}
|
||||
|
||||
if($exception->getPrevious() !== null)
|
||||
{
|
||||
$output .= self::noAnsiException($exception->getPrevious(), true);
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the exception details in a basic format.
|
||||
*
|
||||
* @param Application $application The application that generated the event.
|
||||
* @param Event $event The event to output.
|
||||
* @return string The formatted exception details.
|
||||
* @throws RandomException Thrown when the random_int function fails to generate a random integer.
|
||||
*/
|
||||
private static function basicOutput(Application $application, Event $event): string
|
||||
{
|
||||
$output = (string)null;
|
||||
|
||||
if($application->getConsoleConfiguration()->getTimestampFormat() !== TimestampFormat::NONE)
|
||||
{
|
||||
$output .= ConsoleColor::DEFAULT->formatBold($application->getConsoleConfiguration()->getTimestampFormat()->format($event->getTimestamp()));
|
||||
}
|
||||
|
||||
if($application->getConsoleConfiguration()->isDisplayName())
|
||||
{
|
||||
if($output !== (string)null)
|
||||
{
|
||||
$output .= ' ';
|
||||
}
|
||||
|
||||
$output .= self::getApplicationColor($application)->formatBold($application->getName());
|
||||
}
|
||||
|
||||
if($application->getConsoleConfiguration()->isDisplayLevel())
|
||||
{
|
||||
if($output !== (string)null)
|
||||
{
|
||||
$output .= ' ';
|
||||
}
|
||||
|
||||
$output .= sprintf('[%s]', ConsoleColor::DEFAULT->formatBold($event->getLevel()->value));
|
||||
}
|
||||
|
||||
if($application->getConsoleConfiguration()->getTraceFormat() !== TraceFormat::NONE && $event->getFirstTrace() !== null)
|
||||
{
|
||||
if($output !== (string)null)
|
||||
{
|
||||
$output .= ' ';
|
||||
}
|
||||
|
||||
$output .= $application->getConsoleConfiguration()->getTraceFormat()->format($event->getFirstTrace());
|
||||
}
|
||||
|
||||
if($output !== (string)null)
|
||||
{
|
||||
$output .= ' ';
|
||||
}
|
||||
|
||||
$output .= $event->getMessage();
|
||||
|
||||
if($event->getException() !== null)
|
||||
{
|
||||
$output .= self::basicOutputException($event->getException());
|
||||
}
|
||||
|
||||
return $output . "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the exception details in a basic format.
|
||||
*
|
||||
* @param ExceptionDetails $exception The exception details to output.
|
||||
* @param bool $previous If this is a previous exception in the chain.
|
||||
* @return string The formatted exception details.
|
||||
*/
|
||||
private static function basicOutputException(ExceptionDetails $exception, bool $previous=false): string
|
||||
{
|
||||
if($previous)
|
||||
{
|
||||
$output = sprintf("%s", ConsoleColor::RED->formatBold($exception->getName()));
|
||||
}
|
||||
else
|
||||
{
|
||||
$output = sprintf("\n%s", ConsoleColor::RED->formatBold($exception->getName()));
|
||||
}
|
||||
|
||||
if($exception->getCode() !== 0 && $exception->getCode() !== null)
|
||||
{
|
||||
$output .= sprintf(" (%d)", ConsoleColor::DEFAULT->formatBold($exception->getCode()));
|
||||
}
|
||||
|
||||
if($exception->getMessage() !== null)
|
||||
{
|
||||
$output .= sprintf(": %s", $exception->getMessage());
|
||||
}
|
||||
|
||||
if($exception->getFile() !== null)
|
||||
{
|
||||
$output .= sprintf("\n File: %s", $exception->getFile());
|
||||
|
||||
if($exception->getLine() !== null && $exception->getLine() !== 0)
|
||||
{
|
||||
$output .= sprintf(":%d", ConsoleColor::DEFAULT->formatBold($exception->getLine()));
|
||||
}
|
||||
}
|
||||
|
||||
if($exception->getTrace() !== null && count($exception->getTrace()) > 0)
|
||||
{
|
||||
$output .= "\n Stack Trace:\n";
|
||||
|
||||
foreach($exception->getTrace() as $trace)
|
||||
{
|
||||
$output .= sprintf(" - %s\n", ConsoleColor::DEFAULT->formatLight(TraceFormat::FULL->format($trace)));
|
||||
}
|
||||
}
|
||||
|
||||
if($exception->getPrevious() !== null)
|
||||
{
|
||||
$output .= self::basicOutputException($exception->getPrevious(), true);
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the color for the given application.
|
||||
*
|
||||
* @param Application $application The application to retrieve the color for.
|
||||
* @return ConsoleColor The color for the given application.
|
||||
* @throws RandomException Thrown when the random_int function fails to generate a random integer.
|
||||
*/
|
||||
private static function getApplicationColor(Application $application): ConsoleColor
|
||||
{
|
||||
if(!isset(self::$applicationColors[$application->getName()]))
|
||||
{
|
||||
self::$applicationColors[$application->getName()] = ConsoleColor::getRandomColor([
|
||||
ConsoleColor::BLACK, ConsoleColor::DEFAULT
|
||||
]);
|
||||
}
|
||||
|
||||
return self::$applicationColors[$application->getName()];
|
||||
}
|
||||
}
|
58
src/LogLib2/Classes/LogHandlers/DescriptorHandler.php
Normal file
58
src/LogLib2/Classes/LogHandlers/DescriptorHandler.php
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Classes\LogHandlers;
|
||||
|
||||
use LogLib2\Interfaces\LogHandlerInterface;
|
||||
use LogLib2\Objects\Application;
|
||||
use LogLib2\Objects\Event;
|
||||
|
||||
class DescriptorHandler implements LogHandlerInterface
|
||||
{
|
||||
private static array $resources = [];
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function isAvailable(Application $application): bool
|
||||
{
|
||||
// Check if the descriptor exists
|
||||
if(!file_exists($application->getDescriptorConfiguration()->getDescriptor()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the file lock does not exist, create it to allow for file locking & writing.
|
||||
if(!isset(self::$resources[$application->getName()]))
|
||||
{
|
||||
self::$resources[$application->getName()] = @fopen($application->getDescriptorConfiguration()->getDescriptor(), 'a');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function handleEvent(Application $application, Event $event): void
|
||||
{
|
||||
$message = $application->getDescriptorConfiguration()->getLogFormat()->format(
|
||||
$application->getDescriptorConfiguration()->getTimestampFormat(), $application->getDescriptorConfiguration()->getTraceFormat(), $event
|
||||
);
|
||||
|
||||
if($application->getDescriptorConfiguration()->isAppendNewline())
|
||||
{
|
||||
$message .= PHP_EOL;
|
||||
}
|
||||
|
||||
// Write the event to the descriptor.
|
||||
$result = @fwrite(self::$resources[$application->getName()], $message);
|
||||
|
||||
if($result === false)
|
||||
{
|
||||
@fclose(self::$resources[$application->getName()]);
|
||||
unset(self::$resources[$application->getName()]);
|
||||
self::$resources[$application->getName()] = @fopen($application->getDescriptorConfiguration()->getDescriptor(), 'a');
|
||||
@fwrite(self::$resources[$application->getName()], $message);
|
||||
}
|
||||
}
|
||||
}
|
96
src/LogLib2/Classes/LogHandlers/FileHandler.php
Normal file
96
src/LogLib2/Classes/LogHandlers/FileHandler.php
Normal file
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Classes\LogHandlers;
|
||||
|
||||
use DateTime;
|
||||
use LogLib2\Classes\FileLock;
|
||||
use LogLib2\Classes\Utilities;
|
||||
use LogLib2\Enums\LogFormat;
|
||||
use LogLib2\Interfaces\LogHandlerInterface;
|
||||
use LogLib2\Objects\Application;
|
||||
use LogLib2\Objects\Event;
|
||||
|
||||
class FileHandler implements LogHandlerInterface
|
||||
{
|
||||
private const string CSV_HEADERS = "timestamp,level,message,trace,exception";
|
||||
private static array $fileLocks = [];
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function isAvailable(Application $application): bool
|
||||
{
|
||||
$logPath = $application->getFileConfiguration()->getLogPath();
|
||||
$filePath = self::getLogFilePath($application);
|
||||
|
||||
// If the log path is not writable nor a dir, return false.
|
||||
if(!is_writable($logPath) || !is_dir($logPath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the log file does not exist, create it.
|
||||
if(!file_exists($filePath))
|
||||
{
|
||||
if(!@touch($filePath) || !@chmod($filePath, $application->getFileConfiguration()->getDefaultPermissions()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create the headers for the log file if required.
|
||||
if($application->getFileConfiguration()->getLogFormat() == LogFormat::CSV)
|
||||
{
|
||||
$temporaryLock = new FileLock($filePath, $application->getFileConfiguration()->getDefaultPermissions());
|
||||
$temporaryLock->append(self::CSV_HEADERS . PHP_EOL);
|
||||
unset($temporaryLock);
|
||||
}
|
||||
}
|
||||
|
||||
// If the file lock does not exist, create it to allow for file locking & writing.
|
||||
if(!isset(self::$fileLocks[$application->getName()]))
|
||||
{
|
||||
self::$fileLocks[$application->getName()] = new FileLock($filePath, $application->getFileConfiguration()->getDefaultPermissions());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function handleEvent(Application $application, Event $event): void
|
||||
{
|
||||
$message = $application->getFileConfiguration()->getLogFormat()->format(
|
||||
$application->getFileConfiguration()->getTimestampFormat(), $application->getFileConfiguration()->getTraceFormat(), $event
|
||||
);
|
||||
|
||||
if($application->getFileConfiguration()->isAppendNewline())
|
||||
{
|
||||
$message .= PHP_EOL;
|
||||
}
|
||||
|
||||
self::$fileLocks[$application->getName()]->append($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the log file path for the given application.
|
||||
*
|
||||
* @param Application $application The application to retrieve the log file path for.
|
||||
*
|
||||
* @return string The log file path for the given application.
|
||||
*/
|
||||
private static function getLogFilePath(Application $application): string
|
||||
{
|
||||
$extension = match($application->getFileConfiguration()->getLogFormat())
|
||||
{
|
||||
LogFormat::JSONL => 'jsonl',
|
||||
LogFormat::CSV => 'csv',
|
||||
LogFormat::TXT => 'txt',
|
||||
LogFormat::XML => 'xml',
|
||||
LogFormat::HTML => 'html',
|
||||
};
|
||||
|
||||
return Utilities::getEnvironmentLogPath($application) . DIRECTORY_SEPARATOR .
|
||||
sprintf('%s-%s.%s', Utilities::sanitizeFileName($application->getName()), (new DateTime())->format('Y-m-d'), $extension);
|
||||
}
|
||||
}
|
63
src/LogLib2/Classes/LogHandlers/HttpHandler.php
Normal file
63
src/LogLib2/Classes/LogHandlers/HttpHandler.php
Normal file
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Classes\LogHandlers;
|
||||
|
||||
use LogLib2\Enums\LogFormat;
|
||||
use LogLib2\Interfaces\LogHandlerInterface;
|
||||
use LogLib2\Objects\Application;
|
||||
use LogLib2\Objects\Event;
|
||||
|
||||
class HttpHandler implements LogHandlerInterface
|
||||
{
|
||||
/**
|
||||
* Checks if the current PHP environment is available for execution in CLI mode.
|
||||
*
|
||||
* @return bool True if the PHP environment is running in CLI mode, false otherwise.
|
||||
*/
|
||||
public static function isAvailable(Application $application): bool
|
||||
{
|
||||
if(!function_exists('curl_init'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!filter_var($application->getHttpConfiguration()->getEndpoint(), FILTER_VALIDATE_URL))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function handleEvent(Application $application, Event $event): void
|
||||
{
|
||||
$header = match($application->getHttpConfiguration()->getLogFormat())
|
||||
{
|
||||
LogFormat::JSONL => 'Content-Type: application/json',
|
||||
LogFormat::CSV => 'Content-Type: text/csv',
|
||||
LogFormat::TXT => 'Content-Type: text/plain',
|
||||
LogFormat::XML => 'Content-Type: text/xml',
|
||||
LogFormat::HTML => 'Content-Type: text/html',
|
||||
};
|
||||
|
||||
$message = $application->getHttpConfiguration()->getLogFormat()->format(
|
||||
$application->getHttpConfiguration()->getTimestampFormat(), $application->getHttpConfiguration()->getTraceFormat(), $event
|
||||
);
|
||||
|
||||
if($application->getHttpConfiguration()->isAppendNewline())
|
||||
{
|
||||
$message .= PHP_EOL;
|
||||
}
|
||||
|
||||
// Note, no exception handling is done here. If the HTTP request fails, it will fail silently.
|
||||
$ch = curl_init($application->getHttpConfiguration()->getEndpoint());
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $message);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [$header]);
|
||||
curl_exec($ch);
|
||||
curl_close($ch);
|
||||
}
|
||||
}
|
100
src/LogLib2/Classes/LogHandlers/TcpHandler.php
Normal file
100
src/LogLib2/Classes/LogHandlers/TcpHandler.php
Normal file
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Classes\LogHandlers;
|
||||
|
||||
use LogLib2\Interfaces\LogHandlerInterface;
|
||||
use LogLib2\Objects\Application;
|
||||
use LogLib2\Objects\Event;
|
||||
|
||||
class TcpHandler implements LogHandlerInterface
|
||||
{
|
||||
private static array $sockets = [];
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function isAvailable(Application $application): bool
|
||||
{
|
||||
// Check if the TCP configuration is valid.
|
||||
if(!filter_var($application->getTcpConfiguration()->getHost(), FILTER_VALIDATE_IP))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if($application->getTcpConfiguration()->getPort() < 1 || $application->getTcpConfiguration()->getPort() > 65535)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$socketKey = $application->getTcpConfiguration()->getHost() . ':' . $application->getTcpConfiguration()->getPort();
|
||||
if(!isset(self::$sockets[$socketKey]))
|
||||
{
|
||||
self::$sockets[$socketKey] = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
|
||||
if(self::$sockets[$socketKey] === false)
|
||||
{
|
||||
unset(self::$sockets[$socketKey]);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!@socket_connect(self::$sockets[$socketKey], $application->getTcpConfiguration()->getHost(), $application->getTcpConfiguration()->getPort()))
|
||||
{
|
||||
unset(self::$sockets[$socketKey]);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function handleEvent(Application $application, Event $event): void
|
||||
{
|
||||
$message = $application->getTcpConfiguration()->getLogFormat()->format(
|
||||
$application->getTcpConfiguration()->getTimestampFormat(), $application->getTcpConfiguration()->getTraceFormat(), $event
|
||||
);
|
||||
|
||||
if($application->getTcpConfiguration()->isAppendNewline())
|
||||
{
|
||||
$message .= PHP_EOL;
|
||||
}
|
||||
|
||||
// If the message is too long, fail silently.
|
||||
if(strlen($message) > 65535)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$socketKey = $application->getTcpConfiguration()->getHost() . ':' . $application->getTcpConfiguration()->getPort();
|
||||
if(!isset(self::$sockets[$socketKey]))
|
||||
{
|
||||
self::$sockets[$socketKey] = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
|
||||
if(self::$sockets[$socketKey] === false)
|
||||
{
|
||||
unset(self::$sockets[$socketKey]);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!@socket_connect(self::$sockets[$socketKey], $application->getTcpConfiguration()->getHost(), $application->getTcpConfiguration()->getPort()))
|
||||
{
|
||||
unset(self::$sockets[$socketKey]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If the request fails, try to reconnect and send the message again. if it fails again, fail silently.
|
||||
if(@socket_send(self::$sockets[$socketKey], $message, strlen($message), 0) === false)
|
||||
{
|
||||
if(!@socket_connect(self::$sockets[$socketKey], $application->getTcpConfiguration()->getHost(), $application->getTcpConfiguration()->getPort()))
|
||||
{
|
||||
unset(self::$sockets[$socketKey]);
|
||||
return;
|
||||
}
|
||||
|
||||
@socket_send(self::$sockets[$socketKey], $message, strlen($message), 0);
|
||||
}
|
||||
}
|
||||
}
|
86
src/LogLib2/Classes/LogHandlers/UdpHandler.php
Normal file
86
src/LogLib2/Classes/LogHandlers/UdpHandler.php
Normal file
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Classes\LogHandlers;
|
||||
|
||||
use LogLib2\Interfaces\LogHandlerInterface;
|
||||
use LogLib2\Objects\Application;
|
||||
use LogLib2\Objects\Event;
|
||||
|
||||
class UdpHandler implements LogHandlerInterface
|
||||
{
|
||||
private static array $sockets = [];
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function isAvailable(Application $application): bool
|
||||
{
|
||||
// Check if the UDP configuration is valid.
|
||||
if(!filter_var($application->getUdpConfiguration()->getHost(), FILTER_VALIDATE_IP))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if($application->getUdpConfiguration()->getPort() < 1 || $application->getUdpConfiguration()->getPort() > 65535)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the socket does not exist, create it.
|
||||
$socketKey = $application->getUdpConfiguration()->getHost() . ':' . $application->getUdpConfiguration()->getPort();
|
||||
if(!isset(self::$sockets[$socketKey]))
|
||||
{
|
||||
self::$sockets[$application->getName()] = @socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
|
||||
if(self::$sockets[$application->getName()] === false)
|
||||
{
|
||||
unset(self::$sockets[$socketKey]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function handleEvent(Application $application, Event $event): void
|
||||
{
|
||||
$message = $application->getUdpConfiguration()->getLogFormat()->format(
|
||||
$application->getUdpConfiguration()->getTimestampFormat(), $application->getUdpConfiguration()->getTraceFormat(), $event
|
||||
);
|
||||
|
||||
if($application->getUdpConfiguration()->isAppendNewline())
|
||||
{
|
||||
$message .= PHP_EOL;
|
||||
}
|
||||
|
||||
// If the message is too long, fail silently.
|
||||
if(strlen($message) > 65535)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$socketKey = $application->getUdpConfiguration()->getHost() . ':' . $application->getUdpConfiguration()->getPort();
|
||||
if(!isset(self::$sockets[$socketKey]))
|
||||
{
|
||||
self::$sockets[$socketKey] = @socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
|
||||
if(self::$sockets[$socketKey] === false)
|
||||
{
|
||||
unset(self::$sockets[$socketKey]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If the request fails, try to reconnect and send the message again. if it fails again, fail silently.
|
||||
if(@socket_sendto(self::$sockets[$socketKey], $message, strlen($message), 0, $application->getUdpConfiguration()->getHost(), $application->getUdpConfiguration()->getPort()) === false)
|
||||
{
|
||||
if(!@socket_connect(self::$sockets[$socketKey], $application->getUdpConfiguration()->getHost(), $application->getUdpConfiguration()->getPort()))
|
||||
{
|
||||
unset(self::$sockets[$socketKey]);
|
||||
}
|
||||
|
||||
@socket_sendto(self::$sockets[$socketKey], $message, strlen($message), 0, $application->getUdpConfiguration()->getHost(), $application->getUdpConfiguration()->getPort());
|
||||
}
|
||||
}
|
||||
}
|
184
src/LogLib2/Classes/Utilities.php
Normal file
184
src/LogLib2/Classes/Utilities.php
Normal file
|
@ -0,0 +1,184 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Classes;
|
||||
|
||||
use ErrorException;
|
||||
use LogLib2\Enums\LogLevel;
|
||||
use LogLib2\Objects\Application;
|
||||
use LogLib2\Objects\ExceptionDetails;
|
||||
use LogLib2\Objects\StackTrace;
|
||||
use OptsLib\Parse;
|
||||
use Throwable;
|
||||
|
||||
class Utilities
|
||||
{
|
||||
private static ?array $cachedOptions = null;
|
||||
|
||||
/**
|
||||
* Retrieves the logging level from various sources, including environment variables,
|
||||
* CLI arguments, or from the Application object. Defaults to INFO if no specific
|
||||
* logging level is found.
|
||||
*
|
||||
* @return LogLevel Returns the determined logging level based on the available sources.
|
||||
*/
|
||||
public static function getEnvironmentLogLevel(): LogLevel
|
||||
{
|
||||
// Parse from environment if a variable is set.
|
||||
if(getenv('LOG_LEVEL'))
|
||||
{
|
||||
return LogLevel::parseFrom(getenv('LOG_LEVEL'));
|
||||
}
|
||||
|
||||
// Parse from CLI arguments if the script is running in CLI mode.
|
||||
if(php_sapi_name() === 'cli')
|
||||
{
|
||||
if(self::$cachedOptions === null)
|
||||
{
|
||||
self::$cachedOptions = Parse::getArguments();
|
||||
}
|
||||
|
||||
if(isset(self::$cachedOptions['log-level']))
|
||||
{
|
||||
return LogLevel::parseFrom(self::$cachedOptions['log-level']);
|
||||
}
|
||||
}
|
||||
|
||||
return LogLevel::INFO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the log path for the application from the environment, CLI arguments, or application defaults.
|
||||
*
|
||||
* The method checks if a log path is defined in environment variables, provided as a command-line argument,
|
||||
* or set in the application instance. If no path is specified, it defaults to '/tmp/logs'.
|
||||
*
|
||||
* @param Application|null $application Optional application instance to retrieve a default log path.
|
||||
* @return string The log path determined from the environment, CLI arguments, application instance, or default value.
|
||||
*/
|
||||
public static function getEnvironmentLogPath(?Application $application=null): string
|
||||
{
|
||||
// Parse from CLI arguments if the script is running in CLI mode.
|
||||
if(php_sapi_name() === 'cli')
|
||||
{
|
||||
if(self::$cachedOptions === null)
|
||||
{
|
||||
self::$cachedOptions = Parse::getArguments();
|
||||
}
|
||||
|
||||
if(isset(self::$cachedOptions['log-path']))
|
||||
{
|
||||
return rtrim(self::$cachedOptions['log-path'], DIRECTORY_SEPARATOR);
|
||||
}
|
||||
}
|
||||
|
||||
if($application?->getFileConfiguration()?->getLogPath() !== null)
|
||||
{
|
||||
return rtrim($application->getFileConfiguration()->getLogPath(), DIRECTORY_SEPARATOR);
|
||||
}
|
||||
|
||||
return DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . 'logs';
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes an input value and returns a safely formatted string representation.
|
||||
* Converts arrays and other unsupported data types into a structured string format.
|
||||
*
|
||||
* @param mixed $input The input value to be processed. It can be of any type including arrays, strings, integers, etc.
|
||||
*
|
||||
* @return string A safe and structured string representation of the input value.
|
||||
*/
|
||||
public static function getSafeValue(mixed $input): string
|
||||
{
|
||||
if(is_array($input))
|
||||
{
|
||||
if(array_is_list($input))
|
||||
{
|
||||
$output = [];
|
||||
foreach($input as $value)
|
||||
{
|
||||
$output[] = self::getSafeValue($value);
|
||||
}
|
||||
|
||||
return sprintf('[%s]', implode(', ', $output));
|
||||
}
|
||||
else
|
||||
{
|
||||
$output = [];
|
||||
foreach($input as $key => $value)
|
||||
{
|
||||
$output[] = sprintf('%s: %s', self::getSafeValue($key), self::getSafeValue($value));
|
||||
}
|
||||
|
||||
return sprintf('[%s]', implode(', ', $output));
|
||||
}
|
||||
}
|
||||
|
||||
return match(strtolower(gettype($input)))
|
||||
{
|
||||
'boolean', 'integer', 'double', 'float', 'string', 'null' => $input,
|
||||
default => sprintf('[%s]', strtoupper(gettype($input))),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a backtrace from the current execution point.
|
||||
*
|
||||
* @param int $level The number of stack frames to skip before starting the trace.
|
||||
* @return StackTrace[] An array of StackTrace objects representing the backtrace.
|
||||
*/
|
||||
public static function getBackTrace(int $level=3): array
|
||||
{
|
||||
if(!function_exists('debug_backtrace'))
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
$debugBacktrace = debug_backtrace();
|
||||
$results = [];
|
||||
|
||||
foreach($debugBacktrace as $trace)
|
||||
{
|
||||
$stackTrace = StackTrace::fromTrace($trace);
|
||||
|
||||
if($stackTrace->isEmpty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$results[] = $stackTrace;
|
||||
}
|
||||
|
||||
return array_slice($results, $level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes a file name by replacing invalid characters with underscores.
|
||||
*
|
||||
* @param string $name The file name to sanitize.
|
||||
* @return string Returns the sanitized file name.
|
||||
*/
|
||||
public static function sanitizeFileName(string $name): string
|
||||
{
|
||||
return preg_replace('/[\/:*?"<>|.]/', '_', str_replace(' ', '-', $name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an Error instance into an ErrorException instance.
|
||||
*
|
||||
* @param int $errno The error number.
|
||||
* @param string $errstr The error message.
|
||||
* @param string $errfile The file in which the error occurred.
|
||||
* @param int $errline The line number in which the error occurred.
|
||||
* @return ExceptionDetails Returns the converted ErrorException instance.
|
||||
*/
|
||||
public static function detailsFromError(int|string $errno, string $errstr, string $errfile, int $errline): ExceptionDetails
|
||||
{
|
||||
if(is_string($errno))
|
||||
{
|
||||
$errno = 0;
|
||||
$errstr = sprintf('%s: %s', $errno, $errstr);
|
||||
}
|
||||
|
||||
return new ExceptionDetails('Runtime', $errstr, $errno, $errfile, $errline);
|
||||
}
|
||||
}
|
24
src/LogLib2/Enums/AnsiFormat.php
Normal file
24
src/LogLib2/Enums/AnsiFormat.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Enums;
|
||||
|
||||
enum AnsiFormat
|
||||
{
|
||||
case NONE;
|
||||
case BASIC;
|
||||
|
||||
/**
|
||||
* Parses the input string into an AnsiFormat enum.
|
||||
*
|
||||
* @param string $input The input string to parse.
|
||||
* @return AnsiFormat The parsed AnsiFormat enum.
|
||||
*/
|
||||
public static function parseFrom(string $input): AnsiFormat
|
||||
{
|
||||
return match(strtolower($input))
|
||||
{
|
||||
'basic', '1' => AnsiFormat::BASIC,
|
||||
default => AnsiFormat::NONE,
|
||||
};
|
||||
}
|
||||
}
|
34
src/LogLib2/Enums/CallType.php
Normal file
34
src/LogLib2/Enums/CallType.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Enums;
|
||||
|
||||
enum CallType : string
|
||||
{
|
||||
/**
|
||||
* Represents a method call.
|
||||
*
|
||||
* @var string METHOD_CALL
|
||||
*/
|
||||
case METHOD_CALL = '->';
|
||||
|
||||
/**
|
||||
* Represents a static method call.
|
||||
*
|
||||
* @var string STATIC_CALL
|
||||
*/
|
||||
case STATIC_CALL = '::';
|
||||
|
||||
/**
|
||||
* Represents a function call.
|
||||
*
|
||||
* @var string FUNCTION_CALL
|
||||
*/
|
||||
case FUNCTION_CALL = '()';
|
||||
|
||||
/**
|
||||
* Represents a lambda function call.
|
||||
*
|
||||
* @var string LAMBDA_CALL
|
||||
*/
|
||||
case LAMBDA_CALL = 'λ';
|
||||
}
|
152
src/LogLib2/Enums/ConsoleColor.php
Normal file
152
src/LogLib2/Enums/ConsoleColor.php
Normal file
|
@ -0,0 +1,152 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Enums;
|
||||
|
||||
use Random\RandomException;
|
||||
|
||||
enum ConsoleColor
|
||||
{
|
||||
case DEFAULT;
|
||||
case BLACK;
|
||||
case RED;
|
||||
case GREEN;
|
||||
case YELLOW;
|
||||
case BLUE;
|
||||
case MAGENTA;
|
||||
case CYAN;
|
||||
case WHITE;
|
||||
|
||||
/**
|
||||
* Formats the given input string with the color of the current ConsoleColor.
|
||||
*
|
||||
* @param string $input The input string to format.
|
||||
* @param bool $revertToDefault Whether to revert the color back to the default color after the input string.
|
||||
* @return string The formatted input string.
|
||||
*/
|
||||
public function format(string $input, bool $revertToDefault=true): string
|
||||
{
|
||||
$colorCode = match($this)
|
||||
{
|
||||
self::DEFAULT => 39,
|
||||
self::BLACK => 30,
|
||||
self::RED => 31,
|
||||
self::GREEN => 32,
|
||||
self::YELLOW => 33,
|
||||
self::BLUE => 34,
|
||||
self::MAGENTA => 35,
|
||||
self::CYAN => 36,
|
||||
self::WHITE => 37,
|
||||
};
|
||||
|
||||
return "\033[" . $colorCode . "m" . $input . ($revertToDefault ? "\033[39m" : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the given input string with the light color of the current ConsoleColor.
|
||||
*
|
||||
* @param string $input The input string to format.
|
||||
* @param bool $revertToDefault Whether to revert the color back to the default color after the input string.
|
||||
* @return string The formatted input string.
|
||||
*/
|
||||
public function formatLight(string $input, bool $revertToDefault=true): string
|
||||
{
|
||||
$colorCode = match($this)
|
||||
{
|
||||
self::DEFAULT => 39,
|
||||
self::BLACK => 90,
|
||||
self::RED => 91,
|
||||
self::GREEN => 92,
|
||||
self::YELLOW => 93,
|
||||
self::BLUE => 94,
|
||||
self::MAGENTA => 95,
|
||||
self::CYAN => 96,
|
||||
self::WHITE => 97,
|
||||
};
|
||||
|
||||
return "\033[" . $colorCode . "m" . $input . ($revertToDefault ? "\033[39m" : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the given input string with the bold color of the current ConsoleColor.
|
||||
*
|
||||
* @param string $input The input string to format.
|
||||
* @param bool $revertToDefault Whether to revert the color back to the default color after the input string.
|
||||
* @return string The formatted input string.
|
||||
*/
|
||||
public function formatBold(string $input, bool $revertToDefault=true): string
|
||||
{
|
||||
$colorCode = match($this)
|
||||
{
|
||||
self::DEFAULT => 39,
|
||||
self::BLACK => 30,
|
||||
self::RED => 31,
|
||||
self::GREEN => 32,
|
||||
self::YELLOW => 33,
|
||||
self::BLUE => 34,
|
||||
self::MAGENTA => 35,
|
||||
self::CYAN => 36,
|
||||
self::WHITE => 37,
|
||||
};
|
||||
|
||||
return "\033[1;" . $colorCode . "m" . $input . ($revertToDefault ? "\033[0m" : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the given input string with the background color of the current ConsoleColor.
|
||||
*
|
||||
* @param string $input The input string to format.
|
||||
* @param ConsoleColor $foreground The foreground color to use.
|
||||
* @param bool $revertToDefault Whether to revert the color back to the default color after the input string.
|
||||
* @return string The formatted input string.
|
||||
*/
|
||||
public function formatBackground(string $input, ConsoleColor $foreground, bool $revertToDefault=true): string
|
||||
{
|
||||
$colorCode = match($this)
|
||||
{
|
||||
self::DEFAULT => 49,
|
||||
self::BLACK => 40,
|
||||
self::RED => 41,
|
||||
self::GREEN => 42,
|
||||
self::YELLOW => 43,
|
||||
self::BLUE => 44,
|
||||
self::MAGENTA => 45,
|
||||
self::CYAN => 46,
|
||||
self::WHITE => 47,
|
||||
};
|
||||
|
||||
return "\033[" . $colorCode . "m" . $foreground->format($input, false) . ($revertToDefault ? "\033[49m" : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the given input string with the light background color of the current ConsoleColor.
|
||||
*
|
||||
* @return ConsoleColor The formatted input string.
|
||||
* @throws RandomException Thrown when the random_int function fails to generate a random integer.
|
||||
*/
|
||||
public static function getRandomColor(array $disallow=[]): ConsoleColor
|
||||
{
|
||||
$colors = [
|
||||
self::BLACK,
|
||||
self::RED,
|
||||
self::GREEN,
|
||||
self::YELLOW,
|
||||
self::BLUE,
|
||||
self::MAGENTA,
|
||||
self::CYAN,
|
||||
self::WHITE,
|
||||
];
|
||||
|
||||
// Convert disallowed colors to strings
|
||||
$disallow = array_map(fn($color) => $color->name, $disallow);
|
||||
|
||||
// Filter out disallowed colors
|
||||
$colors = array_filter($colors, fn($color) => !in_array($color->name, $disallow));
|
||||
|
||||
if (empty($colors))
|
||||
{
|
||||
throw new RandomException('No colors available to choose from.');
|
||||
}
|
||||
|
||||
return $colors[array_rand($colors)];
|
||||
}
|
||||
}
|
437
src/LogLib2/Enums/LogFormat.php
Normal file
437
src/LogLib2/Enums/LogFormat.php
Normal file
|
@ -0,0 +1,437 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Enums;
|
||||
|
||||
use LogLib2\Objects\Event;
|
||||
use LogLib2\Objects\ExceptionDetails;
|
||||
use LogLib2\Objects\StackTrace;
|
||||
use SimpleXMLElement;
|
||||
|
||||
enum LogFormat
|
||||
{
|
||||
case JSONL;
|
||||
case CSV;
|
||||
case TXT;
|
||||
case XML;
|
||||
case HTML;
|
||||
|
||||
/**
|
||||
* Formats the log entry.
|
||||
*
|
||||
* @param TimestampFormat $timestampType The timestamp type to use.
|
||||
* @param TraceFormat $traceType The trace type to use.
|
||||
* @param Event $event The event to format.
|
||||
* @return string The formatted log entry.
|
||||
*/
|
||||
public function format(TimestampFormat $timestampType, TraceFormat $traceType, Event $event): string
|
||||
{
|
||||
return match($this)
|
||||
{
|
||||
self::JSONL => self::formatJson($timestampType, $traceType, $event),
|
||||
self::CSV => self::formatCsv($timestampType, $traceType, $event),
|
||||
self::TXT => self::formatTxt($timestampType, $traceType, $event),
|
||||
self::XML => self::formatXml($timestampType, $traceType, $event),
|
||||
self::HTML => self::formatHtml($timestampType, $traceType, $event),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a log format from a string.
|
||||
*
|
||||
* @param string $input The input to parse.
|
||||
* @return LogFormat The parsed log format.
|
||||
*/
|
||||
public static function parseFrom(string $input): LogFormat
|
||||
{
|
||||
return match(strtolower($input))
|
||||
{
|
||||
'csv', '1' => self::CSV,
|
||||
'txt', '2' => self::TXT,
|
||||
'xml', '3' => self::XML,
|
||||
'html', '4' => self::HTML,
|
||||
default => self::JSONL
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the log entry as a JSON string.
|
||||
*
|
||||
* @param TimestampFormat $timestampFormat The timestamp format to use.
|
||||
* @param TraceFormat $traceFormat The trace format to use.
|
||||
* @param Event $event The event to format as a JSON string.
|
||||
* @return string The log entry as a JSON string.
|
||||
*/
|
||||
private static function formatJson(TimestampFormat $timestampFormat, TraceFormat $traceFormat, Event $event): string
|
||||
{
|
||||
return json_encode($event->toStandardArray($timestampFormat, $traceFormat), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the log entry as a CSV string.
|
||||
*
|
||||
* @param TimestampFormat $timestampFormat The timestamp format to use.
|
||||
* @param TraceFormat $traceFormat The trace format to use.
|
||||
* @param Event $event The event to format as a CSV string.
|
||||
* @return string The log entry as a CSV string.
|
||||
*/
|
||||
private static function formatCsv(TimestampFormat $timestampFormat, TraceFormat $traceFormat, Event $event): string
|
||||
{
|
||||
$output = self::sanitizeCsv($timestampFormat->format($event->getTimestamp())) . ',';
|
||||
$output .= self::sanitizeCsv($event->getLevel()->value) . ',';
|
||||
$output .= self::sanitizeCsv($event->getMessage()) . ',';
|
||||
|
||||
if($traceFormat === TraceFormat::NONE || $event->getFirstTrace() === null)
|
||||
{
|
||||
$output .= '-,';
|
||||
}
|
||||
else
|
||||
{
|
||||
$output .= self::sanitizeCsv($traceFormat->format($event->getFirstTrace())) . ',';
|
||||
}
|
||||
|
||||
if ($event->getException() === null)
|
||||
{
|
||||
$output .= '-,';
|
||||
}
|
||||
else
|
||||
{
|
||||
$output .= self::sanitizeCsv(json_encode($event->getException()->toArray(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)) . ',';
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes a CSV value.
|
||||
*
|
||||
* @param string $value The value to sanitize.
|
||||
* @return string The sanitized value.
|
||||
*/
|
||||
private static function sanitizeCsv(string $value): string
|
||||
{
|
||||
$escapedValue = str_replace('"', '""', $value);
|
||||
if (str_contains($escapedValue, ',') || str_contains($escapedValue, '\n') || str_contains($escapedValue, '"'))
|
||||
{
|
||||
$escapedValue = '"' . $escapedValue . '"';
|
||||
}
|
||||
|
||||
return $escapedValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the log entry as a plain text string.
|
||||
*
|
||||
* @param TimestampFormat $timestampType The timestamp type to use.
|
||||
* @param TraceFormat $traceType The trace type to use.
|
||||
* @param Event $event The event to format as a plain text string.
|
||||
* @return string The log entry as a plain text string.
|
||||
*/
|
||||
private static function formatTxt(TimestampFormat $timestampType, TraceFormat $traceType, Event $event): string
|
||||
{
|
||||
$output = '';
|
||||
if ($timestampType !== TimestampFormat::NONE)
|
||||
{
|
||||
$output .= $timestampType->format($event->getTimestamp()) . ' ';
|
||||
}
|
||||
|
||||
$output .= sprintf('[%s] ', $event->getLevel()->value);
|
||||
|
||||
if ($traceType !== TraceFormat::NONE && $event->getFirstTrace() !== null)
|
||||
{
|
||||
$output .= $traceType->format($event->getFirstTrace()) . ' ';
|
||||
}
|
||||
|
||||
$output .= $event->getMessage();
|
||||
if ($event->getException() !== null)
|
||||
{
|
||||
$output .= self::exceptionToString($event->getException());
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the log entry as an XML string.
|
||||
*
|
||||
* @param Event $event The event to format as an XML string.
|
||||
* @return string The log entry as an XML string.
|
||||
*/
|
||||
private static function formatXml(TimestampFormat $timestampType, TraceFormat $traceType, Event $event): string
|
||||
{
|
||||
$xml = new SimpleXMLElement('<event/>');
|
||||
$xml->addChild('application_name', $event->getApplicationName());
|
||||
$xml->addChild('timestamp', $timestampType->format($event->getTimestamp()));
|
||||
$xml->addChild('level', $event->getLevel()->value);
|
||||
$xml->addChild('message', $event->getLevel()->value);
|
||||
|
||||
if($traceType !== TraceFormat::NONE && $event->getFirstTrace() !== null)
|
||||
{
|
||||
$xml->addChild('trace', $traceType->format($event->getFirstTrace()));
|
||||
}
|
||||
|
||||
if(count($event->getTraces()) > 0)
|
||||
{
|
||||
$tracesElement = $xml->addChild('stack_trace');
|
||||
foreach($event->getTraces() as $trace)
|
||||
{
|
||||
$traceElement = $tracesElement->addChild('trace');
|
||||
self::traceToXml($trace, $traceElement);
|
||||
}
|
||||
}
|
||||
|
||||
if ($event->getException() !== null)
|
||||
{
|
||||
self::exceptionToXml($event->getException(), $xml->addChild('exception'));
|
||||
}
|
||||
|
||||
$dom = dom_import_simplexml($xml)->ownerDocument;
|
||||
$dom->formatOutput = true;
|
||||
return $dom->saveXML($dom->documentElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an exception to an XML element.
|
||||
*
|
||||
* @param ExceptionDetails $exception The exception to convert.
|
||||
* @param SimpleXMLElement $xml The XML element to append the exception to.
|
||||
*/
|
||||
private static function exceptionToXml(ExceptionDetails $exception, SimpleXMLElement $xml): void
|
||||
{
|
||||
$xml->addChild('name', htmlspecialchars($exception->getName(), ENT_XML1, 'UTF-8'));
|
||||
$xml->addChild('message', htmlspecialchars($exception->getMessage(), ENT_XML1, 'UTF-8'));
|
||||
|
||||
if ($exception->getCode() !== null)
|
||||
{
|
||||
$xml->addChild('code', (string)$exception->getCode());
|
||||
}
|
||||
|
||||
if ($exception->getFile() !== null)
|
||||
{
|
||||
$xml->addChild('file', htmlspecialchars($exception->getFile(), ENT_XML1, 'UTF-8'));
|
||||
}
|
||||
|
||||
if ($exception->getLine() !== null)
|
||||
{
|
||||
$xml->addChild('line', (string)$exception->getLine());
|
||||
}
|
||||
|
||||
if ($exception->getTrace() !== null)
|
||||
{
|
||||
$tracesElement = $xml->addChild('stack_trace');
|
||||
foreach ($exception->getTrace() as $trace)
|
||||
{
|
||||
$traceElement = $tracesElement->addChild('trace');
|
||||
self::traceToXml($trace, $traceElement);
|
||||
}
|
||||
}
|
||||
|
||||
if ($exception->getPrevious() !== null)
|
||||
{
|
||||
self::exceptionToXml($exception->getPrevious(), $xml->addChild('previous'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a stack trace to an XML element.
|
||||
*
|
||||
* @param StackTrace $trace The stack trace to convert.
|
||||
* @param SimpleXMLElement $xml The XML element to append the stack trace to.
|
||||
*/
|
||||
private static function traceToXml(StackTrace $trace, SimpleXMLElement $xml): void
|
||||
{
|
||||
if ($trace->getFile() !== null)
|
||||
{
|
||||
$xml->addChild('file', htmlspecialchars($trace->getFile(), ENT_XML1, 'UTF-8'));
|
||||
}
|
||||
|
||||
if ($trace->getLine() !== null)
|
||||
{
|
||||
$xml->addChild('line', (string)$trace->getLine());
|
||||
}
|
||||
|
||||
if ($trace->getFunction() !== null)
|
||||
{
|
||||
$xml->addChild('function', htmlspecialchars($trace->getFunction(), ENT_XML1, 'UTF-8'));
|
||||
}
|
||||
|
||||
if ($trace->getClass() !== null)
|
||||
{
|
||||
$xml->addChild('class', htmlspecialchars($trace->getClass(), ENT_XML1, 'UTF-8'));
|
||||
}
|
||||
|
||||
if ($trace->getCallType() !== null)
|
||||
{
|
||||
$xml->addChild('call_type', htmlspecialchars($trace->getCallType()->value, ENT_XML1, 'UTF-8'));
|
||||
}
|
||||
|
||||
if ($trace->getArgs() !== null)
|
||||
{
|
||||
$argsElement = $xml->addChild('arguments');
|
||||
foreach ($trace->getArgs() as $arg)
|
||||
{
|
||||
$argsElement->addChild('argument', htmlspecialchars(json_encode($arg, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), ENT_XML1, 'UTF-8'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the log entry as an HTML string.
|
||||
*
|
||||
* @param Event $event The event to format as an HTML string.
|
||||
* @return string The log entry as an HTML string.
|
||||
*/
|
||||
private static function formatHtml(TimestampFormat $timestampType, TraceFormat $traceType, Event $event): string
|
||||
{
|
||||
$html = '<div class="log-entry">';
|
||||
$html .= sprintf('<p><strong>Timestamp:</strong> %s</p>', $timestampType->format($event->getTimestamp()));
|
||||
$html .= sprintf('<p><strong>Level:</strong> %s</p>', $event->getLevel()->value);
|
||||
$html .= sprintf('<p><strong>Message:</strong> %s</p>', htmlspecialchars($event->getMessage(), ENT_QUOTES, 'UTF-8'));
|
||||
|
||||
if($traceType !== TraceFormat::NONE && $event->getFirstTrace() !== null)
|
||||
{
|
||||
$html .= sprintf('<p><strong>Backtrace:</strong> %s</p>', $traceType->format($event->getFirstTrace()));
|
||||
}
|
||||
|
||||
if ($event->getException() !== null)
|
||||
{
|
||||
$html .= '<p><strong>Exception Details:</strong></p>';
|
||||
$html .= self::exceptionToHtml($event->getException());
|
||||
}
|
||||
|
||||
$html .= '</div>';
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an exception to an HTML string.
|
||||
*
|
||||
* @param ExceptionDetails $exception The exception to convert.
|
||||
* @return string The exception as an HTML string.
|
||||
*/
|
||||
private static function exceptionToHtml(ExceptionDetails $exception): string
|
||||
{
|
||||
$html = '<div class="exception-details">';
|
||||
$html .= sprintf('<p><strong>%s:</strong> %s (Code: %s)</p>',
|
||||
htmlspecialchars($exception->getName(), ENT_QUOTES, 'UTF-8'),
|
||||
htmlspecialchars($exception->getMessage(), ENT_QUOTES, 'UTF-8'),
|
||||
$exception->getCode() !== null ? htmlspecialchars((string)$exception->getCode(), ENT_QUOTES, 'UTF-8') : 'N/A'
|
||||
);
|
||||
|
||||
if ($exception->getFile() !== null)
|
||||
{
|
||||
$html .= sprintf('<p><strong>File:</strong> %s</p>', htmlspecialchars($exception->getFile(), ENT_QUOTES, 'UTF-8'));
|
||||
if ($exception->getLine() !== null)
|
||||
{
|
||||
$html .= sprintf('<p><strong>Line:</strong> %d</p>', $exception->getLine());
|
||||
}
|
||||
}
|
||||
|
||||
if ($exception->getTrace() !== null)
|
||||
{
|
||||
$html .= '<p><strong>Stack Trace:</strong></p><ul>';
|
||||
foreach ($exception->getTrace() as $trace)
|
||||
{
|
||||
$html .= '<li>';
|
||||
$html .= self::traceToHtml($trace);
|
||||
$html .= '</li>';
|
||||
}
|
||||
$html .= '</ul>';
|
||||
}
|
||||
|
||||
if ($exception->getPrevious() !== null)
|
||||
{
|
||||
$html .= '<p><strong>Caused by:</strong></p>';
|
||||
$html .= self::exceptionToHtml($exception->getPrevious());
|
||||
}
|
||||
|
||||
$html .= '</div>';
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a stack trace to an HTML string.
|
||||
*
|
||||
* @param StackTrace $trace The stack trace to convert.
|
||||
* @return string The stack trace as an HTML string.
|
||||
*/
|
||||
private static function traceToHtml(StackTrace $trace): string
|
||||
{
|
||||
$output = '<div class="stack-trace">';
|
||||
|
||||
if ($trace->getFile() !== null)
|
||||
{
|
||||
$output .= sprintf('<p><strong>File:</strong> %s</p>', htmlspecialchars($trace->getFile(), ENT_QUOTES, 'UTF-8'));
|
||||
}
|
||||
|
||||
if ($trace->getLine() !== null)
|
||||
{
|
||||
$output .= sprintf('<p><strong>Line:</strong> %d</p>', $trace->getLine());
|
||||
}
|
||||
|
||||
if ($trace->getFunction() !== null)
|
||||
{
|
||||
$output .= sprintf('<p><strong>Function:</strong> %s</p>', htmlspecialchars($trace->getFunction(), ENT_QUOTES, 'UTF-8'));
|
||||
}
|
||||
|
||||
if ($trace->getClass() !== null)
|
||||
{
|
||||
$output .= sprintf('<p><strong>Class:</strong> %s</p>', htmlspecialchars($trace->getClass(), ENT_QUOTES, 'UTF-8'));
|
||||
}
|
||||
|
||||
if ($trace->getCallType() !== null)
|
||||
{
|
||||
$output .= sprintf('<p><strong>Call Type:</strong> %s</p>', htmlspecialchars($trace->getCallType()->value, ENT_QUOTES, 'UTF-8'));
|
||||
}
|
||||
|
||||
if ($trace->getArgs() !== null)
|
||||
{
|
||||
$output .= '<p><strong>Arguments:</strong></p><ul>';
|
||||
foreach ($trace->getArgs() as $arg)
|
||||
{
|
||||
$output .= sprintf('<li>%s</li>', htmlspecialchars(json_encode($arg, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), ENT_QUOTES, 'UTF-8'));
|
||||
}
|
||||
|
||||
$output .= '</ul>';
|
||||
}
|
||||
|
||||
$output .= '</div>';
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an exception to a string.
|
||||
*
|
||||
* @param ExceptionDetails $exception The exception to convert.
|
||||
* @return string The exception as a string.
|
||||
*/
|
||||
private static function exceptionToString(ExceptionDetails $exception): string
|
||||
{
|
||||
$output = sprintf("\n%s: %s (%s)", $exception->getName(), $exception->getMessage(), $exception->getCode() ?? 0);
|
||||
|
||||
if ($exception->getFile() !== null)
|
||||
{
|
||||
$output .= sprintf("\nFile: %s", $exception->getFile());
|
||||
|
||||
if ($exception->getLine() !== null)
|
||||
{
|
||||
$output .= sprintf(":%d", $exception->getLine());
|
||||
}
|
||||
}
|
||||
|
||||
if ($exception->getTrace() !== null)
|
||||
{
|
||||
$output .= "\n";
|
||||
foreach ($exception->getTrace() as $trace)
|
||||
{
|
||||
$output .= sprintf(" %s\n", TraceFormat::FULL->format($trace));
|
||||
}
|
||||
}
|
||||
|
||||
if ($exception->getPrevious() !== null)
|
||||
{
|
||||
$output .= self::exceptionToString($exception->getPrevious());
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
12
src/LogLib2/Enums/LogHandlers.php
Normal file
12
src/LogLib2/Enums/LogHandlers.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Enums;
|
||||
|
||||
enum LogHandlers : string
|
||||
{
|
||||
case CONSOLE = 'console';
|
||||
case FILE = 'file';
|
||||
case TCP = 'tcp';
|
||||
case UDP = 'udp';
|
||||
case HTTP = 'http';
|
||||
}
|
90
src/LogLib2/Enums/LogLevel.php
Normal file
90
src/LogLib2/Enums/LogLevel.php
Normal file
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Enums;
|
||||
|
||||
enum LogLevel : string
|
||||
{
|
||||
/**
|
||||
* Represents a debug level constant.
|
||||
*/
|
||||
case DEBUG = 'DBG';
|
||||
|
||||
/**
|
||||
* Represents a verbose level constant.
|
||||
*/
|
||||
case VERBOSE = 'VRB';
|
||||
|
||||
/**
|
||||
* Represents an information level constant.
|
||||
*/
|
||||
case INFO = 'INFO';
|
||||
|
||||
/**
|
||||
* Represents a warning level constant.
|
||||
*/
|
||||
case WARNING = 'WRN';
|
||||
|
||||
/**
|
||||
* Represents an error level constant.
|
||||
*/
|
||||
case ERROR = 'ERR';
|
||||
|
||||
/**
|
||||
* Represents a critical level constant.
|
||||
*/
|
||||
case CRITICAL = 'CRT';
|
||||
|
||||
/**
|
||||
* Retrieves the levels of severity corresponding to the current level.
|
||||
*
|
||||
* @return array An array of levels applicable to the current instance.
|
||||
*/
|
||||
public function getLevels(): array
|
||||
{
|
||||
return match ($this)
|
||||
{
|
||||
self::DEBUG => [self::DEBUG, self::VERBOSE, self::INFO, self::WARNING, self::ERROR, self::CRITICAL],
|
||||
self::VERBOSE => [self::VERBOSE, self::INFO, self::WARNING, self::ERROR, self::CRITICAL],
|
||||
self::INFO => [self::INFO, self::WARNING, self::ERROR, self::CRITICAL],
|
||||
self::WARNING => [self::WARNING, self::ERROR, self::CRITICAL],
|
||||
self::ERROR => [self::ERROR, self::CRITICAL],
|
||||
self::CRITICAL => [self::CRITICAL],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the provided log level is allowed based on the current instance's levels.
|
||||
*
|
||||
* @param LogLevel $level The log level to check against the allowed levels.
|
||||
* @return bool True if the log level is allowed, false otherwise.
|
||||
*/
|
||||
public function levelAllowed(LogLevel $level): bool
|
||||
{
|
||||
return in_array($level, $this->getLevels());
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given value and returns the corresponding log level.
|
||||
*
|
||||
* @param int|string $value The value to parse, which can be an integer or a string representation of the log level.
|
||||
* @return LogLevel The log level matching the provided value, or the default log level if no match is found.
|
||||
*/
|
||||
public static function parseFrom(int|string $value): LogLevel
|
||||
{
|
||||
if(is_string($value))
|
||||
{
|
||||
$value = strtolower($value);
|
||||
}
|
||||
|
||||
return match($value)
|
||||
{
|
||||
'debug', 'dbg', 'd', 0 => self::DEBUG,
|
||||
'verbose', 'verb', 'vrb', 'v', 1 => self::VERBOSE,
|
||||
'information', 'info', 'inf', 'i', 2 => self::INFO,
|
||||
'warning', 'warn', 'wrn', 'w', 3 => self::WARNING,
|
||||
'error', 'err', 'e', 4 => self::ERROR,
|
||||
'critical', 'crit', 'crt', 'c', 5 => self::CRITICAL,
|
||||
default => self::INFO
|
||||
};
|
||||
}
|
||||
}
|
63
src/LogLib2/Enums/TimestampFormat.php
Normal file
63
src/LogLib2/Enums/TimestampFormat.php
Normal file
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Enums;
|
||||
|
||||
use DateTime;
|
||||
|
||||
enum TimestampFormat
|
||||
{
|
||||
case NONE;
|
||||
case TIME_ONLY;
|
||||
case TIME_ONLY_MILLIS;
|
||||
case DATE_ONLY;
|
||||
case DATE_TIME;
|
||||
case DATE_TIME_MILLIS;
|
||||
case UNIX_TIMESTAMP;
|
||||
|
||||
/**
|
||||
* Retrieves the format string for the timestamp type.
|
||||
*
|
||||
* @param int|null $time The time to format, or null to use the current time.
|
||||
* @return string Returns the format string for the timestamp type.
|
||||
*/
|
||||
public function format(?int $time=null): string
|
||||
{
|
||||
$format = match($this)
|
||||
{
|
||||
self::NONE => '',
|
||||
self::TIME_ONLY => 'H:i:s',
|
||||
self::TIME_ONLY_MILLIS => 'H:i:s.u',
|
||||
self::DATE_ONLY => 'Y-m-d',
|
||||
self::DATE_TIME => 'Y-m-d H:i:s',
|
||||
self::DATE_TIME_MILLIS => 'Y-m-d H:i:s.u',
|
||||
self::UNIX_TIMESTAMP => 'U',
|
||||
};
|
||||
|
||||
if($time === null)
|
||||
{
|
||||
$time = time();
|
||||
}
|
||||
|
||||
return (new DateTime())->setTimestamp($time)->format($format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the input string into a TimestampFormat enum.
|
||||
*
|
||||
* @param string $input The input string to parse.
|
||||
* @return TimestampFormat The parsed TimestampFormat enum.
|
||||
*/
|
||||
public static function parseFrom(string $input): TimestampFormat
|
||||
{
|
||||
return match(strtolower($input))
|
||||
{
|
||||
'none', '0' => TimestampFormat::NONE,
|
||||
'time_only_millis', '2' => TimestampFormat::TIME_ONLY_MILLIS,
|
||||
'date_only', '3' => TimestampFormat::DATE_ONLY,
|
||||
'date_time', '4' => TimestampFormat::DATE_TIME,
|
||||
'date_time_millis', '5' => TimestampFormat::DATE_TIME_MILLIS,
|
||||
'unix_timestamp', '6' => TimestampFormat::UNIX_TIMESTAMP,
|
||||
default => TimestampFormat::TIME_ONLY,
|
||||
};
|
||||
}
|
||||
}
|
138
src/LogLib2/Enums/TraceFormat.php
Normal file
138
src/LogLib2/Enums/TraceFormat.php
Normal file
|
@ -0,0 +1,138 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Enums;
|
||||
|
||||
use LogLib2\Objects\StackTrace;
|
||||
|
||||
enum TraceFormat
|
||||
{
|
||||
case NONE;
|
||||
case BASIC;
|
||||
case FULL;
|
||||
|
||||
/**
|
||||
* Formats the stack trace based on the type of trace.
|
||||
*
|
||||
* @param StackTrace $stackTrace The stack trace to format.
|
||||
* @return string The formatted stack trace.
|
||||
*/
|
||||
public function format(StackTrace $stackTrace): string
|
||||
{
|
||||
if($this === TraceFormat::BASIC)
|
||||
{
|
||||
return self::formatBasic($stackTrace);
|
||||
}
|
||||
|
||||
if($this === TraceFormat::FULL)
|
||||
{
|
||||
return self::formatFull($stackTrace);
|
||||
}
|
||||
|
||||
return (string)null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the input string into a TraceFormat enum.
|
||||
*
|
||||
* @param string $input The input string to parse.
|
||||
* @return TraceFormat The parsed TraceFormat enum.
|
||||
*/
|
||||
public static function parseFrom(string $input): TraceFormat
|
||||
{
|
||||
return match(strtolower($input))
|
||||
{
|
||||
'none', '0' => TraceFormat::NONE,
|
||||
'basic', '1' => TraceFormat::BASIC,
|
||||
'full', '2' => TraceFormat::FULL,
|
||||
default => TraceFormat::BASIC,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the stack trace as a basic string.
|
||||
*
|
||||
* @param StackTrace $stackTrace The stack trace to format.
|
||||
* @return string The formatted stack trace.
|
||||
*/
|
||||
private static function formatBasic(StackTrace $stackTrace): string
|
||||
{
|
||||
if($stackTrace->getFunction() === null)
|
||||
{
|
||||
if($stackTrace->getClass() !== null)
|
||||
{
|
||||
return $stackTrace->getClass();
|
||||
}
|
||||
|
||||
if($stackTrace->getFile() !== null)
|
||||
{
|
||||
if($stackTrace->getLine() !== null)
|
||||
{
|
||||
return $stackTrace->getFile() . ':' . $stackTrace->getLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
return $stackTrace->getFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($stackTrace->getClass() !== null)
|
||||
{
|
||||
return $stackTrace->getClass() . ($stackTrace->getCallType()?->value ?? CallType::STATIC_CALL->value) . $stackTrace->getFunction();
|
||||
}
|
||||
|
||||
if($stackTrace->getFile() !== null)
|
||||
{
|
||||
if($stackTrace->getLine() !== null)
|
||||
{
|
||||
return $stackTrace->getFile() . ':' . $stackTrace->getLine() . ' ' . ($stackTrace->getCallType()?->value ?? CallType::STATIC_CALL->value) . $stackTrace->getFunction();
|
||||
}
|
||||
else
|
||||
{
|
||||
return $stackTrace->getFile() . ' ' . ($stackTrace->getCallType()?->value ?? CallType::STATIC_CALL->value) . $stackTrace->getFunction();
|
||||
}
|
||||
}
|
||||
|
||||
return $stackTrace->getFunction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the stack trace as a full string.
|
||||
*
|
||||
* @param StackTrace $stackTrace The stack trace to format.
|
||||
* @return string The formatted stack trace.
|
||||
*/
|
||||
private static function formatFull(StackTrace $stackTrace): string
|
||||
{
|
||||
$output = '';
|
||||
|
||||
if($stackTrace->getClass() !== null)
|
||||
{
|
||||
$output .= $stackTrace->getClass();
|
||||
}
|
||||
|
||||
if($stackTrace->getCallType() !== null)
|
||||
{
|
||||
$output .= $stackTrace->getCallType()->value;
|
||||
}
|
||||
|
||||
if($stackTrace->getFunction() !== null)
|
||||
{
|
||||
$output .= $stackTrace->getFunction();
|
||||
}
|
||||
|
||||
if($stackTrace->getFile() !== null)
|
||||
{
|
||||
$output .= ' (' . $stackTrace->getFile();
|
||||
|
||||
if($stackTrace->getLine() !== null)
|
||||
{
|
||||
$output .= ':' . $stackTrace->getLine();
|
||||
}
|
||||
|
||||
$output .= ')';
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
16
src/LogLib2/Exceptions/IOException.php
Normal file
16
src/LogLib2/Exceptions/IOException.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Exceptions;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class IOException extends \Exception
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function __construct(string $message = "", int $code=0, ?Throwable $previous=null)
|
||||
{
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
27
src/LogLib2/Interfaces/LogHandlerInterface.php
Normal file
27
src/LogLib2/Interfaces/LogHandlerInterface.php
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Interfaces;
|
||||
|
||||
use LogLib2\Objects\Application;
|
||||
use LogLib2\Objects\Event;
|
||||
|
||||
interface LogHandlerInterface
|
||||
{
|
||||
/**
|
||||
* Determines if the requested resource or functionality is available.
|
||||
*
|
||||
* @param Application $application The application's instance
|
||||
*
|
||||
* @return bool True if available, false otherwise
|
||||
*/
|
||||
public static function isAvailable(Application $application): bool;
|
||||
|
||||
/**
|
||||
* Handles the logging event for a log handler that implements this class
|
||||
*
|
||||
* @param Application $application The application's instance
|
||||
* @param Event $event The event to log
|
||||
* @return void
|
||||
*/
|
||||
public static function handleEvent(Application $application, Event $event): void;
|
||||
}
|
22
src/LogLib2/Interfaces/SerializableInterface.php
Normal file
22
src/LogLib2/Interfaces/SerializableInterface.php
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Interfaces;
|
||||
|
||||
interface SerializableInterface
|
||||
{
|
||||
/**
|
||||
* Returns an array representation of the object
|
||||
*
|
||||
* @return array The array representation of the object
|
||||
*/
|
||||
public function toArray(): array;
|
||||
|
||||
/**
|
||||
* Constructs the object from an array representation
|
||||
*
|
||||
* @param array|null $data The array representation of the object
|
||||
* @throws \InvalidArgumentException If one or more data entries are invalid
|
||||
* @return SerializableInterface The constructed class that implements SerializableInterface
|
||||
*/
|
||||
public static function fromArray(?array $data=null): SerializableInterface;
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2;
|
||||
|
||||
class LogLib2
|
||||
{
|
||||
|
||||
}
|
617
src/LogLib2/Logger.php
Normal file
617
src/LogLib2/Logger.php
Normal file
|
@ -0,0 +1,617 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2;
|
||||
|
||||
require __DIR__ . DIRECTORY_SEPARATOR . 'autoload_patch.php';
|
||||
|
||||
use LogLib2\Classes\LogHandlers\ConsoleHandler;
|
||||
use LogLib2\Classes\LogHandlers\DescriptorHandler;
|
||||
use LogLib2\Classes\LogHandlers\FileHandler;
|
||||
use LogLib2\Classes\LogHandlers\HttpHandler;
|
||||
use LogLib2\Classes\LogHandlers\TcpHandler;
|
||||
use LogLib2\Classes\LogHandlers\UdpHandler;
|
||||
use LogLib2\Classes\Utilities;
|
||||
use LogLib2\Enums\AnsiFormat;
|
||||
use LogLib2\Enums\LogFormat;
|
||||
use LogLib2\Enums\LogLevel;
|
||||
use LogLib2\Enums\TimestampFormat;
|
||||
use LogLib2\Enums\TraceFormat;
|
||||
use LogLib2\Objects\Application;
|
||||
use LogLib2\Objects\Configurations\ConsoleConfiguration;
|
||||
use LogLib2\Objects\Configurations\DescriptorConfiguration;
|
||||
use LogLib2\Objects\Configurations\FileConfiguration;
|
||||
use LogLib2\Objects\Configurations\HttpConfiguration;
|
||||
use LogLib2\Objects\Configurations\TcpConfiguration;
|
||||
use LogLib2\Objects\Configurations\UdpConfiguration;
|
||||
use LogLib2\Objects\Event;
|
||||
use LogLib2\Objects\ExceptionDetails;
|
||||
use Throwable;
|
||||
|
||||
class Logger
|
||||
{
|
||||
private static ?ConsoleConfiguration $defaultConsoleConfiguration=null;
|
||||
private static ?DescriptorConfiguration $defaultDescriptorConfiguration=null;
|
||||
private static ?FileConfiguration $defaultFileConfiguration=null;
|
||||
private static ?HttpConfiguration $defaultHttpConfiguration=null;
|
||||
private static ?TcpConfiguration $defaultTcpConfiguration=null;
|
||||
private static ?UdpConfiguration $defaultUdpConfiguration=null;
|
||||
private static bool $handlersRegistered=false;
|
||||
private static ?Logger $runtimeLogger=null;
|
||||
private static int $backtraceLevel=3;
|
||||
|
||||
private Application $application;
|
||||
|
||||
/**
|
||||
* Constructs a new instance with the provided application name.
|
||||
*
|
||||
* @param string $application The application name
|
||||
*/
|
||||
public function __construct(string $application)
|
||||
{
|
||||
$this->application = new Application($application);
|
||||
$this->application->setConsoleConfiguration(self::getDefaultConsoleConfiguration());
|
||||
$this->application->setDescriptorConfiguration(self::getDefaultDescriptorConfiguration());
|
||||
$this->application->setFileConfiguration(self::getDefaultFileConfiguration());
|
||||
$this->application->setHttpConfiguration(self::getDefaultHttpConfiguration());
|
||||
$this->application->setTcpConfiguration(self::getDefaultTcpConfiguration());
|
||||
$this->application->setUdpConfiguration(self::getDefaultUdpConfiguration());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the Application instance used by the Logger.
|
||||
*
|
||||
* @return Application The Application instance used by the Logger.
|
||||
*/
|
||||
public function getApplication(): Application
|
||||
{
|
||||
return $this->application;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the Application instance used by the Logger.
|
||||
*
|
||||
* @return Application The Application instance used by the Logger.
|
||||
*/
|
||||
public function debug(string $message): void
|
||||
{
|
||||
$this->handleEvent($this->createEvent(LogLevel::DEBUG, $message));
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a verbose message with the provided message.
|
||||
*
|
||||
* @param string $message The message to log.
|
||||
*/
|
||||
public function verbose(string $message): void
|
||||
{
|
||||
$this->handleEvent($this->createEvent(LogLevel::VERBOSE, $message));
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs an informational message with the provided message.
|
||||
*
|
||||
* @param string $message The message to log.
|
||||
*/
|
||||
public function info(string $message): void
|
||||
{
|
||||
$this->handleEvent($this->createEvent(LogLevel::INFO, $message));
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a warning message with the provided message.
|
||||
*
|
||||
* @param string $message The message to log.
|
||||
*/
|
||||
public function warning(string $message, null|ExceptionDetails|Throwable $e=null): void
|
||||
{
|
||||
$this->handleEvent($this->createEvent(LogLevel::WARNING, $message, $e));
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs an error message with the provided message.
|
||||
*
|
||||
* @param string $message The message to log.
|
||||
*/
|
||||
public function error(string $message, null|ExceptionDetails|Throwable $e=null): void
|
||||
{
|
||||
$this->handleEvent($this->createEvent(LogLevel::ERROR, $message, $e));
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a critical message with the provided message.
|
||||
*
|
||||
* @param string $message The message to log.
|
||||
*/
|
||||
public function critical(string $message, null|ExceptionDetails|Throwable $e=null): void
|
||||
{
|
||||
$this->handleEvent($this->createEvent(LogLevel::CRITICAL, $message, $e));
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs an alert message with the provided message.
|
||||
*
|
||||
* @param string $message The message to log.
|
||||
*/
|
||||
private function createEvent(LogLevel $level, string $message, null|ExceptionDetails|Throwable $e=null): Event
|
||||
{
|
||||
return new Event($this->application->getName(), $level, $message, Utilities::getBackTrace(Logger::getBacktraceLevel()), time(), $e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the provided event by passing it to the appropriate log handlers.
|
||||
*
|
||||
* @param Event $event The event to handle.
|
||||
*/
|
||||
private function handleEvent(Event $event): void
|
||||
{
|
||||
// Return early if the given LogLevel not allowed to be processed with the application's given log level.
|
||||
if(!Utilities::getEnvironmentLogLevel()->levelAllowed($event->getLevel()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle the event with the appropriate log handlers.
|
||||
if($this->application->getConsoleConfiguration()->isEnabled() && ConsoleHandler::isAvailable($this->application))
|
||||
{
|
||||
ConsoleHandler::handleEvent($this->application, $event);
|
||||
}
|
||||
|
||||
if($this->application->getDescriptorConfiguration()->isEnabled() && DescriptorHandler::isAvailable($this->application))
|
||||
{
|
||||
DescriptorHandler::handleEvent($this->application, $event);
|
||||
}
|
||||
|
||||
if($this->application->getFileConfiguration()->isEnabled() && FileHandler::isAvailable($this->application))
|
||||
{
|
||||
FileHandler::handleEvent($this->application, $event);
|
||||
}
|
||||
|
||||
if($this->application->getHttpConfiguration()->isEnabled() && HttpHandler::isAvailable($this->application))
|
||||
{
|
||||
HttpHandler::handleEvent($this->application, $event);
|
||||
}
|
||||
|
||||
if($this->application->getTcpConfiguration()->isEnabled() && TcpHandler::isAvailable($this->application))
|
||||
{
|
||||
TcpHandler::handleEvent($this->application, $event);
|
||||
}
|
||||
|
||||
if($this->application->getUdpConfiguration()->isEnabled() && UdpHandler::isAvailable($this->application))
|
||||
{
|
||||
UdpHandler::handleEvent($this->application, $event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the availability of the log handlers.
|
||||
*
|
||||
* @return array The availability of the log handlers.
|
||||
*/
|
||||
public function getAvailability(): array
|
||||
{
|
||||
return [
|
||||
ConsoleHandler::class => ConsoleHandler::isAvailable($this->application),
|
||||
DescriptorConfiguration::class => DescriptorHandler::isAvailable($this->application),
|
||||
FileHandler::class => FileHandler::isAvailable($this->application),
|
||||
HttpHandler::class => HttpHandler::isAvailable($this->application),
|
||||
TcpHandler::class => TcpHandler::isAvailable($this->application),
|
||||
UdpHandler::class => UdpHandler::isAvailable($this->application)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the default ConsoleConfiguration instance.
|
||||
*
|
||||
* @return ConsoleConfiguration The default ConsoleConfiguration instance.
|
||||
*/
|
||||
public static function getDefaultConsoleConfiguration(): ConsoleConfiguration
|
||||
{
|
||||
if(self::$defaultConsoleConfiguration === null)
|
||||
{
|
||||
self::$defaultConsoleConfiguration = new ConsoleConfiguration();
|
||||
|
||||
// Apply environment variables to the default ConsoleConfiguration instance.
|
||||
if(getenv('LOGLIB_CONSOLE_ENABLED') !== false)
|
||||
{
|
||||
self::$defaultConsoleConfiguration->setEnabled(filter_var(getenv('LOG_CONSOLE_ENABLED'), FILTER_VALIDATE_BOOLEAN));
|
||||
}
|
||||
if(getenv('LOGLIB_CONSOLE_DISPLAY_NAME') !== false)
|
||||
{
|
||||
self::$defaultConsoleConfiguration->setDisplayName(filter_var(getenv('LOG_CONSOLE_DISPLAY_NAME'), FILTER_VALIDATE_BOOLEAN));
|
||||
}
|
||||
if(getenv('LOGLIB_CONSOLE_DISPLAY_LEVEL') !== false)
|
||||
{
|
||||
self::$defaultConsoleConfiguration->setDisplayLevel(filter_var(getenv('LOG_CONSOLE_DISPLAY_LEVEL'), FILTER_VALIDATE_BOOLEAN));
|
||||
}
|
||||
if(getenv('LOGLIB_CONSOLE_ANSI_FORMAT') !== false)
|
||||
{
|
||||
self::$defaultConsoleConfiguration->setAnsiFormat(AnsiFormat::parseFrom(getenv('LOGLIB_CONSOLE_ANSI_FORMAT')));
|
||||
}
|
||||
if(getenv('LOGLIB_CONSOLE_TRACE_FORMAT') !== false)
|
||||
{
|
||||
self::$defaultConsoleConfiguration->setTraceFormat(TraceFormat::parseFrom(getenv('LOGLIB_CONSOLE_TRACE_FORMAT')));
|
||||
}
|
||||
if(getenv('LOGLIB_CONSOLE_TIMESTAMP_FORMAT') !== false)
|
||||
{
|
||||
self::$defaultConsoleConfiguration->setTimestampFormat(TimestampFormat::parseFrom(getenv('LOGLIB_CONSOLE_TIMESTAMP_FORMAT')));
|
||||
}
|
||||
}
|
||||
|
||||
return self::$defaultConsoleConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the default DescriptorConfiguration instance.
|
||||
*
|
||||
* @return DescriptorConfiguration The default DescriptorConfiguration instance.
|
||||
*/
|
||||
public static function getDefaultDescriptorConfiguration(): DescriptorConfiguration
|
||||
{
|
||||
if(self::$defaultDescriptorConfiguration === null)
|
||||
{
|
||||
self::$defaultDescriptorConfiguration = new DescriptorConfiguration();
|
||||
|
||||
// Apply environment variables to the default DescriptorConfiguration instance.
|
||||
if(getenv('LOGLIB_DESCRIPTOR_ENABLED') !== false)
|
||||
{
|
||||
self::$defaultDescriptorConfiguration->setEnabled(filter_var(getenv('LOGLIB_DESCRIPTOR_ENABLED'), FILTER_VALIDATE_BOOLEAN));
|
||||
}
|
||||
|
||||
if(getenv('LOGLIB_DESCRIPTOR_PATH') !== false)
|
||||
{
|
||||
self::$defaultDescriptorConfiguration->setDescriptor(getenv('LOGLIB_DESCRIPTOR_PATH'));
|
||||
}
|
||||
|
||||
if(getenv('LOGLIB_DESCRIPTOR_APPEND_NEWLINE') !== false)
|
||||
{
|
||||
self::$defaultDescriptorConfiguration->setAppendNewline(filter_var(getenv('LOGLIB_DESCRIPTOR_APPEND_NEWLINE'), FILTER_VALIDATE_BOOLEAN));
|
||||
}
|
||||
|
||||
if(getenv('LOGLIB_DESCRIPTOR_LOG_FORMAT') !== false)
|
||||
{
|
||||
self::$defaultDescriptorConfiguration->setLogFormat(LogFormat::parseFrom(getenv('LOGLIB_DESCRIPTOR_LOG_FORMAT')));
|
||||
}
|
||||
|
||||
if(getenv('LOGLIB_DESCRIPTOR_TIMESTAMP_FORMAT') !== false)
|
||||
{
|
||||
self::$defaultDescriptorConfiguration->setTimestampFormat(TimestampFormat::parseFrom(getenv('LOGLIB_DESCRIPTOR_TIMESTAMP_FORMAT')));
|
||||
}
|
||||
|
||||
if(getenv('LOGLIB_DESCRIPTOR_TRACE_FORMAT') !== false)
|
||||
{
|
||||
self::$defaultDescriptorConfiguration->setTraceFormat(TraceFormat::parseFrom(getenv('LOGLIB_DESCRIPTOR_TRACE_FORMAT')));
|
||||
}
|
||||
}
|
||||
|
||||
return self::$defaultDescriptorConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the default FileConfiguration instance.
|
||||
*
|
||||
* @return FileConfiguration The default FileConfiguration instance.
|
||||
*/
|
||||
public static function getDefaultFileConfiguration(): FileConfiguration
|
||||
{
|
||||
if(self::$defaultFileConfiguration === null)
|
||||
{
|
||||
self::$defaultFileConfiguration = new FileConfiguration();
|
||||
|
||||
// Apply environment variables to the default FileConfiguration instance.
|
||||
if(getenv('LOGLIB_FILE_ENABLED') !== false)
|
||||
{
|
||||
self::$defaultFileConfiguration->setEnabled(filter_var(getenv('LOGLIB_FILE_ENABLED'), FILTER_VALIDATE_BOOLEAN));
|
||||
}
|
||||
|
||||
if(getenv('LOGLIB_FILE_DEFAULT_PERMISSIONS') !== false)
|
||||
{
|
||||
$permissions = octdec(filter_var(getenv('LOGLIB_FILE_DEFAULT_PERMISSIONS'), FILTER_VALIDATE_INT));
|
||||
if($permissions !== false)
|
||||
{
|
||||
self::$defaultFileConfiguration->setDefaultPermissions($permissions);
|
||||
}
|
||||
}
|
||||
|
||||
if(getenv('LOGLIB_FILE_PATH') !== false)
|
||||
{
|
||||
// Parse magic constants in the file path.
|
||||
$path = getenv('LOGLIB_FILE_PATH');
|
||||
$path = str_ireplace('%CWD%', getcwd(), $path);
|
||||
$path = str_ireplace('%HOME%', getenv('HOME') ?? sys_get_temp_dir(), $path);
|
||||
$path = str_ireplace('%TMP%', sys_get_temp_dir(), $path);
|
||||
$path = str_ireplace('%TEMP%', sys_get_temp_dir(), $path);
|
||||
|
||||
if(!is_dir($path))
|
||||
{
|
||||
@mkdir($path, self::$defaultFileConfiguration->getDefaultPermissions(), true);
|
||||
}
|
||||
|
||||
self::$defaultFileConfiguration->setLogPath($path);
|
||||
}
|
||||
|
||||
if(getenv('LOGLIB_FILE_APPEND_NEWLINE') !== false)
|
||||
{
|
||||
self::$defaultFileConfiguration->setAppendNewline(filter_var(getenv('LOGLIB_FILE_APPEND_NEWLINE'), FILTER_VALIDATE_BOOLEAN));
|
||||
}
|
||||
|
||||
if(getenv('LOGLIB_FILE_LOG_FORMAT') !== false)
|
||||
{
|
||||
self::$defaultFileConfiguration->setLogFormat(LogFormat::parseFrom(getenv('LOGLIB_FILE_LOG_FORMAT')));
|
||||
}
|
||||
|
||||
if(getenv('LOGLIB_FILE_TIMESTAMP_FORMAT') !== false)
|
||||
{
|
||||
self::$defaultFileConfiguration->setTimestampFormat(TimestampFormat::parseFrom(getenv('LOGLIB_FILE_TIMESTAMP_FORMAT')));
|
||||
}
|
||||
|
||||
if(getenv('LOGLIB_FILE_TRACE_FORMAT') !== false)
|
||||
{
|
||||
self::$defaultFileConfiguration->setTraceFormat(TraceFormat::parseFrom(getenv('LOGLIB_FILE_TRACE_FORMAT')));
|
||||
}
|
||||
}
|
||||
|
||||
return self::$defaultFileConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the default HttpConfiguration instance.
|
||||
*
|
||||
* @return HttpConfiguration The default HttpConfiguration instance.
|
||||
*/
|
||||
public static function getDefaultHttpConfiguration(): HttpConfiguration
|
||||
{
|
||||
if(self::$defaultHttpConfiguration === null)
|
||||
{
|
||||
self::$defaultHttpConfiguration = new HttpConfiguration();
|
||||
|
||||
// Apply environment variables to the default HttpConfiguration instance.
|
||||
if(getenv('LOGLIB_HTTP_ENABLED') !== false)
|
||||
{
|
||||
self::$defaultHttpConfiguration->setEnabled(filter_var(getenv('LOGLIB_HTTP_ENABLED'), FILTER_VALIDATE_BOOLEAN));
|
||||
}
|
||||
|
||||
if(getenv('LOGLIB_HTTP_ENDPOINT') !== false)
|
||||
{
|
||||
self::$defaultHttpConfiguration->setEndpoint(getenv('LOGLIB_HTTP_ENDPOINT'));
|
||||
}
|
||||
|
||||
if(getenv('LOGLIB_HTTP_LOG_FORMAT') !== false)
|
||||
{
|
||||
self::$defaultHttpConfiguration->setLogFormat(LogFormat::parseFrom(getenv('LOGLIB_HTTP_LOG_FORMAT')));
|
||||
}
|
||||
|
||||
if(getenv('LOGLIB_HTTP_TIMESTAMP_FORMAT') !== false)
|
||||
{
|
||||
self::$defaultHttpConfiguration->setTimestampFormat(TimestampFormat::parseFrom(getenv('LOGLIB_HTTP_TIMESTAMP_FORMAT')));
|
||||
}
|
||||
|
||||
if(getenv('LOGLIB_HTTP_TRACE_FORMAT') !== false)
|
||||
{
|
||||
self::$defaultHttpConfiguration->setTraceFormat(TraceFormat::parseFrom(getenv('LOGLIB_HTTP_TRACE_FORMAT')));
|
||||
}
|
||||
}
|
||||
|
||||
return self::$defaultHttpConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the default TcpConfiguration instance.
|
||||
*
|
||||
* @return TcpConfiguration The default TcpConfiguration instance.
|
||||
*/
|
||||
public static function getDefaultTcpConfiguration(): TcpConfiguration
|
||||
{
|
||||
if(self::$defaultTcpConfiguration === null)
|
||||
{
|
||||
self::$defaultTcpConfiguration = new TcpConfiguration();
|
||||
|
||||
// Apply environment variables to the default TcpConfiguration instance.
|
||||
if(getenv('LOGLIB_TCP_ENABLED') !== false)
|
||||
{
|
||||
self::$defaultTcpConfiguration->setEnabled(filter_var(getenv('LOGLIB_TCP_ENABLED'), FILTER_VALIDATE_BOOLEAN));
|
||||
}
|
||||
|
||||
if(getenv('LOGLIB_TCP_HOST') !== false)
|
||||
{
|
||||
self::$defaultTcpConfiguration->setHost(getenv('LOGLIB_TCP_HOST'));
|
||||
}
|
||||
|
||||
if(getenv('LOGLIB_TCP_PORT') !== false)
|
||||
{
|
||||
self::$defaultTcpConfiguration->setPort((int)getenv('LOGLIB_TCP_PORT'));
|
||||
}
|
||||
|
||||
if(getenv('LOGLIB_TCP_APPEND_NEWLINE') !== false)
|
||||
{
|
||||
self::$defaultTcpConfiguration->setAppendNewline(filter_var(getenv('LOGLIB_TCP_APPEND_NEWLINE'), FILTER_VALIDATE_BOOLEAN));
|
||||
}
|
||||
|
||||
if(getenv('LOGLIB_TCP_LOG_FORMAT') !== false)
|
||||
{
|
||||
self::$defaultTcpConfiguration->setLogFormat(LogFormat::parseFrom(getenv('LOGLIB_TCP_LOG_FORMAT')));
|
||||
}
|
||||
|
||||
if(getenv('LOGLIB_TCP_TIMESTAMP_FORMAT') !== false)
|
||||
{
|
||||
self::$defaultTcpConfiguration->setTimestampFormat(TimestampFormat::parseFrom(getenv('LOGLIB_TCP_TIMESTAMP_FORMAT')));
|
||||
}
|
||||
}
|
||||
|
||||
return self::$defaultTcpConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the default UdpConfiguration instance.
|
||||
*
|
||||
* @return UdpConfiguration The default UdpConfiguration instance.
|
||||
*/
|
||||
public static function getDefaultUdpConfiguration(): UdpConfiguration
|
||||
{
|
||||
if(self::$defaultUdpConfiguration === null)
|
||||
{
|
||||
self::$defaultUdpConfiguration = new UdpConfiguration();
|
||||
|
||||
// Apply environment variables to the default UdpConfiguration instance.
|
||||
if(getenv('LOGLIB_UDP_ENABLED') !== false)
|
||||
{
|
||||
self::$defaultUdpConfiguration->setEnabled(filter_var(getenv('LOGLIB_UDP_ENABLED'), FILTER_VALIDATE_BOOLEAN));
|
||||
}
|
||||
|
||||
if(getenv('LOGLIB_UDP_HOST') !== false)
|
||||
{
|
||||
self::$defaultUdpConfiguration->setHost(getenv('LOGLIB_UDP_HOST'));
|
||||
}
|
||||
|
||||
if(getenv('LOGLIB_UDP_PORT') !== false)
|
||||
{
|
||||
self::$defaultUdpConfiguration->setPort((int)getenv('LOGLIB_UDP_PORT'));
|
||||
}
|
||||
|
||||
if(getenv('LOGLIB_UDP_APPEND_NEWLINE') !== false)
|
||||
{
|
||||
self::$defaultUdpConfiguration->setAppendNewline(filter_var(getenv('LOGLIB_UDP_APPEND_NEWLINE'), FILTER_VALIDATE_BOOLEAN));
|
||||
}
|
||||
|
||||
if(getenv('LOGLIB_UDP_LOG_FORMAT') !== false)
|
||||
{
|
||||
self::$defaultUdpConfiguration->setLogFormat(LogFormat::parseFrom(getenv('LOGLIB_UDP_LOG_FORMAT')));
|
||||
}
|
||||
|
||||
if(getenv('LOGLIB_UDP_TIMESTAMP_FORMAT') !== false)
|
||||
{
|
||||
self::$defaultUdpConfiguration->setTimestampFormat(TimestampFormat::parseFrom(getenv('LOGLIB_UDP_TIMESTAMP_FORMAT')));
|
||||
}
|
||||
|
||||
if(getenv('LOGLIB_UDP_TRACE_FORMAT') !== false)
|
||||
{
|
||||
self::$defaultUdpConfiguration->setTraceFormat(TraceFormat::parseFrom(getenv('LOGLIB_UDP_TRACE_FORMAT')));
|
||||
}
|
||||
}
|
||||
|
||||
return self::$defaultUdpConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the backtrace level.
|
||||
*
|
||||
* @return int The backtrace level.
|
||||
*/
|
||||
public static function getBacktraceLevel(): int
|
||||
{
|
||||
return self::$backtraceLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the backtrace level.
|
||||
*
|
||||
* @param int $backtraceLevel The backtrace level.
|
||||
*/
|
||||
public static function setBacktraceLevel(int $backtraceLevel): void
|
||||
{
|
||||
self::$backtraceLevel = $backtraceLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the runtime logger instance.
|
||||
*
|
||||
* @return Logger The runtime logger instance.
|
||||
*/
|
||||
public static function getRuntimeLogger(): Logger
|
||||
{
|
||||
if(self::$runtimeLogger === null)
|
||||
{
|
||||
self::$runtimeLogger = new Logger('Runtime');
|
||||
}
|
||||
|
||||
return self::$runtimeLogger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the log handlers.
|
||||
*/
|
||||
public static function registerHandlers(): void
|
||||
{
|
||||
if(self::$handlersRegistered)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$logger = self::getRuntimeLogger();
|
||||
|
||||
// Register to catch all PHP errors & warnings.
|
||||
set_error_handler(function($errno, $errstr, $errfile, $errline) use ($logger)
|
||||
{
|
||||
switch($errno)
|
||||
{
|
||||
case E_ERROR:
|
||||
case E_CORE_ERROR:
|
||||
case E_COMPILE_ERROR:
|
||||
case E_USER_ERROR:
|
||||
case E_RECOVERABLE_ERROR:
|
||||
case E_CORE_WARNING:
|
||||
case E_COMPILE_WARNING:
|
||||
case E_PARSE:
|
||||
$logger->critical($errstr, Utilities::detailsFromError($errno, $errstr, $errfile, $errline));
|
||||
break;
|
||||
|
||||
case E_WARNING:
|
||||
case E_USER_WARNING:
|
||||
case E_DEPRECATED:
|
||||
case E_USER_DEPRECATED:
|
||||
case E_NOTICE:
|
||||
case E_USER_NOTICE:
|
||||
case E_STRICT:
|
||||
$logger->warning($errstr, Utilities::detailsFromError($errno, $errstr, $errfile, $errline));
|
||||
break;
|
||||
|
||||
default:
|
||||
$logger->error($errstr, Utilities::detailsFromError($errno, $errstr, $errfile, $errline));
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// Register to catch all uncaught exceptions.
|
||||
set_exception_handler(function(Throwable $e) use ($logger)
|
||||
{
|
||||
$logger->error($e->getMessage(), $e);
|
||||
});
|
||||
|
||||
// Register to catch fatal errors.
|
||||
register_shutdown_function(function() use ($logger)
|
||||
{
|
||||
$error = error_get_last();
|
||||
|
||||
if($error !== null)
|
||||
{
|
||||
$logger->critical($error['message'], Utilities::detailsFromError($error['type'], $error['message'], $error['file'], $error['line']));
|
||||
}
|
||||
});
|
||||
|
||||
self::$handlersRegistered = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters the log handlers.
|
||||
*/
|
||||
public static function unregisterHandlers(): void
|
||||
{
|
||||
if(!self::$handlersRegistered)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
self::$handlersRegistered = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the registration status of the log handlers.
|
||||
*
|
||||
* @return bool Returns true if the log handlers are registered, false otherwise.
|
||||
*/
|
||||
public static function isHandlersRegistered(): bool
|
||||
{
|
||||
return self::$handlersRegistered;
|
||||
}
|
||||
}
|
189
src/LogLib2/Objects/Application.php
Normal file
189
src/LogLib2/Objects/Application.php
Normal file
|
@ -0,0 +1,189 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Objects;
|
||||
|
||||
use LogLib2\Objects\Configurations\ConsoleConfiguration;
|
||||
use LogLib2\Objects\Configurations\DescriptorConfiguration;
|
||||
use LogLib2\Objects\Configurations\FileConfiguration;
|
||||
use LogLib2\Objects\Configurations\HttpConfiguration;
|
||||
use LogLib2\Objects\Configurations\TcpConfiguration;
|
||||
use LogLib2\Objects\Configurations\UdpConfiguration;
|
||||
|
||||
class Application
|
||||
{
|
||||
private string $name;
|
||||
private ConsoleConfiguration $consoleConfiguration;
|
||||
private DescriptorConfiguration $descriptorConfiguration;
|
||||
private FileConfiguration $fileConfiguration;
|
||||
private HttpConfiguration $httpConfiguration;
|
||||
private TcpConfiguration $tcpConfiguration;
|
||||
private UdpConfiguration $udpConfiguration;
|
||||
|
||||
/**
|
||||
* Constructs a new instance with the provided application name and log level.
|
||||
*
|
||||
* @param string $name The application name.
|
||||
*/
|
||||
public function __construct(string $name)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->consoleConfiguration = new ConsoleConfiguration();
|
||||
$this->descriptorConfiguration = new DescriptorConfiguration();
|
||||
$this->fileConfiguration = new FileConfiguration();
|
||||
$this->httpConfiguration = new HttpConfiguration();
|
||||
$this->tcpConfiguration = new TcpConfiguration();
|
||||
$this->udpConfiguration = new UdpConfiguration();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the name of the application.
|
||||
*
|
||||
* @return string The name of the application.
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the ConsoleConfiguration instance for the application.
|
||||
*
|
||||
* @return ConsoleConfiguration The ConsoleConfiguration instance for the application.
|
||||
*/
|
||||
public function getConsoleConfiguration(): ConsoleConfiguration
|
||||
{
|
||||
return $this->consoleConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ConsoleConfiguration instance for the application.
|
||||
*
|
||||
* @param ConsoleConfiguration $configuration The ConsoleConfiguration instance for the application.
|
||||
* @return Application Returns the current instance for method chaining.
|
||||
*/
|
||||
public function setConsoleConfiguration(ConsoleConfiguration $configuration): Application
|
||||
{
|
||||
$this->consoleConfiguration = $configuration;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the DescriptorConfiguration instance for the application.
|
||||
*
|
||||
* @return DescriptorConfiguration The DescriptorConfiguration instance for the application.
|
||||
*/
|
||||
public function getDescriptorConfiguration(): DescriptorConfiguration
|
||||
{
|
||||
return $this->descriptorConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the DescriptorConfiguration instance for the application.
|
||||
*
|
||||
* @param DescriptorConfiguration $configuration The DescriptorConfiguration instance for the application.
|
||||
* @return Application Returns the current instance for method chaining.
|
||||
*/
|
||||
public function setDescriptorConfiguration(DescriptorConfiguration $configuration): Application
|
||||
{
|
||||
$this->descriptorConfiguration = $configuration;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the FileConfiguration instance for the application.
|
||||
*
|
||||
* @return FileConfiguration The FileConfiguration instance for the application.
|
||||
*/
|
||||
public function getFileConfiguration(): FileConfiguration
|
||||
{
|
||||
return $this->fileConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the FileConfiguration instance for the application.
|
||||
*
|
||||
* @param FileConfiguration $configuration The FileConfiguration instance for the application.
|
||||
* @return Application Returns the current instance for method chaining.
|
||||
*/
|
||||
public function setFileConfiguration(FileConfiguration $configuration): Application
|
||||
{
|
||||
$this->fileConfiguration = $configuration;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the HttpConfiguration instance for the application.
|
||||
*
|
||||
* @return HttpConfiguration The HttpConfiguration instance for the application.
|
||||
*/
|
||||
public function getHttpConfiguration(): HttpConfiguration
|
||||
{
|
||||
return $this->httpConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the HttpConfiguration instance for the application.
|
||||
*
|
||||
* @param HttpConfiguration $configuration The HttpConfiguration instance for the application.
|
||||
* @return Application Returns the current instance for method chaining.
|
||||
*/
|
||||
public function setHttpConfiguration(HttpConfiguration $configuration): Application
|
||||
{
|
||||
$this->httpConfiguration = $configuration;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the TcpConfiguration instance for the application.
|
||||
*
|
||||
* @return TcpConfiguration The TcpConfiguration instance for the application.
|
||||
*/
|
||||
public function getTcpConfiguration(): TcpConfiguration
|
||||
{
|
||||
return $this->tcpConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the TcpConfiguration instance for the application.
|
||||
*
|
||||
* @param TcpConfiguration $configuration The TcpConfiguration instance for the application.
|
||||
* @return Application Returns the current instance for method chaining.
|
||||
*/
|
||||
public function setTcpConfiguration(TcpConfiguration $configuration): Application
|
||||
{
|
||||
$this->tcpConfiguration = $configuration;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the UdpConfiguration instance for the application.
|
||||
*
|
||||
* @return UdpConfiguration The UdpConfiguration instance for the application.
|
||||
*/
|
||||
public function getUdpConfiguration(): UdpConfiguration
|
||||
{
|
||||
return $this->udpConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the UdpConfiguration instance for the application.
|
||||
*
|
||||
* @param UdpConfiguration $configuration The UdpConfiguration instance for the application.
|
||||
* @return Application Returns the current instance for method chaining.
|
||||
*/
|
||||
public function setUdpConfiguration(UdpConfiguration $configuration): Application
|
||||
{
|
||||
$this->udpConfiguration = $configuration;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the string representation of the application.
|
||||
*
|
||||
* @return string The string representation of the application.
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
}
|
162
src/LogLib2/Objects/Configurations/ConsoleConfiguration.php
Normal file
162
src/LogLib2/Objects/Configurations/ConsoleConfiguration.php
Normal file
|
@ -0,0 +1,162 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Objects\Configurations;
|
||||
|
||||
use LogLib2\Enums\AnsiFormat;
|
||||
use LogLib2\Enums\TimestampFormat;
|
||||
use LogLib2\Enums\TraceFormat;
|
||||
|
||||
class ConsoleConfiguration
|
||||
{
|
||||
private bool $enabled;
|
||||
private bool $displayName;
|
||||
private bool $displayLevel;
|
||||
private AnsiFormat $ansiFormat;
|
||||
private TraceFormat $traceFormat;
|
||||
private TimestampFormat $timestampFormat;
|
||||
|
||||
/**
|
||||
* ConsoleConfiguration constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->enabled = true;
|
||||
$this->displayName = true;
|
||||
$this->displayLevel = true;
|
||||
$this->ansiFormat = AnsiFormat::BASIC;
|
||||
$this->traceFormat = TraceFormat::BASIC;
|
||||
$this->timestampFormat = TimestampFormat::TIME_ONLY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the enabled status of the console configuration.
|
||||
*
|
||||
* @return bool Returns true if the console configuration is enabled, false otherwise.
|
||||
*/
|
||||
public function isEnabled(): bool
|
||||
{
|
||||
return $this->enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the enabled status of the console configuration.
|
||||
*
|
||||
* @param bool $enabled The enabled status to set.
|
||||
* @return ConsoleConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setEnabled(bool $enabled): ConsoleConfiguration
|
||||
{
|
||||
$this->enabled = $enabled;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the display name status of the console configuration.
|
||||
*
|
||||
* @return bool Returns true if the display name is enabled, false otherwise.
|
||||
*/
|
||||
public function isDisplayName(): bool
|
||||
{
|
||||
return $this->displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the display name status of the console configuration.
|
||||
*
|
||||
* @param bool $displayName The display name status to set.
|
||||
* @return ConsoleConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setDisplayName(bool $displayName): ConsoleConfiguration
|
||||
{
|
||||
$this->displayName = $displayName;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the display level status of the console configuration.
|
||||
*
|
||||
* @return bool Returns true if the display level is enabled, false otherwise.
|
||||
*/
|
||||
public function isDisplayLevel(): bool
|
||||
{
|
||||
return $this->displayLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the display level status of the console configuration.
|
||||
*
|
||||
* @param bool $displayLevel The display level status to set.
|
||||
* @return ConsoleConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setDisplayLevel(bool $displayLevel): ConsoleConfiguration
|
||||
{
|
||||
$this->displayLevel = $displayLevel;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the ANSI format of the console configuration.
|
||||
*
|
||||
* @return AnsiFormat Returns the ANSI format as an AnsiForamt.
|
||||
*/
|
||||
public function getAnsiFormat(): AnsiFormat
|
||||
{
|
||||
return $this->ansiFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ANSI format of the console configuration.
|
||||
*
|
||||
* @param AnsiFormat $ansiFormat The ANSI format to set.
|
||||
* @return ConsoleConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setAnsiFormat(AnsiFormat $ansiFormat): ConsoleConfiguration
|
||||
{
|
||||
$this->ansiFormat = $ansiFormat;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the trace format of the console configuration.
|
||||
*
|
||||
* @return TraceFormat Returns the trace format as a TraceFormat.
|
||||
*/
|
||||
public function getTraceFormat(): TraceFormat
|
||||
{
|
||||
return $this->traceFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the trace format of the console configuration.
|
||||
*
|
||||
* @param TraceFormat $traceFormat The trace format to set.
|
||||
* @return ConsoleConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setTraceFormat(TraceFormat $traceFormat): ConsoleConfiguration
|
||||
{
|
||||
$this->traceFormat = $traceFormat;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the timestamp format of the console configuration.
|
||||
*
|
||||
* @return TimestampFormat Returns the timestamp format as a TimestampFormat.
|
||||
*/
|
||||
public function getTimestampFormat(): TimestampFormat
|
||||
{
|
||||
return $this->timestampFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the timestamp format of the console configuration.
|
||||
*
|
||||
* @param TimestampFormat $timestampFormat The timestamp format to set.
|
||||
* @return ConsoleConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setTimestampFormat(TimestampFormat $timestampFormat): ConsoleConfiguration
|
||||
{
|
||||
$this->timestampFormat = $timestampFormat;
|
||||
return $this;
|
||||
}
|
||||
}
|
162
src/LogLib2/Objects/Configurations/DescriptorConfiguration.php
Normal file
162
src/LogLib2/Objects/Configurations/DescriptorConfiguration.php
Normal file
|
@ -0,0 +1,162 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Objects\Configurations;
|
||||
|
||||
use LogLib2\Enums\LogFormat;
|
||||
use LogLib2\Enums\TimestampFormat;
|
||||
use LogLib2\Enums\TraceFormat;
|
||||
|
||||
class DescriptorConfiguration
|
||||
{
|
||||
private bool $enabled;
|
||||
private string $descriptor;
|
||||
private bool $appendNewline;
|
||||
private LogFormat $logFormat;
|
||||
private TimestampFormat $timestampFormat;
|
||||
private TraceFormat $traceFormat;
|
||||
|
||||
/**
|
||||
* FileConfiguration constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->enabled = false;
|
||||
$this->descriptor = DIRECTORY_SEPARATOR . 'dev' . DIRECTORY_SEPARATOR . 'null';
|
||||
$this->appendNewline = false;
|
||||
$this->logFormat = LogFormat::JSONL;
|
||||
$this->timestampFormat = TimestampFormat::UNIX_TIMESTAMP;
|
||||
$this->traceFormat = TraceFormat::FULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the enabled status of the descriptor configuration.
|
||||
*
|
||||
* @return bool Returns true if the descriptor configuration is enabled, false otherwise.
|
||||
*/
|
||||
public function isEnabled(): bool
|
||||
{
|
||||
return $this->enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the enabled status of the descriptor configuration.
|
||||
*
|
||||
* @param bool $enabled The enabled status to set.
|
||||
* @return DescriptorConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setEnabled(bool $enabled): DescriptorConfiguration
|
||||
{
|
||||
$this->enabled = $enabled;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the descriptor of the descriptor configuration.
|
||||
*
|
||||
* @return string Returns the descriptor as a string.
|
||||
*/
|
||||
public function getDescriptor(): string
|
||||
{
|
||||
return $this->descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the descriptor of the descriptor configuration.
|
||||
*
|
||||
* @param string $descriptor The descriptor to set.
|
||||
* @return DescriptorConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setDescriptor(string $descriptor): DescriptorConfiguration
|
||||
{
|
||||
$this->descriptor = $descriptor;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the append newline status of the descriptor configuration.
|
||||
*
|
||||
* @return bool Returns true if the descriptor configuration appends a newline, false otherwise.
|
||||
*/
|
||||
public function isAppendNewline(): bool
|
||||
{
|
||||
return $this->appendNewline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the append newline status of the descriptor configuration.
|
||||
*
|
||||
* @param bool $appendNewline The append newline status to set.
|
||||
* @return DescriptorConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setAppendNewline(bool $appendNewline): DescriptorConfiguration
|
||||
{
|
||||
$this->appendNewline = $appendNewline;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the log type of the descriptor configuration.
|
||||
*
|
||||
* @return LogFormat Returns the log type.
|
||||
*/
|
||||
public function getLogFormat(): LogFormat
|
||||
{
|
||||
return $this->logFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the log type of the descriptor configuration.
|
||||
*
|
||||
* @param LogFormat $logFormat The log type to set.
|
||||
* @return DescriptorConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setLogFormat(LogFormat $logFormat): DescriptorConfiguration
|
||||
{
|
||||
$this->logFormat = $logFormat;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the timestamp type of the descriptor configuration.
|
||||
*
|
||||
* @return TimestampFormat Returns the timestamp type.
|
||||
*/
|
||||
public function getTimestampFormat(): TimestampFormat
|
||||
{
|
||||
return $this->timestampFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the timestamp type of the descriptor configuration.
|
||||
*
|
||||
* @param TimestampFormat $timestampFormat The timestamp type to set.
|
||||
* @return DescriptorConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setTimestampFormat(TimestampFormat $timestampFormat): DescriptorConfiguration
|
||||
{
|
||||
$this->timestampFormat = $timestampFormat;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the trace format of the descriptor configuration.
|
||||
*
|
||||
* @return TraceFormat Returns the trace format.
|
||||
*/
|
||||
public function getTraceFormat(): TraceFormat
|
||||
{
|
||||
return $this->traceFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the trace format of the descriptor configuration.
|
||||
*
|
||||
* @param TraceFormat $traceFormat The trace format to set.
|
||||
* @return DescriptorConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setTraceFormat(TraceFormat $traceFormat): DescriptorConfiguration
|
||||
{
|
||||
$this->traceFormat = $traceFormat;
|
||||
return $this;
|
||||
}
|
||||
}
|
210
src/LogLib2/Objects/Configurations/FileConfiguration.php
Normal file
210
src/LogLib2/Objects/Configurations/FileConfiguration.php
Normal file
|
@ -0,0 +1,210 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Objects\Configurations;
|
||||
|
||||
use LogLib2\Classes\Utilities;
|
||||
use LogLib2\Enums\LogFormat;
|
||||
use LogLib2\Enums\LogLevel;
|
||||
use LogLib2\Enums\TimestampFormat;
|
||||
use LogLib2\Enums\TraceFormat;
|
||||
|
||||
class FileConfiguration
|
||||
{
|
||||
private bool $enabled;
|
||||
private LogLevel $logLevel;
|
||||
private string $logPath;
|
||||
private int $defaultPermissions;
|
||||
private bool $appendNewline;
|
||||
private LogFormat $logFormat;
|
||||
private TimestampFormat $timestampFormat;
|
||||
private TraceFormat $traceFormat;
|
||||
|
||||
/**
|
||||
* FileConfiguration constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->enabled = true;
|
||||
$this->logPath = Utilities::getEnvironmentLogPath();
|
||||
$this->defaultPermissions = 0777;
|
||||
$this->appendNewline = true;
|
||||
$this->logFormat = LogFormat::TXT;
|
||||
$this->timestampFormat = TimestampFormat::TIME_ONLY;
|
||||
$this->traceFormat = TraceFormat::BASIC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the enabled status of the file configuration.
|
||||
*
|
||||
* @return bool Returns true if the file configuration is enabled, false otherwise.
|
||||
*/
|
||||
public function isEnabled(): bool
|
||||
{
|
||||
return $this->enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the enabled status of the file configuration.
|
||||
*
|
||||
* @param bool $enabled The enabled status to set.
|
||||
* @return FileConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setEnabled(bool $enabled): FileConfiguration
|
||||
{
|
||||
$this->enabled = $enabled;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the log level of the file configuration.
|
||||
*
|
||||
* @return LogLevel Returns the log level as a LogLevel.
|
||||
*/
|
||||
public function getLogLevel(): LogLevel
|
||||
{
|
||||
return $this->logLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the log level of the file configuration.
|
||||
*
|
||||
* @param LogLevel $logLevel The log level to set.
|
||||
* @return FileConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setLogLevel(LogLevel $logLevel): FileConfiguration
|
||||
{
|
||||
$this->logLevel = $logLevel;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the log path of the file configuration.
|
||||
*
|
||||
* @return string Returns the log path as a string.
|
||||
*/
|
||||
public function getLogPath(): string
|
||||
{
|
||||
return $this->logPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the log path of the file configuration.
|
||||
*
|
||||
* @param string $logPath The log path to set.
|
||||
* @return FileConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setLogPath(string $logPath): FileConfiguration
|
||||
{
|
||||
$this->logPath = $logPath;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the default permissions of the file configuration.
|
||||
*
|
||||
* @return int Returns the default permissions as an integer.
|
||||
*/
|
||||
public function getDefaultPermissions(): int
|
||||
{
|
||||
return $this->defaultPermissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $defaultPermissions
|
||||
* @return FileConfiguration
|
||||
*/
|
||||
public function setDefaultPermissions(int $defaultPermissions): FileConfiguration
|
||||
{
|
||||
$this->defaultPermissions = $defaultPermissions;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the append newline status of the file configuration.
|
||||
*
|
||||
* @return bool Returns true if the file configuration appends a newline, false otherwise.
|
||||
*/
|
||||
public function isAppendNewline(): bool
|
||||
{
|
||||
return $this->appendNewline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the append newline status of the file configuration.
|
||||
*
|
||||
* @param bool $appendNewline The append newline status to set.
|
||||
* @return FileConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setAppendNewline(bool $appendNewline): FileConfiguration
|
||||
{
|
||||
$this->appendNewline = $appendNewline;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the log type of the file configuration.
|
||||
*
|
||||
* @return LogFormat Returns the log type.
|
||||
*/
|
||||
public function getLogFormat(): LogFormat
|
||||
{
|
||||
return $this->logFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the log type of the file configuration.
|
||||
*
|
||||
* @param LogFormat $logFormat The log type to set.
|
||||
* @return FileConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setLogFormat(LogFormat $logFormat): FileConfiguration
|
||||
{
|
||||
$this->logFormat = $logFormat;
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the timestamp format of the file configuration.
|
||||
*
|
||||
* @return TimestampFormat Returns the timestamp format as a TimestampFormat.
|
||||
*/
|
||||
public function getTimestampFormat(): TimestampFormat
|
||||
{
|
||||
return $this->timestampFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the timestamp format of the file configuration.
|
||||
*
|
||||
* @param TimestampFormat $timestampFormat The timestamp format to set.
|
||||
* @return FileConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setTimestampFormat(TimestampFormat $timestampFormat): FileConfiguration
|
||||
{
|
||||
$this->timestampFormat = $timestampFormat;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the trace format of the file configuration.
|
||||
*
|
||||
* @return TraceFormat Returns the trace format as a TraceFormat.
|
||||
*/
|
||||
public function getTraceFormat(): TraceFormat
|
||||
{
|
||||
return $this->traceFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the trace format of the file configuration.
|
||||
*
|
||||
* @param TraceFormat $traceFormat The trace format to set.
|
||||
* @return FileConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setTraceFormat(TraceFormat $traceFormat): FileConfiguration
|
||||
{
|
||||
$this->traceFormat = $traceFormat;
|
||||
return $this;
|
||||
}
|
||||
}
|
162
src/LogLib2/Objects/Configurations/HttpConfiguration.php
Normal file
162
src/LogLib2/Objects/Configurations/HttpConfiguration.php
Normal file
|
@ -0,0 +1,162 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Objects\Configurations;
|
||||
|
||||
use LogLib2\Enums\LogFormat;
|
||||
use LogLib2\Enums\TimestampFormat;
|
||||
use LogLib2\Enums\TraceFormat;
|
||||
|
||||
class HttpConfiguration
|
||||
{
|
||||
private bool $enabled;
|
||||
private string $endpoint;
|
||||
private bool $appendNewline;
|
||||
private LogFormat $logFormat;
|
||||
private TimestampFormat $timestampFormat;
|
||||
private TraceFormat $traceFormat;
|
||||
|
||||
/**
|
||||
* HttpConfiguration constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->enabled = false;
|
||||
$this->endpoint = 'http://0.0.0.0:5131';
|
||||
$this->appendNewline = false;
|
||||
$this->logFormat = LogFormat::JSONL;
|
||||
$this->timestampFormat = TimestampFormat::UNIX_TIMESTAMP;
|
||||
$this->traceFormat = TraceFormat::FULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the enabled status of the HTTP configuration.
|
||||
*
|
||||
* @return bool Returns true if the HTTP configuration is enabled, false otherwise.
|
||||
*/
|
||||
public function isEnabled(): bool
|
||||
{
|
||||
return $this->enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the enabled status of the HTTP configuration.
|
||||
*
|
||||
* @param bool $enabled The enabled status to set.
|
||||
* @return HttpConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setEnabled(bool $enabled): HttpConfiguration
|
||||
{
|
||||
$this->enabled = $enabled;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the endpoint of the HTTP configuration.
|
||||
*
|
||||
* @return string Returns the endpoint as a string.
|
||||
*/
|
||||
public function getEndpoint(): string
|
||||
{
|
||||
return $this->endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the endpoint of the HTTP configuration.
|
||||
*
|
||||
* @param string $endpoint The endpoint to set.
|
||||
* @return HttpConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setEndpoint(string $endpoint): HttpConfiguration
|
||||
{
|
||||
$this->endpoint = $endpoint;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the append newline status of the HTTP configuration.
|
||||
*
|
||||
* @return bool Returns true if the HTTP configuration appends a newline, false otherwise.
|
||||
*/
|
||||
public function isAppendNewline(): bool
|
||||
{
|
||||
return $this->appendNewline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the append newline status of the HTTP configuration.
|
||||
*
|
||||
* @param bool $appendNewline The append newline status to set.
|
||||
* @return HttpConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setAppendNewline(bool $appendNewline): HttpConfiguration
|
||||
{
|
||||
$this->appendNewline = $appendNewline;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the log format of the HTTP configuration.
|
||||
*
|
||||
* @return LogFormat Returns the log format.
|
||||
*/
|
||||
public function getLogFormat(): LogFormat
|
||||
{
|
||||
return $this->logFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the log format of the HTTP configuration.
|
||||
*
|
||||
* @param LogFormat $logFormat The log format to set.
|
||||
* @return HttpConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setLogFormat(LogFormat $logFormat): HttpConfiguration
|
||||
{
|
||||
$this->logFormat = $logFormat;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the timestamp format of the HTTP configuration.
|
||||
*
|
||||
* @return TimestampFormat Returns the timestamp format.
|
||||
*/
|
||||
public function getTimestampFormat(): TimestampFormat
|
||||
{
|
||||
return $this->timestampFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the timestamp format of the HTTP configuration.
|
||||
*
|
||||
* @param TimestampFormat $timestampFormat The timestamp format to set.
|
||||
* @return HttpConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setTimestampFormat(TimestampFormat $timestampFormat): HttpConfiguration
|
||||
{
|
||||
$this->timestampFormat = $timestampFormat;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the trace format of the HTTP configuration.
|
||||
*
|
||||
* @return TraceFormat Returns the trace format.
|
||||
*/
|
||||
public function getTraceFormat(): TraceFormat
|
||||
{
|
||||
return $this->traceFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the trace format of the HTTP configuration.
|
||||
*
|
||||
* @param TraceFormat $traceFormat The trace format to set.
|
||||
* @return HttpConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setTraceFormat(TraceFormat $traceFormat): HttpConfiguration
|
||||
{
|
||||
$this->traceFormat = $traceFormat;
|
||||
return $this;
|
||||
}
|
||||
}
|
174
src/LogLib2/Objects/Configurations/TcpConfiguration.php
Normal file
174
src/LogLib2/Objects/Configurations/TcpConfiguration.php
Normal file
|
@ -0,0 +1,174 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Objects\Configurations;
|
||||
|
||||
use LogLib2\Enums\LogFormat;
|
||||
use LogLib2\Enums\TimestampFormat;
|
||||
use LogLib2\Enums\TraceFormat;
|
||||
|
||||
class TcpConfiguration
|
||||
{
|
||||
private bool $enabled;
|
||||
private string $host;
|
||||
private int $port;
|
||||
private bool $appendNewline;
|
||||
private LogFormat $logFormat;
|
||||
private TimestampFormat $timestampFormat;
|
||||
private TraceFormat $traceFormat;
|
||||
|
||||
/**
|
||||
* TcpConfiguration constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->enabled = false;
|
||||
$this->host = '0.0.0.0';
|
||||
$this->port = 5131;
|
||||
$this->appendNewline = false;
|
||||
$this->logFormat = LogFormat::JSONL;
|
||||
$this->timestampFormat = TimestampFormat::UNIX_TIMESTAMP;
|
||||
$this->traceFormat = TraceFormat::FULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the enabled status of the TCP configuration.
|
||||
*
|
||||
* @return bool Returns true if the TCP configuration is enabled, false otherwise.
|
||||
*/
|
||||
public function isEnabled(): bool
|
||||
{
|
||||
return $this->enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the enabled status of the TCP configuration.
|
||||
*
|
||||
* @param bool $enabled The enabled status to set.
|
||||
* @return TcpConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setEnabled(bool $enabled): TcpConfiguration
|
||||
{
|
||||
$this->enabled = $enabled;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the host of the TCP configuration.
|
||||
*
|
||||
* @return string Returns the host as a string.
|
||||
*/
|
||||
public function getHost(): string
|
||||
{
|
||||
return $this->host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the host of the TCP configuration.
|
||||
*
|
||||
* @param string $host The host to set.
|
||||
* @return TcpConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setHost(string $host): TcpConfiguration
|
||||
{
|
||||
$this->host = $host;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the port of the TCP configuration.
|
||||
*
|
||||
* @return int Returns the port as an integer.
|
||||
*/
|
||||
public function getPort(): int
|
||||
{
|
||||
return $this->port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the port of the TCP configuration.
|
||||
*
|
||||
* @param int $port The port to set.
|
||||
* @return TcpConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setPort(int $port): TcpConfiguration
|
||||
{
|
||||
$this->port = $port;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the append newline status of the TCP configuration.
|
||||
*
|
||||
* @return bool Returns true if the TCP configuration appends a newline, false otherwise.
|
||||
*/
|
||||
public function isAppendNewline(): bool
|
||||
{
|
||||
return $this->appendNewline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the append newline status of the TCP configuration.
|
||||
*
|
||||
* @param bool $appendNewline The append newline status to set.
|
||||
* @return TcpConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setAppendNewline(bool $appendNewline): TcpConfiguration
|
||||
{
|
||||
$this->appendNewline = $appendNewline;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the log format of the TCP configuration.
|
||||
*
|
||||
* @return LogFormat Returns the log format.
|
||||
*/
|
||||
public function getLogFormat(): LogFormat
|
||||
{
|
||||
return $this->logFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the log format of the TCP configuration.
|
||||
*
|
||||
* @param LogFormat $logFormat The log format to set.
|
||||
* @return TcpConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setLogFormat(LogFormat $logFormat): TcpConfiguration
|
||||
{
|
||||
$this->logFormat = $logFormat;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the timestamp format of the TCP configuration.
|
||||
*
|
||||
* @return TimestampFormat Returns the timestamp format.
|
||||
*/
|
||||
public function getTimestampFormat(): TimestampFormat
|
||||
{
|
||||
return $this->timestampFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the timestamp format of the TCP configuration.
|
||||
*
|
||||
* @param TimestampFormat $timestampFormat The timestamp format to set.
|
||||
* @return TcpConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setTimestampFormat(TimestampFormat $timestampFormat): TcpConfiguration
|
||||
{
|
||||
$this->timestampFormat = $timestampFormat;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the trace format of the TCP configuration.
|
||||
*
|
||||
* @return TraceFormat Returns the trace format.
|
||||
*/
|
||||
public function getTraceFormat(): TraceFormat
|
||||
{
|
||||
return $this->traceFormat;
|
||||
}
|
||||
}
|
186
src/LogLib2/Objects/Configurations/UdpConfiguration.php
Normal file
186
src/LogLib2/Objects/Configurations/UdpConfiguration.php
Normal file
|
@ -0,0 +1,186 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Objects\Configurations;
|
||||
|
||||
use LogLib2\Enums\LogFormat;
|
||||
use LogLib2\Enums\TimestampFormat;
|
||||
use LogLib2\Enums\TraceFormat;
|
||||
|
||||
class UdpConfiguration
|
||||
{
|
||||
private bool $enabled;
|
||||
private string $host;
|
||||
private int $port;
|
||||
private bool $appendNewline;
|
||||
private LogFormat $logFormat;
|
||||
private TimestampFormat $timestampFormat;
|
||||
private TraceFormat $traceFormat;
|
||||
|
||||
/**
|
||||
* TcpConfiguration constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->enabled = false;
|
||||
$this->host = '0.0.0.0';
|
||||
$this->port = 5131;
|
||||
$this->appendNewline = false;
|
||||
$this->logFormat = LogFormat::JSONL;
|
||||
$this->timestampFormat = TimestampFormat::UNIX_TIMESTAMP;
|
||||
$this->traceFormat = TraceFormat::FULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the enabled status of the TCP configuration.
|
||||
*
|
||||
* @return bool Returns true if the TCP configuration is enabled, false otherwise.
|
||||
*/
|
||||
public function isEnabled(): bool
|
||||
{
|
||||
return $this->enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the enabled status of the TCP configuration.
|
||||
*
|
||||
* @param bool $enabled The enabled status to set.
|
||||
* @return UdpConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setEnabled(bool $enabled): UdpConfiguration
|
||||
{
|
||||
$this->enabled = $enabled;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the host of the TCP configuration.
|
||||
*
|
||||
* @return string Returns the host as a string.
|
||||
*/
|
||||
public function getHost(): string
|
||||
{
|
||||
return $this->host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the host of the TCP configuration.
|
||||
*
|
||||
* @param string $host The host to set.
|
||||
* @return UdpConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setHost(string $host): UdpConfiguration
|
||||
{
|
||||
$this->host = $host;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the port of the TCP configuration.
|
||||
*
|
||||
* @return int Returns the port as an integer.
|
||||
*/
|
||||
public function getPort(): int
|
||||
{
|
||||
return $this->port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the port of the TCP configuration.
|
||||
*
|
||||
* @param int $port The port to set.
|
||||
* @return UdpConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setPort(int $port): UdpConfiguration
|
||||
{
|
||||
$this->port = $port;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the append newline status of the TCP configuration.
|
||||
*
|
||||
* @return bool Returns true if the TCP configuration appends a newline, false otherwise.
|
||||
*/
|
||||
public function isAppendNewline(): bool
|
||||
{
|
||||
return $this->appendNewline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the append newline status of the TCP configuration.
|
||||
*
|
||||
* @param bool $appendNewline The append newline status to set.
|
||||
* @return UdpConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setAppendNewline(bool $appendNewline): UdpConfiguration
|
||||
{
|
||||
$this->appendNewline = $appendNewline;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the log format of the TCP configuration.
|
||||
*
|
||||
* @return LogFormat Returns the log format.
|
||||
*/
|
||||
public function getLogFormat(): LogFormat
|
||||
{
|
||||
return $this->logFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the log format of the TCP configuration.
|
||||
*
|
||||
* @param LogFormat $logFormat The log format to set.
|
||||
* @return UdpConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setLogFormat(LogFormat $logFormat): UdpConfiguration
|
||||
{
|
||||
$this->logFormat = $logFormat;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the timestamp format of the TCP configuration.
|
||||
*
|
||||
* @return TimestampFormat Returns the timestamp format.
|
||||
*/
|
||||
public function getTimestampFormat(): TimestampFormat
|
||||
{
|
||||
return $this->timestampFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the timestamp format of the TCP configuration.
|
||||
*
|
||||
* @param TimestampFormat $timestampFormat The timestamp format to set.
|
||||
* @return UdpConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setTimestampFormat(TimestampFormat $timestampFormat): UdpConfiguration
|
||||
{
|
||||
$this->timestampFormat = $timestampFormat;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the trace format of the TCP configuration.
|
||||
*
|
||||
* @return TraceFormat Returns the trace format.
|
||||
*/
|
||||
public function getTraceFormat(): TraceFormat
|
||||
{
|
||||
return $this->traceFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the trace format of the TCP configuration.
|
||||
*
|
||||
* @param TraceFormat $traceFormat The trace format to set.
|
||||
* @return UdpConfiguration Returns the current instance.
|
||||
*/
|
||||
public function setTraceFormat(TraceFormat $traceFormat): UdpConfiguration
|
||||
{
|
||||
$this->traceFormat = $traceFormat;
|
||||
return $this;
|
||||
}
|
||||
}
|
215
src/LogLib2/Objects/Event.php
Normal file
215
src/LogLib2/Objects/Event.php
Normal file
|
@ -0,0 +1,215 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Objects;
|
||||
|
||||
use LogLib2\Enums\LogLevel;
|
||||
use LogLib2\Enums\TimestampFormat;
|
||||
use LogLib2\Enums\TraceFormat;
|
||||
use LogLib2\Interfaces\SerializableInterface;
|
||||
use Throwable;
|
||||
|
||||
class Event implements SerializableInterface
|
||||
{
|
||||
private string $applicationName;
|
||||
private int $timestamp;
|
||||
private LogLevel $level;
|
||||
private string $message;
|
||||
private ?ExceptionDetails $exception;
|
||||
/**
|
||||
* @var StackTrace[]
|
||||
*/
|
||||
private array $traces;
|
||||
|
||||
/**
|
||||
* Constructs a new instance with the provided parameters.
|
||||
*
|
||||
* @param string $applicationName The name of the application that generated the event.
|
||||
* @param LogLevel $level The log level of the event.
|
||||
* @param string $message The message of the event.
|
||||
* @param array $backtrace The array of StackTrace instances.
|
||||
* @param int|null $timestamp The timestamp of the event, or null if not specified (defaults to the current time).
|
||||
* @param ExceptionDetails|Throwable|null $exceptionDetails The exception details, or null if not specified.
|
||||
*/
|
||||
public function __construct(string $applicationName, LogLevel $level, string $message, array $backtrace, ?int $timestamp=null, ExceptionDetails|Throwable|null $exceptionDetails=null)
|
||||
{
|
||||
if($exceptionDetails instanceof Throwable)
|
||||
{
|
||||
$exceptionDetails = ExceptionDetails::fromThrowable($exceptionDetails);
|
||||
}
|
||||
|
||||
$this->applicationName = $applicationName;
|
||||
if($timestamp === null)
|
||||
{
|
||||
$timestamp = time();
|
||||
}
|
||||
$this->timestamp = $timestamp;
|
||||
$this->level = $level;
|
||||
$this->message = $message;
|
||||
$this->exception = $exceptionDetails;
|
||||
$this->traces = $backtrace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the application name.
|
||||
*
|
||||
* @return string Returns the application name as a string.
|
||||
*/
|
||||
public function getApplicationName(): string
|
||||
{
|
||||
return $this->applicationName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the timestamp.
|
||||
*
|
||||
* @return int Returns the timestamp as an integer.
|
||||
*/
|
||||
public function getTimestamp(): int
|
||||
{
|
||||
return $this->timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the log level.
|
||||
*
|
||||
* @return LogLevel Returns the log level as a LogLevel instance.
|
||||
*/
|
||||
public function getLevel(): LogLevel
|
||||
{
|
||||
return $this->level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the message.
|
||||
*
|
||||
* @return string Returns the message as a string.
|
||||
*/
|
||||
public function getMessage(): string
|
||||
{
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the exception details.
|
||||
*
|
||||
* @return ExceptionDetails|null Returns the exception details, or null if not set.
|
||||
*/
|
||||
public function getException(): ?ExceptionDetails
|
||||
{
|
||||
return $this->exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the backtrace.
|
||||
*
|
||||
* @return StackTrace[] Returns the backtrace as an array of StackTrace instances.
|
||||
*/
|
||||
public function getTraces(): array
|
||||
{
|
||||
return $this->traces;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the first trace.
|
||||
*
|
||||
* @return StackTrace|null Returns the first trace or null if no traces are set.
|
||||
*/
|
||||
public function getFirstTrace(): ?StackTrace
|
||||
{
|
||||
if(count($this->traces) > 0)
|
||||
{
|
||||
return $this->traces[0];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a standard array representation of the event.
|
||||
*
|
||||
* @return array The standard array representation of the event.
|
||||
*/
|
||||
public function toStandardArray(TimestampFormat $timestampFormat, TraceFormat $traceFormat): array
|
||||
{
|
||||
$result = $this->toArray();
|
||||
|
||||
/// Rename the traces to stack_trace
|
||||
$result['stack_trace'] = $result['traces'];
|
||||
unset($result['traces']);
|
||||
|
||||
// Format the timestamp
|
||||
if($timestampFormat === TimestampFormat::NONE)
|
||||
{
|
||||
$result['timestamp'] = TimestampFormat::UNIX_TIMESTAMP->format($result['timestamp']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$result['timestamp'] = $timestampFormat->format($result['timestamp']);
|
||||
}
|
||||
|
||||
// Format the trace
|
||||
if(count($result['stack_trace']) > 0)
|
||||
{
|
||||
$result['trace'] = $traceFormat->format($this->getFirstTrace());
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
$result = [
|
||||
'application_name' => $this->applicationName,
|
||||
'timestamp' => $this->timestamp,
|
||||
'level' => $this->level->value,
|
||||
'message' => $this->message,
|
||||
'traces' => [],
|
||||
'exception' => null,
|
||||
];
|
||||
|
||||
foreach($this->traces as $trace)
|
||||
{
|
||||
$result['traces'][] = $trace->toArray();
|
||||
}
|
||||
|
||||
if($this->exception !== null)
|
||||
{
|
||||
$result['exception'] = $this->exception->toArray();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function fromArray(?array $data=null): Event
|
||||
{
|
||||
$traces = [];
|
||||
if(isset($data['traces']))
|
||||
{
|
||||
foreach($data['traces'] as $traceData)
|
||||
{
|
||||
$traces[] = StackTrace::fromArray($traceData);
|
||||
}
|
||||
}
|
||||
|
||||
$exceptionDetails = null;
|
||||
if(isset($data['exception']))
|
||||
{
|
||||
$exceptionDetails = ExceptionDetails::fromArray($data['exception']);
|
||||
}
|
||||
|
||||
return new Event(
|
||||
$data['application_name'],
|
||||
LogLevel::from($data['level']),
|
||||
$data['message'],
|
||||
$traces,
|
||||
$data['timestamp'],
|
||||
$exceptionDetails
|
||||
);
|
||||
}
|
||||
}
|
171
src/LogLib2/Objects/ExceptionDetails.php
Normal file
171
src/LogLib2/Objects/ExceptionDetails.php
Normal file
|
@ -0,0 +1,171 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Objects;
|
||||
|
||||
use LogLib2\Interfaces\SerializableInterface;
|
||||
use Throwable;
|
||||
|
||||
class ExceptionDetails implements SerializableInterface
|
||||
{
|
||||
private string $name;
|
||||
private string $message;
|
||||
private ?int $code;
|
||||
private ?string $file;
|
||||
private ?int $line;
|
||||
/**
|
||||
* @var StackTrace[]|null
|
||||
*/
|
||||
private ?array $trace;
|
||||
private ?ExceptionDetails $previous;
|
||||
|
||||
/**
|
||||
* Constructs a new instance with the provided parameters.
|
||||
*
|
||||
* @param string $name The name of the exception.
|
||||
* @param string $message The exception message.
|
||||
* @param int|null $code The exception code, or null if not specified.
|
||||
* @param string|null $file The file name, or null if not specified.
|
||||
* @param int|null $line The line number, or null if not specified.
|
||||
* @param StackTrace[]|null $trace The array of StackTrace instances, or null if not provided.
|
||||
* @param ExceptionDetails|null $previous The previous exception, or null if not specified.
|
||||
*/
|
||||
public function __construct(string $name, string $message, ?int $code=null, ?string $file=null, ?int $line=null, ?array $trace=null, ?ExceptionDetails $previous=null)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->message = $message;
|
||||
$this->code = $code;
|
||||
$this->file = $file;
|
||||
$this->line = $line;
|
||||
$this->trace = $trace;
|
||||
$this->previous = $previous;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function getMessage(): string
|
||||
{
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
public function getCode(): ?int
|
||||
{
|
||||
return $this->code;
|
||||
}
|
||||
|
||||
public function getFile(): ?string
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
public function getLine(): ?int
|
||||
{
|
||||
return $this->line;
|
||||
}
|
||||
|
||||
public function getTrace(): ?array
|
||||
{
|
||||
return $this->trace;
|
||||
}
|
||||
|
||||
public function getPrevious(): ?ExceptionDetails
|
||||
{
|
||||
return $this->previous;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
$result = [
|
||||
'name' => $this->name,
|
||||
'message' => $this->message,
|
||||
'code' => $this->code,
|
||||
'file' => $this->file,
|
||||
'line' => $this->line,
|
||||
'trace' => [],
|
||||
'previous' => null,
|
||||
];
|
||||
|
||||
if($this->trace !== null)
|
||||
{
|
||||
foreach($this->trace as $trace)
|
||||
{
|
||||
$result['trace'][] = $trace->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
if($this->previous !== null)
|
||||
{
|
||||
$result['previous'] = $this->previous->toArray();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function fromArray(?array $data=null): SerializableInterface
|
||||
{
|
||||
|
||||
$trace = [];
|
||||
if(isset($data['trace']))
|
||||
{
|
||||
foreach($data['trace'] as $traceData)
|
||||
{
|
||||
$trace[] = StackTrace::fromArray($traceData);
|
||||
}
|
||||
}
|
||||
|
||||
$previous = null;
|
||||
if(isset($data['previous']))
|
||||
{
|
||||
$previous = self::fromArray($data['previous']);
|
||||
}
|
||||
|
||||
return new ExceptionDetails(
|
||||
$data['name'] ?? '',
|
||||
$data['message'] ?? '',
|
||||
$data['code'] ?? null,
|
||||
$data['file'] ?? null,
|
||||
$data['line'] ?? null,
|
||||
$trace,
|
||||
$previous
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance from the provided Throwable instance.
|
||||
*
|
||||
* @param Throwable $e The Throwable instance to create the ExceptionDetails instance from.
|
||||
* @return ExceptionDetails The created ExceptionDetails instance.
|
||||
*/
|
||||
public static function fromThrowable(Throwable $e): ExceptionDetails
|
||||
{
|
||||
$trace = [];
|
||||
foreach($e->getTrace() as $traceData)
|
||||
{
|
||||
$trace[] = StackTrace::fromTrace($traceData);
|
||||
}
|
||||
|
||||
$previous = null;
|
||||
if($e->getPrevious() !== null)
|
||||
{
|
||||
$previous = self::fromThrowable($e->getPrevious());
|
||||
}
|
||||
|
||||
return new ExceptionDetails(
|
||||
get_class($e),
|
||||
$e->getMessage(),
|
||||
$e->getCode(),
|
||||
$e->getFile(),
|
||||
$e->getLine(),
|
||||
$trace,
|
||||
$previous
|
||||
);
|
||||
}
|
||||
}
|
207
src/LogLib2/Objects/StackTrace.php
Normal file
207
src/LogLib2/Objects/StackTrace.php
Normal file
|
@ -0,0 +1,207 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2\Objects;
|
||||
|
||||
use LogLib2\Classes\Utilities;
|
||||
use LogLib2\Enums\CallType;
|
||||
use LogLib2\Interfaces\SerializableInterface;
|
||||
|
||||
class StackTrace implements SerializableInterface
|
||||
{
|
||||
private ?string $file;
|
||||
private ?int $line;
|
||||
private ?string $function;
|
||||
private ?array $args;
|
||||
private ?string $class;
|
||||
private ?CallType $callType;
|
||||
|
||||
/**
|
||||
* Constructs a new instance with the provided parameters.
|
||||
*
|
||||
* @param string|null $file The file name, or null if not specified.
|
||||
* @param int|null $line The line number, or null if not specified.
|
||||
* @param string|null $function The function name, or null if not specified.
|
||||
* @param array|null $args The array of arguments, or null if not provided.
|
||||
* @param string|null $class The class name, or null if not specified.
|
||||
* @param CallType|null $callType The type of the call, or null if not specified.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(?string $file=null, ?int $line=null, ?string $function=null, ?array $args=null, ?string $class=null, ?CallType $callType=null)
|
||||
{
|
||||
$this->file = $file;
|
||||
$this->line = $line;
|
||||
$this->function = $function;
|
||||
|
||||
if($args !== null && !empty($args))
|
||||
{
|
||||
$this->args = $args;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->args = null;
|
||||
}
|
||||
|
||||
$this->class = $class;
|
||||
$this->callType = $callType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the file name.
|
||||
*
|
||||
* @return string|null Returns the file as a string, or null if no file is set.
|
||||
*/
|
||||
public function getFile(): ?string
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the line number.
|
||||
*
|
||||
* @return int|null Returns the line number or null if not set.
|
||||
*/
|
||||
public function getLine(): ?int
|
||||
{
|
||||
return $this->line;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the function name.
|
||||
*
|
||||
* @return string|null The function name or null if not set.
|
||||
*/
|
||||
public function getFunction(): ?string
|
||||
{
|
||||
return $this->function;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the arguments.
|
||||
*
|
||||
* @return array|null Returns an array of arguments or null if no arguments are set.
|
||||
*/
|
||||
public function getArgs(): ?array
|
||||
{
|
||||
return $this->args;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return string|null The class name or null if not set.
|
||||
*/
|
||||
public function getClass(): ?string
|
||||
{
|
||||
return $this->class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the call type.
|
||||
*
|
||||
* @return CallType|null The call type or null if not set.
|
||||
*/
|
||||
public function getCallType(): ?CallType
|
||||
{
|
||||
return $this->callType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the current object contains no data.
|
||||
*
|
||||
* @return bool True if all properties are null, false otherwise.
|
||||
*/
|
||||
public function isEmpty(): bool
|
||||
{
|
||||
return
|
||||
$this->file === null &&
|
||||
$this->line === null &&
|
||||
$this->function === null &&
|
||||
$this->args === null &&
|
||||
$this->class === null &&
|
||||
$this->callType === null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'file' => $this->file,
|
||||
'line' => $this->line,
|
||||
'function' => $this->function,
|
||||
'args' => $this->args,
|
||||
'class' => $this->class,
|
||||
'call_type' => $this->callType?->value ?? CallType::STATIC_CALL->value,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function fromArray(?array $data=null): StackTrace
|
||||
{
|
||||
$callType = null;
|
||||
if(isset($data['call_type']))
|
||||
{
|
||||
$callType = CallType::tryFrom($data['call_type']);
|
||||
}
|
||||
|
||||
return new StackTrace(
|
||||
$data['file'] ?? null,
|
||||
$data['line'] ?? null,
|
||||
$data['function'] ?? null,
|
||||
$data['args'] ?? null,
|
||||
$data['class'] ?? null,
|
||||
$callType
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance from the provided trace data.
|
||||
*
|
||||
* @param array $trace The trace data to be used.
|
||||
* @return StackTrace The new instance created from the trace data.
|
||||
*/
|
||||
public static function fromTrace(array $trace): StackTrace
|
||||
{
|
||||
$parsedTrace = [
|
||||
'file' => $trace['file'] ?? null,
|
||||
'function' => $trace['function'] ?? null,
|
||||
'class' => $trace['class'] ?? null,
|
||||
'call' => $trace['call'] ?? null,
|
||||
];
|
||||
|
||||
if(isset($trace['line']))
|
||||
{
|
||||
$parsedTrace['line'] = (int) $trace['line'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$parsedTrace['line'] = null;
|
||||
}
|
||||
|
||||
if(isset($trace['args']))
|
||||
{
|
||||
$result = [];
|
||||
if(array_is_list($trace['args']))
|
||||
{
|
||||
foreach($trace['args'] as $arg)
|
||||
{
|
||||
$result[] = Utilities::getSafeValue($arg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach($trace['args'] as $key => $arg)
|
||||
{
|
||||
$result[$key] = Utilities::getSafeValue($arg);
|
||||
}
|
||||
}
|
||||
|
||||
$parsedTrace['args'] = $result;
|
||||
}
|
||||
|
||||
return StackTrace::fromArray($parsedTrace);
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace LogLib2;
|
||||
|
||||
class Program
|
||||
{
|
||||
/**
|
||||
* LogLib2 main entry point
|
||||
*
|
||||
* @param string[] $args Command-line arguments
|
||||
* @return int Exit code
|
||||
*/
|
||||
public static function main(array $args): int
|
||||
{
|
||||
print("Hello World from net.nosial.loglib2!" . PHP_EOL);
|
||||
return 0;
|
||||
}
|
||||
}
|
11
src/LogLib2/autoload_patch.php
Normal file
11
src/LogLib2/autoload_patch.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is used to patch the autoloader, ncc will load this file first before evaluating the package's class
|
||||
* files. Without this file, ncc will run into a recursive dependency issue where classes are trying to load each
|
||||
* other before they are defined.
|
||||
*/
|
||||
|
||||
require __DIR__ . DIRECTORY_SEPARATOR . 'Objects' . DIRECTORY_SEPARATOR . 'Event.php';
|
||||
require __DIR__ . DIRECTORY_SEPARATOR . 'Objects' . DIRECTORY_SEPARATOR . 'ExceptionDetails.php';
|
||||
require __DIR__ . DIRECTORY_SEPARATOR . 'Objects' . DIRECTORY_SEPARATOR . 'StackTrace.php';
|
Loading…
Add table
Reference in a new issue