Compare commits

..

No commits in common. "master" and "1.0.0" have entirely different histories.

44 changed files with 1004 additions and 2910 deletions

View file

@ -1,552 +0,0 @@
name: CI
on:
push:
branches:
- '**'
release:
types: [created]
workflow_dispatch:
jobs:
release:
runs-on: ubuntu-latest
container:
image: php:8.3
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install dependencies
run: |
apt update -yqq
apt install git libpq-dev libzip-dev zip make wget gnupg -yqq
- name: Install phive
run: |
wget -O phive.phar https://phar.io/releases/phive.phar
wget -O phive.phar.asc https://phar.io/releases/phive.phar.asc
gpg --keyserver hkps://keys.openpgp.org --recv-keys 0x9D8A98B29B2D5D79
gpg --verify phive.phar.asc phive.phar
chmod +x phive.phar
mv phive.phar /usr/local/bin/phive
- name: Install phab
run: |
phive install phpab --global --trust-gpg-keys 0x2A8299CE842DD38C
- name: Install latest version of NCC
run: |
git clone https://git.n64.cc/nosial/ncc.git
cd ncc
make redist
NCC_DIR=$(find build/ -type d -name "ncc_*" | head -n 1)
if [ -z "$NCC_DIR" ]; then
echo "NCC build directory not found"
exit 1
fi
php "$NCC_DIR/INSTALL" --auto
cd .. && rm -rf ncc
- name: Build project
run: |
ncc build --config release --build-source --log-level debug
- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: release
path: build/release/net.nosial.loglib.ncc
release-compressed:
runs-on: ubuntu-latest
container:
image: php:8.3
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install dependencies
run: |
apt update -yqq
apt install git libpq-dev libzip-dev zip make wget gnupg -yqq
- name: Install phive
run: |
wget -O phive.phar https://phar.io/releases/phive.phar
wget -O phive.phar.asc https://phar.io/releases/phive.phar.asc
gpg --keyserver hkps://keys.openpgp.org --recv-keys 0x9D8A98B29B2D5D79
gpg --verify phive.phar.asc phive.phar
chmod +x phive.phar
mv phive.phar /usr/local/bin/phive
- name: Install phab
run: |
phive install phpab --global --trust-gpg-keys 0x2A8299CE842DD38C
- name: Install latest version of NCC
run: |
git clone https://git.n64.cc/nosial/ncc.git
cd ncc
make redist
NCC_DIR=$(find build/ -type d -name "ncc_*" | head -n 1)
if [ -z "$NCC_DIR" ]; then
echo "NCC build directory not found"
exit 1
fi
php "$NCC_DIR/INSTALL" --auto
cd .. && rm -rf ncc
- name: Build project
run: |
ncc build --config release-compressed --build-source --log-level debug
- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: release-compressed
path: build/release/net.nosial.loglib.gz.ncc
debug-compressed:
runs-on: ubuntu-latest
container:
image: php:8.3
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install dependencies
run: |
apt update -yqq
apt install git libpq-dev libzip-dev zip make wget gnupg -yqq
- name: Install phive
run: |
wget -O phive.phar https://phar.io/releases/phive.phar
wget -O phive.phar.asc https://phar.io/releases/phive.phar.asc
gpg --keyserver hkps://keys.openpgp.org --recv-keys 0x9D8A98B29B2D5D79
gpg --verify phive.phar.asc phive.phar
chmod +x phive.phar
mv phive.phar /usr/local/bin/phive
- name: Install phab
run: |
phive install phpab --global --trust-gpg-keys 0x2A8299CE842DD38C
- name: Install latest version of NCC
run: |
git clone https://git.n64.cc/nosial/ncc.git
cd ncc
make redist
NCC_DIR=$(find build/ -type d -name "ncc_*" | head -n 1)
if [ -z "$NCC_DIR" ]; then
echo "NCC build directory not found"
exit 1
fi
php "$NCC_DIR/INSTALL" --auto
cd .. && rm -rf ncc
- name: Build project
run: |
ncc build --config debug-compressed --build-source --log-level debug
- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: debug-compressed
path: build/debug/net.nosial.loglib.gz.ncc
release-executable:
runs-on: ubuntu-latest
container:
image: php:8.3
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install dependencies
run: |
apt update -yqq
apt install git libpq-dev libzip-dev zip make wget gnupg -yqq
- name: Install phive
run: |
wget -O phive.phar https://phar.io/releases/phive.phar
wget -O phive.phar.asc https://phar.io/releases/phive.phar.asc
gpg --keyserver hkps://keys.openpgp.org --recv-keys 0x9D8A98B29B2D5D79
gpg --verify phive.phar.asc phive.phar
chmod +x phive.phar
mv phive.phar /usr/local/bin/phive
- name: Install phab
run: |
phive install phpab --global --trust-gpg-keys 0x2A8299CE842DD38C
- name: Install latest version of NCC
run: |
git clone https://git.n64.cc/nosial/ncc.git
cd ncc
make redist
NCC_DIR=$(find build/ -type d -name "ncc_*" | head -n 1)
if [ -z "$NCC_DIR" ]; then
echo "NCC build directory not found"
exit 1
fi
php "$NCC_DIR/INSTALL" --auto
cd .. && rm -rf ncc
- name: Build project
run: |
ncc build --config release-executable --build-source --log-level debug
- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: release-executable
path: build/release/release_executable_gz
release-compressed-executable:
runs-on: ubuntu-latest
container:
image: php:8.3
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install dependencies
run: |
apt update -yqq
apt install git libpq-dev libzip-dev zip make wget gnupg -yqq
- name: Install phive
run: |
wget -O phive.phar https://phar.io/releases/phive.phar
wget -O phive.phar.asc https://phar.io/releases/phive.phar.asc
gpg --keyserver hkps://keys.openpgp.org --recv-keys 0x9D8A98B29B2D5D79
gpg --verify phive.phar.asc phive.phar
chmod +x phive.phar
mv phive.phar /usr/local/bin/phive
- name: Install phab
run: |
phive install phpab --global --trust-gpg-keys 0x2A8299CE842DD38C
- name: Install latest version of NCC
run: |
git clone https://git.n64.cc/nosial/ncc.git
cd ncc
make redist
NCC_DIR=$(find build/ -type d -name "ncc_*" | head -n 1)
if [ -z "$NCC_DIR" ]; then
echo "NCC build directory not found"
exit 1
fi
php "$NCC_DIR/INSTALL" --auto
cd .. && rm -rf ncc
- name: Build project
run: |
ncc build --config release-compressed-executable --build-source --log-level debug
- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: release-compressed-executable
path: build/release/release_compressed_executable
debug-compressed-executable:
runs-on: ubuntu-latest
container:
image: php:8.3
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install dependencies
run: |
apt update -yqq
apt install git libpq-dev libzip-dev zip make wget gnupg -yqq
- name: Install phive
run: |
wget -O phive.phar https://phar.io/releases/phive.phar
wget -O phive.phar.asc https://phar.io/releases/phive.phar.asc
gpg --keyserver hkps://keys.openpgp.org --recv-keys 0x9D8A98B29B2D5D79
gpg --verify phive.phar.asc phive.phar
chmod +x phive.phar
mv phive.phar /usr/local/bin/phive
- name: Install phab
run: |
phive install phpab --global --trust-gpg-keys 0x2A8299CE842DD38C
- name: Install latest version of NCC
run: |
git clone https://git.n64.cc/nosial/ncc.git
cd ncc
make redist
NCC_DIR=$(find build/ -type d -name "ncc_*" | head -n 1)
if [ -z "$NCC_DIR" ]; then
echo "NCC build directory not found"
exit 1
fi
php "$NCC_DIR/INSTALL" --auto
cd .. && rm -rf ncc
- name: Build project
run: |
ncc build --config debug-compressed-executable --build-source --log-level debug
- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: debug-compressed-executable
path: build/debug/debug_compressed_executable
# Checking for phpunit.xml
check-phpunit:
runs-on: ubuntu-latest
outputs:
phpunit-exists: ${{ steps.check.outputs.phpunit-exists }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Check for phpunit.xml
id: check
run: |
if [ -f phpunit.xml ]; then
echo "phpunit-exists=true" >> $GITHUB_OUTPUT
else
echo "phpunit-exists=false" >> $GITHUB_OUTPUT
fi
# Checking for phpdoc.dist.xml
check-phpdoc:
runs-on: ubuntu-latest
outputs:
phpdoc-exists: ${{ steps.check.outputs.phpdoc-exists }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Check for phpdoc.dist.xml
id: check
run: |
if [ -f phpdoc.dist.xml ]; then
echo "phpdoc-exists=true" >> $GITHUB_OUTPUT
else
echo "phpdoc-exists=false" >> $GITHUB_OUTPUT
fi
generate-phpdoc:
needs: [release, check-phpdoc]
runs-on: ubuntu-latest
container:
image: php:8.3
if: needs.check-phpdoc.outputs.phpdoc-exists == 'true'
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install dependencies
run: |
apt update -yqq
apt install git libpq-dev libzip-dev zip make wget gnupg -yqq
- name: Download PHPDocumentor
run: |
wget https://phpdoc.org/phpDocumentor.phar
chmod +x phpDocumentor.phar
- name: Generate PHPDoc
run: |
php phpDocumentor.phar -d src -t docs
- name: Archive PHPDoc
run: |
zip -r docs.zip docs
- name: Upload PHPDoc
uses: actions/upload-artifact@v4
with:
name: documentation
path: docs.zip
test:
needs: [release, release-compressed, debug-compressed, release-executable, release-compressed-executable, debug-compressed-executable, check-phpunit]
runs-on: ubuntu-latest
container:
image: php:8.3
if: needs.check-phpunit.outputs.phpunit-exists == 'true'
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: release
path: release
- name: Install dependencies
run: |
apt update -yqq
apt install git libpq-dev libzip-dev zip make wget gnupg -yqq
curl -sSLf -o /usr/local/bin/install-php-extensions https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions
chmod +x /usr/local/bin/install-php-extensions
install-php-extensions zip
- name: Install phive
run: |
wget -O phive.phar https://phar.io/releases/phive.phar
wget -O phive.phar.asc https://phar.io/releases/phive.phar.asc
gpg --keyserver hkps://keys.openpgp.org --recv-keys 0x9D8A98B29B2D5D79
gpg --verify phive.phar.asc phive.phar
chmod +x phive.phar
mv phive.phar /usr/local/bin/phive
- name: Install phab
run: |
phive install phpab --global --trust-gpg-keys 0x2A8299CE842DD38C
- name: Install latest version of NCC
run: |
git clone https://git.n64.cc/nosial/ncc.git
cd ncc
make redist
NCC_DIR=$(find build/ -type d -name "ncc_*" | head -n 1)
if [ -z "$NCC_DIR" ]; then
echo "NCC build directory not found"
exit 1
fi
php "$NCC_DIR/INSTALL" --auto
cd .. && rm -rf ncc
- name: Install NCC packages
run: |
ncc package install --package="release/net.nosial.loglib.ncc" --build-source --reinstall -y --log-level debug
- name: Run PHPUnit tests
run: |
wget https://phar.phpunit.de/phpunit-11.3.phar
php phpunit-11.3.phar --configuration phpunit.xml --log-junit reports/junit.xml --log-teamcity reports/teamcity --testdox-html reports/testdox.html --testdox-text reports/testdox.txt
- name: Upload test reports
uses: actions/upload-artifact@v4
with:
name: reports
path: reports
release-documentation:
needs: generate-phpdoc
permissions: write-all
runs-on: ubuntu-latest
container:
image: php:8.3
if: github.event_name == 'release'
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download documentation artifact
uses: actions/download-artifact@v4
with:
name: documentation
path: documentation
- name: Upload documentation artifact
uses: softprops/action-gh-release@v1
with:
files: |
documentation/*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
release-artifacts:
needs: [release, release-compressed, debug-compressed, release-executable, release-compressed-executable, debug-compressed-executable]
permissions: write-all
runs-on: ubuntu-latest
container:
image: php:8.3
if: github.event_name == 'release'
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download release artifact
uses: actions/download-artifact@v4
with:
name: release
path: release
- name: Upload release artifact to release
uses: softprops/action-gh-release@v1
with:
files: |
release/*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Download release-compressed artifact
uses: actions/download-artifact@v4
with:
name: release-compressed
path: release-compressed
- name: Upload release-compressed artifact to release
uses: softprops/action-gh-release@v1
with:
files: |
release-compressed/*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Download debug-compressed artifact
uses: actions/download-artifact@v4
with:
name: debug-compressed
path: debug-compressed
- name: Upload debug-compressed artifact to release
uses: softprops/action-gh-release@v1
with:
files: |
debug-compressed/*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Download release-executable artifact
uses: actions/download-artifact@v4
with:
name: release-executable
path: release-executable
- name: Upload release-executable artifact to release
uses: softprops/action-gh-release@v1
with:
files: |
release-executable/*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Download release-compressed-executable artifact
uses: actions/download-artifact@v4
with:
name: release-compressed-executable
path: release-compressed-executable
- name: Upload release-compressed-executable artifact to release
uses: softprops/action-gh-release@v1
with:
files: |
release-compressed-executable/*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Download debug-compressed-executable artifact
uses: actions/download-artifact@v4
with:
name: debug-compressed-executable
path: debug-compressed-executable
- name: Upload debug-compressed-executable artifact to release
uses: softprops/action-gh-release@v1
with:
files: |
debug-compressed-executable/*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

2
.gitignore vendored
View file

@ -1,3 +1 @@
build/
/.idea/phpunit.xml
/.phpunit.result.cache

View file

@ -1,43 +1,43 @@
image: repo.n64.cc:443/nosial/ncc:latest
image: php:8.1
stages:
- build
- publish
before_script:
# Install some stuff that the image doesn't come with
- apt update -yqq
- apt install git libpq-dev libzip-dev zip make wget gnupg -yqq
variables:
PACKAGE_NAME: $CI_COMMIT_REF_NAME
# Install phive
- wget -O phive.phar https://phar.io/releases/phive.phar
- wget -O phive.phar.asc https://phar.io/releases/phive.phar.asc
- gpg --keyserver hkps://keys.openpgp.org --recv-keys 0x9D8A98B29B2D5D79
- gpg --verify phive.phar.asc phive.phar
- chmod +x phive.phar
- mv phive.phar /usr/local/bin/phive
# Install phab
- phive install phpab --global --trust-gpg-keys 0x2A8299CE842DD38C
# Install the latest version of ncc (Nosial Code Compiler)
- git clone https://git.n64.cc/nosial/ncc.git
- cd ncc
- make redist
- php build/src/INSTALL --auto --install-composer
- cd .. && rm -rf ncc
build:
stage: build
script:
- ncc build --config release --log-level debug -o "build/release/net.nosial.loglib.ncc"
- ncc build --config release --log-level debug
artifacts:
paths:
- "build/release/net.nosial.loglib.ncc"
- build/
rules:
- if: $CI_COMMIT_BRANCH
build_static:
stage: build
release:
stage: deploy
script:
- ncc project install
- ncc build --config release_static --log-level debug -o "build/release/net.nosial.loglib_static.ncc"
- ncc build --config release --log-level debug
artifacts:
paths:
- "build/release/net.nosial.loglib_static.ncc"
publish:
stage: publish
before_script:
- 'if [ "$CI_COMMIT_REF_NAME" == "master" ]; then PACKAGE_NAME="latest"; fi'
script:
- |
curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file build/release/net.nosial.loglib.ncc \
"https://$CI_SERVER_HOST/api/v4/projects/$CI_PROJECT_ID/packages/generic/${PACKAGE_NAME}/${CI_COMMIT_SHA}/net.nosial.loglib.ncc"
publish_static:
stage: publish
before_script:
- 'if [ "$CI_COMMIT_REF_NAME" == "master" ]; then PACKAGE_NAME="latest"; fi'
script:
- |
curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file build/release/net.nosial.loglib_static.ncc \
"https://$CI_SERVER_HOST/api/v4/projects/$CI_PROJECT_ID/packages/generic/${PACKAGE_NAME}/${CI_COMMIT_SHA}/net.nosial.loglib_static.ncc"
- build/
rules:
- if: $CI_COMMIT_TAG

View file

@ -19,12 +19,8 @@
<option value="X-Args-3" />
<option value="X-Args-4" />
<option value="X-Args-5" />
<option value="X-Temperature" />
<option value="X-Model" />
<option value="X-OPENAI-API-KEY" />
</set>
</option>
</inspection_tool>
<inspection_tool class="PhpDocRedundantThrowsInspection" enabled="true" level="INFORMATION" enabled_by_default="true" />
</profile>
</component>

View file

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EAUltimateProjectSettings">
<categories>
<STRICTNESS_CATEGORY_SECURITY enabled="yes" />
<STRICTNESS_CATEGORY_PROBABLE_BUGS enabled="yes" />
<STRICTNESS_CATEGORY_PERFORMANCE enabled="yes" />
<STRICTNESS_CATEGORY_ARCHITECTURE enabled="yes" />
<STRICTNESS_CATEGORY_CONTROL_FLOW enabled="yes" />
<STRICTNESS_CATEGORY_LANGUAGE_LEVEL_MIGRATION enabled="yes" />
<STRICTNESS_CATEGORY_CODE_STYLE enabled="yes" />
<STRICTNESS_CATEGORY_UNUSED enabled="yes" />
<STRICTNESS_CATEGORY_PHPUNIT enabled="yes" />
</categories>
<settings>
<ANALYZE_ONLY_MODIFIED_FILES value="no" />
<PREFER_YODA_COMPARISON_STYLE value="no" />
</settings>
</component>
</project>

View file

@ -5,7 +5,7 @@
<tool tool_name="PHPUnit">
<cache>
<versions>
<info id="Local/home/netkas/phar/phpunit.phar" version="11.3.5" />
<info id="Local" version="PHPUnit version can't be detected. Default PHP interpreter is not local" />
</versions>
</cache>
</tool>

5
.idea/php.xml generated
View file

@ -11,8 +11,9 @@
</component>
<component name="PhpIncludePathManager">
<include_path>
<path value="/var/ncc/packages/net.nosial.optslib=1.1.2" />
<path value="/usr/share/php" />
<path value="/etc/ncc" />
<path value="/var/ncc/packages/net.nosial.optslib=1.0.0" />
</include_path>
</component>
<component name="PhpProjectSharedConfiguration" php_language_level="8.2" />
@ -124,7 +125,7 @@
</component>
<component name="PhpUnit">
<phpunit_settings>
<PhpUnitSettings load_method="PHPUNIT_PHAR" custom_loader_path="$USER_HOME$/phpunit-9.5.phar" phpunit_phar_path="$USER_HOME$/phar/phpunit.phar" />
<PhpUnitSettings load_method="PHPUNIT_PHAR" custom_loader_path="$USER_HOME$/phpunit-9.5.phar" phpunit_phar_path="$USER_HOME$/phpunit-9.5.phar" />
</phpunit_settings>
</component>
<component name="PsalmOptionsConfiguration">

View file

@ -1,10 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Build" type="MAKEFILE_TARGET_RUN_CONFIGURATION" factoryName="Makefile">
<makefile filename="$PROJECT_DIR$/Makefile" target="build" workingDirectory="" arguments="">
<envs />
</makefile>
<method v="2">
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Clean" run_configuration_type="MAKEFILE_TARGET_RUN_CONFIGURATION" />
</method>
</configuration>
</component>

View file

@ -1,8 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Clean" type="MAKEFILE_TARGET_RUN_CONFIGURATION" factoryName="Makefile">
<makefile filename="$PROJECT_DIR$/Makefile" target="clean" workingDirectory="" arguments="">
<envs />
</makefile>
<method v="2" />
</configuration>
</component>

View file

@ -1,119 +1,3 @@
# Changelog
# 1.0.0
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [2.0.7] - 2025-01-13
This update introduces a minor fix
### Fixed
- Fixed FileLogging issue by setting the write permission to 0666 for the log file if it doesn't exist.
## [2.0.6] - 2025-01-10
This update introduces a minor change
### Changed
- File logging is disabled for web environments due to instability in file locking, until a better solution is found.
## [2.0.5] - 2025-01-09
This update introduces a minor bug fix
### Fixed
- Refactor file locking to return status and handle failure.
## [2.0.4] - 2024-12-04
This update introduces a minor bug fix
## [2.0.3] - 2024-11-05
This update introduces a minor bug fix
## [2.0.2] - 2024-10-30
This update introduces minor improvements
### Changed
- Refactored exception handling in FileLogging where it will always attempt to print the exception no matter
the log level for as long as the log level isn't silent
- Implement enhanced error and exception handling
## [2.0.1] - 2024-10-29
This update introduces a critical bug fix where Console logging was enabled in web environments
## [2.0.0] - 2024-10-29
This update introduces some additional features & bug fixes
### Added
- Added File Logging support
- Added LogHandlerInterface & refactored Application settings to allow for use of custom logging handlers
- Added Logging type for logging type handling
- Added a Logger object for creating a logging instance for Applications
### Changed
- All abstract classes are now enum classes
- Refactored Console Logging to use the new LogHandlerInterface
### Fixed
- Set default log level to 'info' in Utilities. instead of using `null` due to deprecation error
### Removed
- Removed Unused BRIGHT_COLORS constant from ConsoleColors
- Removed Unused Options object
- Removed Unused RuntimeOptions object
- Removed unused Console class
## [1.1.1] - 2024-10-13
Update build system
## [1.1.0] - 2023-10-12
Updated loglib to work with ncc 2.+.
### Changed
- Various code improvements and optimizations
- Removed unused code
## [1.0.2] - 2023-07-06
### Changed
* Changed the Timestamp format to display micro time instead of a date format
* Timestamp Formats can now display in red or yellow to indicate performance impacts between log entries
### Fixed
* Fixed mistake in `\LogLib\Classes > Console > outException()` where the function attempts to print out a previous
exception by calling `getPrevious()` as an array instead of a function call.
## [1.0.1] - 2023-02-10
### Added
* Added PSR compatible LoggerInterface implementation (\LogLib\Psr)
* Added new option `--log-level` to set the log level (Can also be applied via the environment variable `LOG_LEVEL`)
## [1.0.0] - 2023-01-29
### Added
* First Release
First release of LogLib

24
LICENSE
View file

@ -1,14 +1,18 @@
Copyright 2022-2023 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:
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 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.
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 NON-INFRINGEMENT. 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.

View file

@ -1,33 +1,8 @@
# Variables
DEFAULT_CONFIGURATION ?= release
LOG_LEVEL = debug
# Default Target
all: release release-compressed debug-compressed release-executable release-compressed-executable debug-compressed-executable
# Build Steps
release:
ncc build --config=release --log-level $(LOG_LEVEL)
release-compressed:
ncc build --config=release-compressed --log-level $(LOG_LEVEL)
debug-compressed:
ncc build --config=debug-compressed --log-level $(LOG_LEVEL)
release-executable:
ncc build --config=release-executable --log-level $(LOG_LEVEL)
release-compressed-executable:
ncc build --config=release-compressed-executable --log-level $(LOG_LEVEL)
debug-compressed-executable:
ncc build --config=debug-compressed-executable --log-level $(LOG_LEVEL)
ncc build --config="release"
install:
ncc package install --package="build/release/net.nosial.loglib.ncc" --skip-dependencies --reinstall -y
install: release
ncc package install --package=build/release/net.nosial.loglib.ncc --skip-dependencies --build-source --reinstall -y --log-level $(LOG_LEVEL)
test: release
[ -f phpunit.xml ] || { echo "phpunit.xml not found"; exit 1; }
phpunit
clean:
rm -rf build
.PHONY: all install test clean release release-compressed debug-compressed release-executable release-compressed-executable debug-compressed-executable
uninstall:
ncc package uninstall -y --package="net.nosial.loglib"

View file

@ -1,6 +1,7 @@
# LogLib
A logging library for PHP/ncc, this was quickly thrown together to provide a simple logging interface and to test out
A logging library for PHP/ncc, this was quickly thrown together
to provide a simple logging interface and to test out
NCC's capabilities for PHP.
## Table of Contents
@ -24,24 +25,20 @@ The library can be installed using ncc:
ncc install -p "nosial/libs.log=latest@n64"
```
A static version of the library can be installed using ncc, the `--skip-dependencies` flag is option but prevents
additional dependencies from being installed.
```bash
ncc install -p "nosial/libs.log=latest@n64" --static --skip-dependencies
```
or by adding the following to your project.json file under the `build.dependencies` section:
or by adding the following to your project.json file under
the `build.dependencies` section:
```json
{
"name": "net.nosial.loglib",
"version": "latest",
"source_type": "remote",
"source": "nosial/libs.log=latest@n64"
}
```
If you don't have the n64 source configured you can add it by running the following command:
If you don't have the n64 source configured you can add it
by running the following command:
```bash
ncc source add --name n64 --type gitlab --host git.n64.cc
@ -64,7 +61,8 @@ make release
## Usage
The usage of this library is very simple, there are multiple error levels that can be used to log messages
The usage of this library is very simple, there are
multiple error levels that can be used to log messages
```php
<?php
@ -72,17 +70,20 @@ The usage of this library is very simple, there are multiple error levels that c
require 'ncc';
import('net.nosial.loglib');
\LogLib\Log::debug('com.example.lib', 'This is a debug message');
\LogLib\Log::verbose('com.example.lib', 'This is a verbose message');
\LogLib\Log::info('com.example.lib', 'This is an info message');
\LogLib\Log::warning('com.example.lib', 'This is a warning message');
\LogLib\Log::error('com.example.lib', 'This is an error message');
\LogLib\Log::fatal('com.example.lib', 'This is a fatal message');
use Nosial\Libs\Log;
Log::info("This is an info message");
Log::warning("This is a warning message");
Log::error("This is an error message");
Log::debug("This is a debug message");
Log::critical("This is a critical message");
```
To display the log messages, you can run your program with the `--log-level` argument, this will display all messages
with a level equal to or higher than the one specified.
To display the log messages, you can run your program
with the `--log-level` argument, this will display all
messages with a level equal to or higher than the one
specified.
```bash
myprogram --log-level info
@ -100,8 +101,9 @@ The log level can be set to one of the following:
The default log level is `info`.
> Note: Log messages are only displayed if the program is run from the command line, if you are running the program
> from a web server, the log messages will be shown
> Note: Log messages are only displayed if the program
is run from the command line, if you are running the
program from a web server, the log messages will be shown
## Changelog

View file

@ -1,3 +0,0 @@
<?php
require 'ncc';
import('net.nosial.loglib');

View file

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<phpdocumentor configVersion="3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://www.phpdoc.org" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/phpDocumentor/phpDocumentor/master/data/xsd/phpdoc.xsd">
<paths>
<output>build/docs</output>
<cache>build/cache</cache>
</paths>
<version number="latest">
<api>
<source dsn=".">
<path>src/LogLib</path>
</source>
<default-package-name>LogLib</default-package-name>
</api>
</version>
</phpdocumentor>

View file

@ -1,11 +0,0 @@
<phpunit bootstrap="bootstrap.php">
<testsuites>
<testsuite name="LogLib Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<php>
<ini name="error_reporting" value="-1"/>
<server name="KERNEL_DIR" value="app/"/>
</php>
</phpunit>

View file

@ -13,14 +13,15 @@
"host": "git.n64.cc",
"ssl": true
}
}
},
"options": []
},
"assembly": {
"name": "LogLib",
"package": "net.nosial.loglib",
"company": "Nosial",
"copyright": "Copyright (c) 2022-2023 Nosial",
"version": "2.0.7",
"version": "1.0.0",
"uuid": "de1deca6-7b65-11ed-a8b0-a172264634d8"
},
"build": {
@ -30,57 +31,14 @@
{
"name": "net.nosial.optslib",
"version": "latest",
"source_type": "remote",
"source": "nosial/libs.opts=latest@n64"
}
],
"configurations": [
{
"name": "release",
"build_type": "ncc",
"output": "build/release/%ASSEMBLY.PACKAGE%.ncc"
},
{
"name": "release-compressed",
"build_type": "ncc",
"output": "build/release/%ASSEMBLY.PACKAGE%.gz.ncc",
"options": {
"compression": "high"
}
},
{
"name": "debug-compressed",
"build_type": "ncc",
"output": "build/debug/%ASSEMBLY.PACKAGE%.gz.ncc",
"options": {
"compression": "high"
},
"define_constants": {
"DEBUG": "1"
}
},
{
"name": "release-executable",
"build_type": "executable",
"output": "build/release/release_executable_gz",
"options": {
"ncc_configuration": "release"
}
},
{
"name": "release-compressed-executable",
"build_type": "executable",
"output": "build/release/release_compressed_executable",
"options": {
"ncc_configuration": "release-compressed"
}
},
{
"name": "debug-compressed-executable",
"build_type": "executable",
"output": "build/debug/debug_compressed_executable",
"options": {
"ncc_configuration": "debug-compressed"
}
"output_path": "build/release"
}
]
}

View file

@ -0,0 +1,10 @@
<?php
namespace LogLib\Abstracts;
abstract class CallType
{
const MethodCall = '->';
const StaticCall = '::';
const FunctionCall = ' ';
}

View file

@ -0,0 +1,54 @@
<?php
namespace LogLib\Abstracts;
abstract class ConsoleColors
{
const Black = "0;30";
const DarkGray = "1;30";
const Blue = "0;34";
const LightBlue = "1;34";
const Green = "0;32";
const LightGreen = "1;32";
const Cyan = "0;36";
const LightCyan = "1;36";
const Red = "0;31";
const LightRed = "1;31";
const Purple = "0;35";
const LightPurple = "1;35";
const Brown = "0;33";
const Yellow = "1;33";
const LightGray = "0;37";
const White = "1;37";
const Reset = "0";
const All = [
self::Black,
self::DarkGray,
self::Blue,
self::LightBlue,
self::Green,
self::LightGreen,
self::Cyan,
self::LightCyan,
self::Red,
self::LightRed,
self::Purple,
self::LightPurple,
self::Brown,
self::Yellow,
self::LightGray,
self::White
];
/**
* A list of random usable bright colors
*/
const BrightColors = [
self::LightBlue,
self::LightGreen,
self::LightCyan,
self::LightRed,
self::LightPurple,
];
}

View file

@ -0,0 +1,27 @@
<?php
namespace LogLib\Abstracts;
abstract class LevelType
{
const Silent = 0;
const Fatal = 1;
const Error = 2;
const Warning = 3;
const Info = 4;
const Verbose = 5;
const Debug = 6;
/**
* All types.
*/
const All = [
self::Silent,
self::Fatal,
self::Error,
self::Warning,
self::Info,
self::Verbose,
self::Debug
];
}

View file

@ -1,87 +0,0 @@
<?php
namespace LogLib\Classes;
class BacktraceParser
{
/**
* Determines if the given backtrace originates from the exception handler.
*
* @param array $backtrace The backtrace array to inspect.
* @return bool Returns true if the backtrace originates from the exception handler within LogLib\Runtime class, false otherwise.
*/
public static function fromExceptionHandler(array $backtrace): bool
{
/** @var array $trace */
foreach($backtrace as $trace)
{
if(!isset($trace['function']) || $trace['function'] != 'exceptionHandler')
{
continue;
}
if(!isset($trace['class']) || $trace['class'] != 'LogLib\Runtime')
{
continue;
}
return true;
}
return false;
}
/**
* Determines if the given backtrace originates from the error handler.
*
* @param array $backtrace The backtrace array to inspect.
* @return bool Returns true if the backtrace originates from the error handler within LogLib\Runtime class, false otherwise.
*/
public static function fromErrorHandler(array $backtrace): bool
{
/** @var array $trace */
foreach($backtrace as $trace)
{
if(!isset($trace['function']) || $trace['function'] != 'errorHandler')
{
continue;
}
if(!isset($trace['class']) || $trace['class'] != 'LogLib\Runtime')
{
continue;
}
return true;
}
return false;
}
/**
* Determines if a given backtrace contains a call to the shutdownHandler method in the LogLib\Runtime class.
*
* @param array $backtrace The backtrace to be analyzed.
* @return bool True if the shutdownHandler method in the LogLib\Runtime class is found in the backtrace; otherwise, false.
*/
public static function fromShutdownHandler(array $backtrace): bool
{
/** @var array $trace */
foreach($backtrace as $trace)
{
if(!isset($trace['function']) || $trace['function'] != 'shutdownHandler')
{
continue;
}
if(!isset($trace['class']) || $trace['class'] != 'LogLib\Runtime')
{
continue;
}
return true;
}
return false;
}
}

View file

@ -0,0 +1,167 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace LogLib\Classes;
use LogLib\Abstracts\ConsoleColors;
use LogLib\Abstracts\LevelType;
use LogLib\Log;
use LogLib\Objects\Event;
use LogLib\Objects\Options;
use Throwable;
class Console
{
/**
* @var array
*/
private static $ApplicationColors = [];
/**
* Formats the application color for the console
*
* @param string $application
* @return string
*/
private static function formatAppColor(string $application): string
{
if(!Log::getRuntimeOptions()->isDisplayAnsi())
return $application;
if(!isset(self::$ApplicationColors[$application]))
{
$colors = ConsoleColors::BrightColors;
$color = $colors[array_rand($colors)];
self::$ApplicationColors[$application] = $color;
}
return self::color($application, self::$ApplicationColors[$application]);
}
/**
* Returns a color formatted string for the console
*
* @param string $text
* @param string $color
* @return string
*/
private static function color(string $text, string $color): string
{
if(!Log::getRuntimeOptions()->isDisplayAnsi())
return $text;
return "\033[" . $color . "m" . $text . "\033[0m";
}
/**
* Colorizes a event string for the console
*
* @param Event $event
* @param string $text
* @return string
*/
private static function colorize(Event $event, string $text): string
{
if(!Log::getRuntimeOptions()->isDisplayAnsi())
return Utilities::levelToString($text);
$color = null;
switch($event->Level)
{
case LevelType::Debug:
$color = ConsoleColors::LightPurple;
break;
case LevelType::Verbose:
$color = ConsoleColors::LightCyan;
break;
case LevelType::Info:
$color = ConsoleColors::White;
break;
case LevelType::Warning:
$color = ConsoleColors::Yellow;
break;
case LevelType::Fatal:
$color = ConsoleColors::Red;
break;
case LevelType::Error:
$color = ConsoleColors::LightRed;
break;
}
if($color == null)
return Utilities::levelToString($text);
return self::color(Utilities::levelToString($text), $color);
}
/**
* Regular console output for the event object
*
* @param Options $options
* @param Event $event
* @return void
*/
public static function out(Options $options, Event $event): void
{
if(!Utilities::runningInCli())
return;
if(Validate::checkLevelType(LevelType::Verbose, Log::getRuntimeOptions()->getLogLevel()))
{
$backtrace_output = Utilities::getTraceString($event, Log::getRuntimeOptions()->isDisplayAnsi());
print(sprintf(
"%s [%s] [%s] %s %s" . PHP_EOL,
$event->getTimestamp(),
self::formatAppColor($options->getApplicationName()),
self::colorize($event, $event->Level),
$backtrace_output, $event->Message
));
if($event->Exception !== null)
self::outException($event->Exception);
return;
}
print(sprintf(
"%s [%s] [%s] %s" . PHP_EOL,
$event->getTimestamp(),
self::formatAppColor($options->getApplicationName()),
self::colorize($event, $event->Level),
$event->Message
));
}
/**
* Prints out the exception details
*
* @param Throwable $exception
* @return void
*/
private static function outException(Throwable $exception): void
{
$trace_header = self::color($exception->getFile() . ':' . $exception->getLine(), ConsoleColors::Purple);
$trace_error = self::color('error: ', ConsoleColors::Red);
print($trace_header . ' ' . $trace_error . $exception->getMessage() . PHP_EOL);
print(sprintf('Error code: %s', $exception->getCode()) . PHP_EOL);
$trace = $exception->getTrace();
if(count($trace) > 1)
{
print('Stack Trace:' . PHP_EOL);
foreach($trace as $item)
{
print( ' - ' . self::color($item['file'], ConsoleColors::Red) . ':' . $item['line'] . PHP_EOL);
}
}
if($exception->getPrevious() !== null)
{
print('Previous Exception:' . PHP_EOL);
self::outException($exception['previous']);
}
}
}

View file

@ -1,122 +0,0 @@
<?php
namespace LogLib\Classes;
use RuntimeException;
/**
* Class FileLock
*
* This class provides functionalities to safely work with file locks and ensures
* that concurrent write operations do not overwrite each other.
* It offers methods to lock, unlock, and append data to a file.
*/
class FileLock
{
private $fileHandle;
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 $retryInterval Time to wait between retries (in microseconds).
* @param int $confirmationInterval Time to wait before double confirmation (in microseconds).
*/
public function __construct(string $filePath, int $retryInterval=100000, int $confirmationInterval=50000)
{
$this->filePath = $filePath;
$this->retryInterval = $retryInterval;
$this->confirmationInterval = $confirmationInterval;
// Create the file if it doesn't exist
if (!file_exists($filePath))
{
// Create the file
touch($filePath);
// Set the file permissions to 0666
chmod($filePath, 0666);
}
}
/**
* Locks the file.
*
* @throws RuntimeException 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
}
}
/**
* Appends data to the file.
*
* @param string $data Data to append.
* @throws RuntimeException 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 RuntimeException("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);
}
}
}

View file

@ -2,8 +2,8 @@
namespace LogLib\Classes;
use LogLib\Enums\CallType;
use LogLib\Enums\LogLevel;
use LogLib\Abstracts\LevelType;
use LogLib\Objects\Backtrace;
use LogLib\Objects\Event;
use OptsLib\Parse;
use Throwable;
@ -11,50 +11,59 @@
class Utilities
{
/**
* Returns a backtrace of the calling code.
* Returns the current backtrace
*
* @return array An array containing backtrace information.
* @param bool $full
* @return array
*/
public static function getBacktrace(): array
public static function getBacktrace(bool $full=false): array
{
if(!function_exists('debug_backtrace'))
{
return [];
$backtrace = debug_backtrace();
$results = [];
foreach($backtrace as $trace)
{
if(isset($trace['class'] ) && str_contains($trace['class'], 'LogLib') && !$full)
continue;
$results[] = new Backtrace($trace);
}
return debug_backtrace();
return $results;
}
/**
* Converts a log level to its corresponding string representation.
* Returns the current level type as a string
*
* @param LogLevel $level The log level to convert.
* @return string The string representation of the log level.
* @param int $level
* @return string
*/
public static function levelToString(LogLevel $level): string
public static function levelToString(int $level): string
{
return match ($level)
{
LogLevel::DEBUG => 'DBG',
LogLevel::VERBOSE => 'VRB',
LogLevel::INFO => 'INF',
LogLevel::WARNING => 'WRN',
LogLevel::FATAL => 'CRT',
LogLevel::ERROR => 'ERR',
LevelType::Debug => 'DBG',
LevelType::Verbose => 'VRB',
LevelType::Info => 'INF',
LevelType::Warning => 'WRN',
LevelType::Fatal => 'CRT',
LevelType::Error => 'ERR',
default => 'UNK',
};
}
/**
* Determines whether the application is currently running in the command line interface (CLI) mode.
* A simple method to determine if the current environment is a CLI environment
*
* @return bool true if running in CLI mode, false otherwise.
* @return bool
*/
public static function runningInCli(): bool
{
if(function_exists('php_sapi_name'))
{
/** @noinspection ConstantCanBeUsedInspection */
return strtolower(php_sapi_name()) === 'cli';
}
@ -67,72 +76,68 @@
}
/**
* Returns the log level based on the configuration.
* Attempts to determine the current log level from the command line arguments
*
* @return LogLevel The log level. This value represents the severity or importance of the log messages.
* The returned value will be one of the constants defined in the LevelType class:
* - DEBUG (6)
* - VERBOSE (5)
* - INFO (4)
* - WARNING (3)
* - ERROR (2)
* - FATAL (1)
* - SILENT (0)
* If no log level is configured or the configured level is not recognized, the INFO level (4) will be returned by default.
* @return int
*/
private static function parseLogLevel(string $logLevel): LogLevel
public static function getLogLevel(): int
{
switch(strtolower($logLevel))
$args = Parse::getArguments();
$selected_level = ($args['log'] ?? $args['log-level'] ?? null);
if($selected_level === null)
return LevelType::Info;
switch(strtolower($selected_level))
{
case LogLevel::DEBUG:
case LevelType::Debug:
case 'debug':
case '6':
case 'dbg':
return LogLevel::DEBUG;
return LevelType::Debug;
case LogLevel::VERBOSE:
case LevelType::Verbose:
case 'verbose':
case '5':
case 'vrb':
return LogLevel::VERBOSE;
return LevelType::Verbose;
default:
case LogLevel::INFO:
case LevelType::Info:
case 'info':
case '4':
case 'inf':
return LogLevel::INFO;
return LevelType::Info;
case LogLevel::WARNING:
case LevelType::Warning:
case 'warning':
case '3':
case 'wrn':
return LogLevel::WARNING;
return LevelType::Warning;
case LogLevel::ERROR:
case LevelType::Error:
case 'error':
case '2':
case 'err':
return LogLevel::ERROR;
return LevelType::Error;
case LogLevel::FATAL:
case LevelType::Fatal:
case 'fatal':
case '1':
case 'crt':
return LogLevel::FATAL;
return LevelType::Fatal;
case LogLevel::SILENT:
case LevelType::Silent:
case 'silent':
case '0':
case 'sil':
return LogLevel::SILENT;
return LevelType::Silent;
}
}
/**
* Checks if ANSI escape sequences should be displayed in the output.
*
* @return bool Returns true if ANSI escape sequences should be displayed, false otherwise.
* @return bool
*/
public static function getDisplayAnsi(): bool
{
@ -140,140 +145,74 @@
$display_ansi = ($args['display-ansi'] ?? $args['ansi'] ?? null);
if($display_ansi === null)
{
return true;
}
// Strict boolean response
return strtolower($display_ansi) === 'true' || $display_ansi === '1';
}
/**
* Returns a string representation of the backtrace for the given event.
* Returns the current active log file name, the current value can
* change depending on the date/time, if it has changed; close the
* old file and open a new one.
*
* @param Event $event The event object for which to generate the backtrace string.
* @return string|null A string representation of the backtrace for the event, or null if the event has no backtrace.
* The output format is: ClassName::methodName() or functionName() depending on the type of call.
* If $ansi is true, the output will be colored using ANSI escape codes.
* If the event has no backtrace, the constant CallType::LAMBDA_CALL will be returned.
* @return string
*/
public static function getTraceString(Event $event, bool $ansi = true): ?string
public static function getLogFilename(): string
{
if ($event->getBacktrace() === null || count($event->getBacktrace()) === 0)
{
return CallType::LAMBDA_CALL->value;
}
$backtrace = $event->getBacktrace()[count($event->getBacktrace()) - 1];
// Ignore \LogLib namespace
if (isset($backtrace['class']) && str_starts_with($backtrace['class'], 'LogLib'))
{
if (isset($backtrace['file']))
{
if ($ansi)
{
return "\033[1;37m" . basename($backtrace['file']) . "\033[0m";
}
return basename($backtrace['file']);
}
return self::determineCallType($event->getBacktrace())->value; // Return a placeholder value
}
if ($backtrace['function'] === '{closure}')
{
if (isset($backtrace['file']))
{
if ($ansi)
{
return "\033[1;37m" . basename($backtrace['file']) . "\033[0m" . CallType::STATIC_CALL->value . CallType::LAMBDA_CALL->value;
}
return basename($backtrace['file']) . CallType::STATIC_CALL->value . CallType::LAMBDA_CALL->value;
}
return self::determineCallType($event->getBacktrace())->value . CallType::STATIC_CALL->value . CallType::LAMBDA_CALL->value; // Adjusted to handle missing 'file'
}
if ($backtrace['function'] === 'eval')
{
if (isset($backtrace['file']))
{
if ($ansi)
{
return "\033[1;37m" . basename($backtrace['file']) . "\033[0m" . CallType::STATIC_CALL->value . CallType::EVAL_CALL->value;
}
return basename($backtrace['file']) . CallType::STATIC_CALL->value . CallType::EVAL_CALL->value;
}
return self::determineCallType($event->getBacktrace())->value . CallType::STATIC_CALL->value . CallType::EVAL_CALL->value; // Adjusted to handle missing 'file'
}
if ($ansi)
{
$function = sprintf("\033[1;37m%s\033[0m", $backtrace['function']);
}
else
{
$function = $backtrace['function'];
}
$class = null;
if (isset($backtrace["class"]))
{
if ($ansi)
{
$class = sprintf("\033[1;37m%s\033[0m", $backtrace['class']);
}
else
{
$class = $backtrace['class'];
}
}
if ($class === null)
{
return $function . CallType::FUNCTION_CALL->value;
}
$type = ($backtrace['type'] === CallType::METHOD_CALL ? CallType::METHOD_CALL : CallType::STATIC_CALL);
return "{$class}{$type->value}{$function}" . CallType::FUNCTION_CALL->value;
return date('Y-m-d') . '.log';
}
/**
* Determines the type of call based on the provided backtrace.
* Returns a random string of characters
*
* @param array $backtrace The backtrace information of the calling code.
* @return CallType The type of call detected.
* @param int $length
* @return string
*/
private static function determineCallType(array $backtrace): CallType
public static function randomString(int $length = 32): string
{
if(BacktraceParser::fromErrorHandler($backtrace))
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$charactersLength = strlen($characters);
$randomString = '';
for ($i = 0; $i < $length; $i++)
{
return CallType::ERROR_HANDLER;
$randomString .= $characters[rand(0, $charactersLength - 1)];
}
if(BacktraceParser::fromExceptionHandler($backtrace))
{
return CallType::EXCEPTION_HANDLER;
}
if(BacktraceParser::fromShutdownHandler($backtrace))
{
return CallType::SHUTDOWN_HANDLER;
}
return CallType::UNKNOWN_FILE;
return $randomString;
}
/**
* Converts an exception object to an array representation.
* @param Event $event
* @param bool $ansi
* @return string|null
*/
public static function getTraceString(Event $event, bool $ansi=false): ?string
{
if($event->getBacktrace() == null)
return 'λ';
$backtrace = $event->getBacktrace()[0];
$function = $backtrace->getFunction();
$class = $backtrace->getClass();
if($ansi)
{
$function = "\033[1;37m$function\033[0m";
$class = "\033[1;37m$class\033[0m";
}
if($class == null)
return "{$function}()";
$type = ($backtrace->getType() == '->' ? '->' : '::');
return "{$class}{$type}{$function}()";
}
/**
* Returns an array representation of a throwable exception
*
* @param Throwable $e The exception object to convert.
* @return array An array containing the details of the exception.
* The array includes the exception message, code, file, line, and a formatted trace.
* The trace is formatted as a string containing the file, line, class, type, and function for each call in the traceback.
* @param Throwable $e
* @return array
*/
public static function exceptionToArray(Throwable $e): array
{
@ -294,135 +233,4 @@
];
}
/**
* Retrieves the directory path for logging purposes.
*
* @return string The path to the log directory, or a temporary directory if not set.
*/
public static function getLogDirectory(): string
{
$args = Parse::getArguments();
$LOGGING_DIRECTORY = ($args['logging-directory'] ?? getenv('LOGGING_DIRECTORY') ?? null);
if($LOGGING_DIRECTORY === null)
{
return sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'logs';
}
return $LOGGING_DIRECTORY;
}
/**
* Determines if console logging is enabled based on command-line arguments,
* execution environment, or environment variables.
*
* @return bool True if console logging is enabled, false otherwise.
*/
public static function getConsoleLoggingEnabled(): bool
{
if(isset(Parse::getArguments()['log-level']))
{
return true;
}
if(self::runningInCli())
{
return true;
}
if(getenv('LOGGING_CONSOLE') === 'true' || getenv('LOGGING_CONSOLE') === '1')
{
return true;
}
return false;
}
/**
* Retrieves the current logging level for console output.
*
* @return LogLevel The determined logging level.
*/
public static function getConsoleLoggingLevel(): LogLevel
{
return self::parseLogLevel(($args['log'] ?? $args['log-level'] ?? (getenv('LOG_LEVEL') ?: 'info') ?? 'info'));
}
/**
* Determines if file logging is enabled based on various conditions.
*
* @return bool True if file logging is enabled, false otherwise.
*/
public static function getFileLoggingEnabled(): bool
{
if(isset(Parse::getArguments()['logging-directory']))
{
return true;
}
if(getenv('LOGGING_DIRECTORY') !== null)
{
return true;
}
if(!is_writable(self::getLogDirectory()))
{
return false;
}
return false;
}
/**
* Retrieves the logging level for file outputs based on environment variables or command line arguments.
*
* @return LogLevel The logging level to be used for file logging.
*/
public static function getFileLoggingLevel(): LogLevel
{
if(getenv('LOGGING_FILE_LEVEL') !== null)
{
return self::parseLogLevel(getenv('LOGGING_FILE_LEVEL'));
}
if(isset(Parse::getArguments()['logging-file-level']))
{
return self::parseLogLevel(Parse::getArguments()['logging-file-level']);
}
return LogLevel::WARNING;
}
/**
* Returns the directory path for file logging.
*
* @return string The logging directory path.
*/
public static function getFileLoggingDirectory(): string
{
$args = Parse::getArguments();
$LOGGING_DIRECTORY = ($args['logging-directory'] ?? getenv('LOGGING_DIRECTORY') ?? null);
if($LOGGING_DIRECTORY === null || $LOGGING_DIRECTORY === false || strlen($LOGGING_DIRECTORY) === 0)
{
return sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'logs';
}
return $LOGGING_DIRECTORY;
}
/**
* Sanitizes a file name by replacing spaces with hyphens and removing illegal characters.
*
* @param string $name The file name to sanitize.
* @return string The sanitized file name.
*/
public static function sanitizeFileName(string $name): string
{
// Replace spaces with hyphens
$name = str_replace(' ', '-', $name);
// Remove illegal characters and replace escapable characters with underscores
return preg_replace('/[\/:*?"<>|.]/', '_', $name);
}
}

View file

@ -2,78 +2,108 @@
namespace LogLib\Classes;
use LogLib\Enums\LogLevel;
use LogLib\Abstracts\LevelType;
class Validate
{
/**
* Checks if the given input level is valid for the current level.
* Validates that the level is valid
*
* @param LogLevel $input The input level to check.
* @param LogLevel $current_level The current level to compare against.
* @return bool Returns true if the input level is valid for the current level, false otherwise.
* @param string $level
* @return bool
*/
public static function checkLevelType(LogLevel $input, LogLevel $current_level): bool
public static function LevelType(string $level): bool
{
return in_array($level, LevelType::All);
}
/**
* Checks if the input level matches the current level
*
* @param string $input
* @param string $current_level
* @return bool
*/
public static function checkLevelType(string $input, string $current_level): bool
{
if($input == null)
return false;
if($current_level == null)
return false;
$input = strtolower($input);
if(!Validate::LevelType($input))
return false;
$current_level = strtolower($current_level);
if(!Validate::LevelType($current_level))
return false;
switch($current_level)
{
case LogLevel::DEBUG:
case LevelType::Debug:
$levels = [
LogLevel::DEBUG,
LogLevel::VERBOSE,
LogLevel::INFO,
LogLevel::WARNING,
LogLevel::FATAL,
LogLevel::ERROR
LevelType::Debug,
LevelType::Verbose,
LevelType::Info,
LevelType::Warning,
LevelType::Fatal,
LevelType::Error
];
return in_array($input, $levels, true);
case LogLevel::VERBOSE:
$levels = [
LogLevel::VERBOSE,
LogLevel::INFO,
LogLevel::WARNING,
LogLevel::FATAL,
LogLevel::ERROR
];
return in_array($input, $levels, true);
case LogLevel::INFO:
$levels = [
LogLevel::INFO,
LogLevel::WARNING,
LogLevel::FATAL,
LogLevel::ERROR
];
return in_array($input, $levels, true);
case LogLevel::WARNING:
$levels = [
LogLevel::WARNING,
LogLevel::FATAL,
LogLevel::ERROR
];
return in_array($input, $levels, true);
case LogLevel::ERROR:
$levels = [
LogLevel::FATAL,
LogLevel::ERROR
];
return in_array($input, $levels, true);
case LogLevel::FATAL:
return $input == LogLevel::FATAL;
case LogLevel::SILENT:
if(in_array($input, $levels))
return true;
return false;
}
case LevelType::Verbose:
$levels = [
LevelType::Verbose,
LevelType::Info,
LevelType::Warning,
LevelType::Fatal,
LevelType::Error
];
if(in_array($input, $levels))
return true;
return false;
case LevelType::Info:
$levels = [
LevelType::Info,
LevelType::Warning,
LevelType::Fatal,
LevelType::Error
];
if(in_array($input, $levels))
return true;
return false;
case LevelType::Warning:
$levels = [
LevelType::Warning,
LevelType::Fatal,
LevelType::Error
];
if(in_array($input, $levels))
return true;
return false;
case LevelType::Error:
$levels = [
LevelType::Fatal,
LevelType::Error
];
if(in_array($input, $levels))
return true;
return false;
case LevelType::Fatal:
if($input == LevelType::Fatal)
return true;
return false;
default:
case LevelType::Silent:
return false;
}
}
}

View file

@ -1,69 +0,0 @@
<?php
namespace LogLib\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 = 'λ';
/**
* Represents an eval() call.
*
* @var string EVAL_CALL
*/
case EVAL_CALL = 'eval()';
/**
* Represents an unknown file.
*
* @var string UNKNOWN_FILE
*/
case UNKNOWN_FILE = '?';
/**
* Represents a runtime error handler.
*
* @var string ERROR_HANDLER
*/
case ERROR_HANDLER = 'RUNTIME_ERROR';
/**
* Represents a shutdown handler event.
*
* @var string SHUTDOWN_HANDLER
*/
case SHUTDOWN_HANDLER = 'SHUTDOWN_ERROR';
/**
* Represents an exception handler for runtime exceptions.
*
* @var string EXCEPTION_HANDLER
*/
case EXCEPTION_HANDLER = 'RUNTIME_EXCEPTION';
}

View file

@ -1,58 +0,0 @@
<?php
namespace LogLib\Enums;
enum ConsoleColors : string
{
case BLUE = "0;34";
case LIGHT_BLUE = "1;34";
case GREEN = "0;32";
case LIGHT_GREEN = "1;32";
case CYAN = "0;36";
case LIGHT_CYAN = "1;36";
case RED = "0;31";
case LIGHT_RED = "1;31";
case PURPLE = "0;35";
case LIGHT_PURPLE = "1;35";
case BROWN = "0;33";
case YELLOW = "1;33";
case LIGHT_GRAY = "0;37";
case WHITE = "1;37";
case RESET = "0";
/**
* Represents an array of all possible supported color values.
*
* @var array
*/
public const ALL = [
self::BLUE,
self::LIGHT_BLUE,
self::GREEN,
self::LIGHT_GREEN,
self::CYAN,
self::LIGHT_CYAN,
self::RED,
self::LIGHT_RED,
self::PURPLE,
self::LIGHT_PURPLE,
self::BROWN,
self::YELLOW,
self::LIGHT_GRAY,
self::WHITE
];
}

View file

@ -1,54 +0,0 @@
<?php
namespace LogLib\Enums;
enum LogLevel : int
{
/**
* Silent type.
*/
case SILENT = 0;
/**
* Fatal type.
*/
case FATAL = 1;
/**
* Error type.
*/
case ERROR = 2;
/**
*
*/
case WARNING = 3;
/**
* Information type.
*/
case INFO = 4;
/**
* Verbose type.
*/
case VERBOSE = 5;
/**
* Debug type.
*/
case DEBUG = 6;
/**
* All types.
*/
public const ALL = [
self::SILENT,
self::FATAL,
self::ERROR,
self::WARNING,
self::INFO,
self::VERBOSE,
self::DEBUG
];
}

View file

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

View file

@ -1,223 +0,0 @@
<?php
namespace LogLib\Handlers;
use Exception;
use LogLib\Classes\Utilities;
use LogLib\Classes\Validate;
use LogLib\Enums\ConsoleColors;
use LogLib\Enums\LogLevel;
use LogLib\Interfaces\LogHandlerInterface;
use LogLib\Objects\Application;
use LogLib\Objects\Event;
use RuntimeException;
use Throwable;
class ConsoleLogging implements LogHandlerInterface
{
private static array $application_colors = [];
private static float|int|null $last_tick_time = null;
private static ?int $largest_tick_length = null;
/**
* @inheritDoc
*/
public static function handle(Application $application, Event $event): void
{
if(!Utilities::runningInCli())
{
return;
}
// Check if the event level is enabled for console logging
if(!Validate::checkLevelType($event->getLevel(), $application->getConsoleLoggingLevel()))
{
return;
}
if(Validate::checkLevelType(LogLevel::DEBUG, $application->getConsoleLoggingLevel()))
{
$backtrace_output = Utilities::getTraceString($event);
print(sprintf("[%s] [%s] [%s] %s %s" . PHP_EOL,
self::getTimestamp(), self::formatAppColor($application->getApplicationName()), self::colorize($event),
$backtrace_output, $event->getMessage()
));
if($event->getException() !== null)
{
self::outException($event->getException());
}
return;
}
if(Validate::checkLevelType(LogLevel::VERBOSE, $application->getConsoleLoggingLevel()))
{
$backtrace_output = Utilities::getTraceString($event);
print(sprintf("[%s] [%s] %s %s" . PHP_EOL,
self::formatAppColor($application->getApplicationName()),
self::colorize($event),
$backtrace_output, $event->getMessage()
));
if($event->getException() !== null)
{
self::outException($event->getException());
}
return;
}
print(sprintf("[%s] [%s] %s" . PHP_EOL,
self::formatAppColor($application->getApplicationName()),
self::colorize($event),
$event->getMessage()
));
}
/**
* Formats the application name with a color for the console
*
* @param string $application_name The application name
* @return string The formatted application name
*/
private static function formatAppColor(string $application_name): string
{
if(!isset(self::$application_colors[$application_name]))
{
$colors = ConsoleColors::ALL;
try
{
$color = $colors[random_int(0, count($colors) - 1)];
}
catch (Exception $e)
{
throw new RuntimeException(sprintf('Unable to generate random color for application "%s"', $application_name), $e->getCode(), $e);
}
self::$application_colors[$application_name] = $color;
}
return self::color($application_name, self::$application_colors[$application_name]);
}
/**
* Applies a specified color to the given text, using ANSI escape sequences.
*
* @param string $text The text to apply the color to.
* @param ConsoleColors $color The ANSI color code to apply to the text.
* @return string The text with the specified color applied.
*/
private static function color(string $text, ConsoleColors $color): string
{
return "\033[" . $color->value . "m" . $text . "\033[0m";
}
/**
* Colorizes the log message based on the event level using ANSI escape sequences.
*
* @param Event $event The log event to colorize.
* @return string The colorized log message.
*/
private static function colorize(Event $event): string
{
$color = match($event->getLevel())
{
LogLevel::DEBUG => ConsoleColors::LIGHT_PURPLE,
LogLevel::VERBOSE => ConsoleColors::LIGHT_CYAN,
LogLevel::INFO => ConsoleColors::WHITE,
LogLevel::WARNING => ConsoleColors::YELLOW,
LogLevel::FATAL => ConsoleColors::RED,
LogLevel::ERROR => ConsoleColors::LIGHT_RED,
default => null,
};
if($color === null)
{
return Utilities::levelToString($event->getLevel());
}
return self::color(Utilities::levelToString($event->getLevel()), $color);
}
/**
* Retrieves the current timestamp as a formatted string.
*
* @return string The current timestamp.
*/
private static function getTimestamp(): string
{
$tick_time = (string)microtime(true);
if(!is_null(self::$largest_tick_length) && strlen($tick_time) > (int)self::$largest_tick_length)
{
self::$largest_tick_length = strlen($tick_time);
}
if(strlen($tick_time) < self::$largest_tick_length)
{
$tick_time = str_pad($tick_time, (strlen($tick_time) + (self::$largest_tick_length - strlen($tick_time))));
}
$fmt_tick = $tick_time;
if(self::$last_tick_time !== null)
{
$timeDiff = microtime(true) - self::$last_tick_time;
if ($timeDiff > 1.0)
{
$fmt_tick = self::color($tick_time, ConsoleColors::LIGHT_RED);
}
elseif ($timeDiff > 0.5)
{
$fmt_tick = self::color($tick_time, ConsoleColors::YELLOW);
}
}
self::$last_tick_time = $tick_time;
return $fmt_tick;
}
/**
* Prints information about the given exception, including the error message, error code,
* and stack trace.
*
* @param Throwable|null $exception The exception to print information about.
* @return void
*/
private static function outException(?Throwable $exception=null): void
{
if($exception === null)
{
return;
}
$trace_header = self::color($exception->getFile() . ':' . $exception->getLine(), ConsoleColors::PURPLE);
$trace_error = self::color('error: ', ConsoleColors::RED);
print($trace_header . ' ' . $trace_error . $exception->getMessage() . PHP_EOL);
print(sprintf('Error code: %s', $exception->getCode()) . PHP_EOL);
$trace = $exception->getTrace();
if(count($trace) > 1)
{
print('Stack Trace:' . PHP_EOL);
foreach($trace as $item)
{
if(isset($item['file']) && isset($item['line']))
{
print( ' - ' . self::color($item['file'], ConsoleColors::RED) . ':' . $item['line'] . PHP_EOL);
}
}
}
if($exception->getPrevious() !== null)
{
print('Previous Exception:' . PHP_EOL);
self::outException($exception->getPrevious());
}
}
}

View file

@ -1,151 +0,0 @@
<?php
namespace LogLib\Handlers;
use LogLib\Classes\FileLock;
use LogLib\Classes\Utilities;
use LogLib\Classes\Validate;
use LogLib\Enums\LogLevel;
use LogLib\Interfaces\LogHandlerInterface;
use LogLib\Objects\Application;
use LogLib\Objects\Event;
use RuntimeException;
use Throwable;
class FileLogging implements LogHandlerInterface
{
private static array $application_logs = [];
/**
* @inheritDoc
*/
public static function handle(Application $application, Event $event): void
{
if(!Validate::checkLevelType($event->getLevel(), $application->getFileLoggingLevel()))
{
return;
}
if(Validate::checkLevelType(LogLevel::DEBUG, $application->getConsoleLoggingLevel()))
{
$backtrace_output = Utilities::getTraceString($event, false);
$output = sprintf("[%s] [%s] [%s] %s %s" . PHP_EOL,
self::getTimestamp(), $application->getApplicationName(), $event->getLevel()->name, $backtrace_output, $event->getMessage()
);
}
else if(Validate::checkLevelType(LogLevel::VERBOSE, $application->getConsoleLoggingLevel()))
{
$backtrace_output = Utilities::getTraceString($event, false);
$output = sprintf("[%s] [%s] [%s] %s %s" . PHP_EOL, self::getTimestamp(), $application->getApplicationName(), $event->getLevel()->name, $backtrace_output, $event->getMessage());
}
else
{
$output = sprintf("[%s] [%s] [%s] %s" . PHP_EOL, self::getTimestamp(), $application->getApplicationName(), $event->getLevel()->name, $event->getMessage());
}
if($event->getException() !== null)
{
$output .= self::outException($event->getException());
}
self::getLogger($application)->append($output);
}
/**
* Retrieves the logger instance associated with the given application.
* If the logger does not exist, it initializes a new one and stores it.
*
* @param Application $application The application for which the logger is to be retrieved.
* @return FileLock The logger instance associated with the specified application.
*/
private static function getLogger(Application $application): FileLock
{
if(!isset(self::$application_logs[$application->getApplicationName()]))
{
self::$application_logs[$application->getApplicationName()] = new FileLock(self::getLogFile($application));
}
return self::$application_logs[$application->getApplicationName()];
}
/**
* Retrieves the log file path for the specified application.
*
* @param Application $application The application instance for which the log file is to be retrieved.
* @return string The full path of the log file.
*/
private static function getLogFile(Application $application): string
{
$logging_directory = $application->getFileLoggingDirectory();
if(!file_exists($logging_directory))
{
if(!mkdir($logging_directory))
{
throw new RuntimeException(sprintf("Cannot write to %s due to insufficient permissions", $logging_directory));
}
}
$logging_file = $logging_directory . DIRECTORY_SEPARATOR . Utilities::sanitizeFileName($application->getApplicationName()) . '-' . date('Y-m-d') . '.log';
if(!file_exists($logging_file) && !@touch($logging_file))
{
throw new RuntimeException(sprintf("Cannot write to %s due to insufficient permissions", $logging_file));
}
return $logging_file;
}
/**
* Retrieves the current timestamp formatted as "yd/m/y H:i".
*
* @return string The formatted current timestamp.
*/
private static function getTimestamp(): string
{
return date('yd/m/y H:i');
}
/**
* Generates a detailed string representation of a given Throwable object, including its message, code,
* file, line of occurrence, stack trace, and any previous exceptions.
*
* @param Throwable|null $exception The throwable object to process. If null, an empty string is returned.
* @return string A detailed string representation of the throwable object.
*/
private static function outException(?Throwable $exception=null): string
{
if($exception === null)
{
return '';
}
$output = '';
$trace_header = $exception->getFile() . ':' . $exception->getLine();
$trace_error = 'error: ';
$output .= $trace_header . ' ' . $trace_error . $exception->getMessage() . PHP_EOL;
$output .= sprintf('Error code: %s', $exception->getCode() . PHP_EOL);
$trace = $exception->getTrace();
if(count($trace) > 1)
{
$output .= 'Stack Trace:' . PHP_EOL;
foreach($trace as $item)
{
if(isset($item['file']) && isset($item['line']))
{
$output .= ' - ' . $item['file'] . ':' . $item['line'] . PHP_EOL;
}
}
}
if($exception->getPrevious() !== null)
{
$output .= 'Previous Exception:' . PHP_EOL;
$output .= self::outException($exception->getPrevious());
}
return $output;
}
}

View file

@ -1,20 +0,0 @@
<?php
namespace LogLib\Interfaces;
use LogLib\Exceptions\LoggingException;
use LogLib\Objects\Application;
use LogLib\Objects\Event;
interface LogHandlerInterface
{
/**
* Outputs the event details based on the given options.
*
* @param Application $application The options used to configure the output
* @param Event $event The event to be output
* @return void
* @throws LoggingException If an error occurs while handling the event
*/
public static function handle(Application $application, Event $event): void;
}

View file

@ -4,48 +4,40 @@
namespace LogLib;
use ErrorException;
use Exception;
use InvalidArgumentException;
use LogLib\Abstracts\LevelType;
use LogLib\Classes\Console;
use LogLib\Classes\Utilities;
use LogLib\Enums\LogLevel;
use LogLib\Objects\Application;
use LogLib\Classes\Validate;
use LogLib\Objects\Event;
use LogLib\Objects\Options;
use LogLib\Objects\RuntimeOptions;
use Throwable;
class Log
{
/**
* @var Application[]|null
* @var Options[]
*/
private static $applications;
private static $Applications;
/**
* @var RuntimeOptions
*/
private static $RuntimeOptions;
/**
* Registers a new application logger
*
* @param Application $application The options for the application
* @param bool $overwrite
* @param Options $options The options for the application
* @return bool
*/
public static function register(Application $application, bool $overwrite=false): bool
public static function register(Options $options): bool
{
if(self::isRegistered($application->getApplicationName()))
{
if($overwrite)
{
self::$applications[$application->getApplicationName()] = $application;
return true;
}
if(self::isRegistered($options->getApplicationName()))
return false;
}
if(self::$applications === null)
{
self::$applications = [];
}
self::$applications[$application->getApplicationName()] = $application;
self::$Applications[$options->getApplicationName()] = $options;
return true;
}
@ -57,15 +49,8 @@
*/
public static function unregister(string $application): void
{
if(self::$applications === null)
{
return;
}
if(isset(self::$applications[$application]))
{
unset(self::$applications[$application]);
}
if(isset(self::$Applications[$application]))
unset(self::$Applications[$application]);
}
/**
@ -76,65 +61,64 @@
*/
private static function isRegistered(string $application): bool
{
return isset(self::$applications[$application]);
return isset(self::$Applications[$application]);
}
/**
* Retrieves the application options. If the application is not registered, it optionally creates and registers a new one.
*
* @param string $application The name of the application.
* @param bool $create (Optional) Whether to create the application if it is not registered. Default is true.
* @return Application The options for the specified application.
* @param string $application
* @return Options
*/
public static function getApplication(string $application, bool $create=true): Application
public static function getApplication(string $application): Options
{
if(!self::isRegistered($application))
{
if(!$create)
{
throw new InvalidArgumentException("The application '$application' is not registered");
}
self::register(new Application($application));
}
return self::$applications[$application];
return self::$Applications[$application];
}
/**
* Logs a message with a specified application name, level, optional message, and optional throwable.
*
* @param string|null $application_name The name of the application
* @param LogLevel $level The level type of the log (default is LevelType::INFO)
* @param string|null $message The message of the log event
* @param string $application_name The name of the application
* @return Options The options for the application
*/
public static function getOptions(string $application_name): Options
{
if(!self::isRegistered($application_name))
{
self::register(new Options($application_name));
}
return self::$Applications[$application_name];
}
/**
* @param string $application_name The name of the application
* @param string $level The level of the event
* @param string|null $message The message of the event
* @param Throwable|null $throwable The exception that was thrown, if any
* @return void
*/
private static function log(?string $application_name, LogLevel $level=LogLevel::INFO, ?string $message=null, ?Throwable $throwable=null): void
private static function log(string $application_name, string $level=LevelType::Info, ?string $message=null, ?Throwable $throwable=null): void
{
$application = self::getApplication($application_name);
$application = self::getOptions($application_name);
if($message === null)
{
if(!Validate::checkLevelType($level, self::getRuntimeOptions()->getLogLevel()))
return;
if($message == null)
throw new InvalidArgumentException('Message cannot be null');
}
if($level == null || !Validate::levelType($level))
throw new InvalidArgumentException('Invalid logging level');
$event = new Event($message, $level, $throwable);
$event = new Event();
$event->Level = $level;
$event->Message = $message;
$event->Exception = $throwable;
if($event->getBacktrace() === null)
{
if($event->getBacktrace() == null)
$event->setBacktrace(Utilities::getBacktrace());
}
if($application->isConsoleLoggingEnabled())
{
$application->getConsoleLoggingHandler()::handle($application, $event);
}
if($application->isFileLoggingEnabled())
{
$application->getFileLoggingHandler()::handle($application, $event);
}
if(self::getRuntimeOptions()->isConsoleOutput())
Console::out($application, $event);
}
/**
@ -144,7 +128,7 @@
*/
public static function info(string $application_name, string $message): void
{
self::log($application_name, LogLevel::INFO, $message);
self::log($application_name, LevelType::Info, $message);
}
/**
@ -154,7 +138,7 @@
*/
public static function verbose(string $application_name, string $message): void
{
self::log($application_name, LogLevel::VERBOSE, $message);
self::log($application_name, LevelType::Verbose, $message);
}
/**
@ -164,65 +148,74 @@
*/
public static function debug(string $application_name, string $message): void
{
self::log($application_name, LogLevel::DEBUG, $message);
self::log($application_name, LevelType::Debug, $message);
}
/**
* Logs a warning message.
*
* @param string $application_name The name of the application.
* @param string $message The warning message to log.
* @param Throwable|null $throwable (Optional) The throwable object associated with the warning.
* @param string $application_name The name of the application
* @param string $message The message of the event
* @param Throwable|null $throwable The exception that was thrown, if any
* @return void
*/
public static function warning(string $application_name, string $message, ?Throwable $throwable=null): void
{
self::log($application_name, LogLevel::WARNING, $message, $throwable);
self::log($application_name, LevelType::Warning, $message, $throwable);
}
/**
* Logs an error message.
*
* @param string $application_name The name of the application.
* @param string $message The error message.
* @param Throwable|null $throwable The optional throwable object associated with the error.
* @param string $application_name The name of the application
* @param string $message The message of the event
* @param Throwable|null $throwable The exception that was thrown, if any
* @return void
*/
public static function error(string $application_name, string $message, ?Throwable $throwable=null): void
{
self::log($application_name, LogLevel::ERROR, $message, $throwable);
self::log($application_name, LevelType::Error, $message, $throwable);
}
/**
* Logs a fatal message.
*
* @param string $application_name The name of the application.
* @param string $message The fatal message to log.
* @param Throwable|null $throwable (Optional) The throwable object associated with the fatal message.
* @param string $application_name The name of the application
* @param string $message The message of the event
* @param Throwable|null $throwable The exception that was thrown, if any
* @return void
*/
public static function fatal(string $application_name, string $message, ?Throwable $throwable=null): void
{
self::log($application_name, LogLevel::FATAL, $message, $throwable);
self::log($application_name, LevelType::Fatal, $message, $throwable);
}
/**
* Registers an exception handler that logs any uncaught exceptions as errors.
* Registers LogLib as a exception handler
*
* @return void
*/
public static function registerExceptionHandler(): void
{
Runtime::registerExceptionHandler();
set_exception_handler(function(Throwable $throwable) {
self::error('Runtime', $throwable->getMessage(), $throwable);
});
}
/**
* Unregisters the currently registered exception handler.
* Unregisters all applications
*
* @return void
*/
public static function unregisterExceptionHandler(): void
{
Runtime::unregisterExceptionHandler();
set_exception_handler(null);
}
/**
* @return RuntimeOptions
*/
public static function getRuntimeOptions(): RuntimeOptions
{
if(self::$RuntimeOptions == null)
{
self::$RuntimeOptions = new RuntimeOptions();
}
return self::$RuntimeOptions;
}
}

View file

@ -1,86 +0,0 @@
<?php
namespace LogLib;
use LogLib\Objects\Application;
use Throwable;
class Logger extends Application
{
/**
* @inheritDoc
*/
public function __construct(string $applicationName)
{
parent::__construct($applicationName);
Log::register($this, true);
}
/**
* Logs an informational message.
*
* @param string $message The message to log.
* @return void
*/
public function info(string $message): void
{
Log::info($this->getApplicationName(), $message);
}
/**
* Logs a verbose message with the application name.
*
* @param string $message The message to be logged.
* @return void
*/
public function verbose(string $message): void
{
Log::verbose($this->getApplicationName(), $message);
}
/**
* Logs a debug message.
*
* @param string $message The debug message to log.
* @return void
*/
public function debug(string $message): void
{
Log::debug($this->getApplicationName(), $message);
}
/**
* Logs a warning message with the application name.
*
* @param string $message The warning message to log.
* @return void
*/
public function warning(string $message): void
{
Log::warning($this->getApplicationName(), $message);
}
/**
* Logs an error message with an optional throwable instance.
*
* @param string $message The error message to be logged.
* @param Throwable|null $throwable An optional throwable instance to be logged along with the error message.
* @return void
*/
public function error(string $message, ?Throwable $throwable=null): void
{
Log::error($this->getApplicationName(), $message, $throwable);
}
/**
* Logs a fatal error message along with an optional throwable.
*
* @param string $message The fatal error message to log.
* @param Throwable|null $throwable Optional throwable associated with the fatal error.
* @return void
*/
public function fatal(string $message, ?Throwable $throwable=null): void
{
Log::fatal($this->getApplicationName(), $message, $throwable);
}
}

View file

@ -1,248 +0,0 @@
<?php
namespace LogLib\Objects;
use InvalidArgumentException;
use LogLib\Classes\Utilities;
use LogLib\Enums\LogLevel;
use LogLib\Handlers\ConsoleLogging;
use LogLib\Handlers\FileLogging;
use LogLib\Interfaces\LogHandlerInterface;
class Application
{
private string $applicationName;
private bool $handleExceptions;
private bool $consoleLoggingEnabled;
private string $consoleLoggingHandler;
private LogLevel $consoleLoggingLevel;
private bool $fileLoggingEnabled;
private string $fileLoggingHandler;
private LogLevel $fileLoggingLevel;
private string $fileLoggingDirectory;
/**
* Constructor for initializing the application logging and exception handling.
*
* @param string $applicationName The name of the application.
* @return void
*/
public function __construct(string $applicationName)
{
$this->applicationName = $applicationName;
$this->handleExceptions = true;
$this->consoleLoggingEnabled = Utilities::getConsoleLoggingEnabled();
$this->consoleLoggingHandler = ConsoleLogging::class;
$this->consoleLoggingLevel = Utilities::getConsoleLoggingLevel();
$this->fileLoggingEnabled = Utilities::getFileLoggingEnabled();
$this->fileLoggingHandler = FileLogging::class;
$this->fileLoggingLevel = Utilities::getFileLoggingLevel();
$this->fileLoggingDirectory = Utilities::getFileLoggingDirectory();
}
/**
*
* @return string
*/
public function getApplicationName(): string
{
return $this->applicationName;
}
/**
* Checks if exceptions are being handled.
*
* @return bool
*/
public function isHandleExceptions(): bool
{
return $this->handleExceptions;
}
/**
* Sets the flag to handle exceptions.
*
* @param bool $handleExceptions Flag indicating whether to handle exceptions.
* @return void
*/
public function setHandleExceptions(bool $handleExceptions): void
{
$this->handleExceptions = $handleExceptions;
}
/**
* Checks if console logging is enabled.
*
* @return bool True if console logging is enabled, false otherwise.
*/
public function isConsoleLoggingEnabled(): bool
{
return $this->consoleLoggingEnabled;
}
/**
*
* @param bool $consoleLoggingEnabled Indicates whether console logging is enabled.
* @return void
*/
public function setConsoleLoggingEnabled(bool $consoleLoggingEnabled): void
{
$this->consoleLoggingEnabled = $consoleLoggingEnabled;
}
/**
* Gets the current console logging handler.
*
* @return LogHandlerInterface|string The console logging handler currently set.
*/
public function getConsoleLoggingHandler(): LogHandlerInterface|string
{
return new $this->consoleLoggingHandler;
}
/**
* Sets the console logging handler.
*
* @param LogHandlerInterface|string $consoleLoggingHandler The console logging handler to set.
* @return void
*/
public function setConsoleLoggingHandler(LogHandlerInterface|string $consoleLoggingHandler): void
{
if($consoleLoggingHandler instanceof LogHandlerInterface)
{
$this->consoleLoggingHandler = get_class($consoleLoggingHandler);
return;
}
if(!class_exists($consoleLoggingHandler))
{
throw new InvalidArgumentException("The class $consoleLoggingHandler does not exist.");
}
if(!in_array(LogHandlerInterface::class, class_implements($consoleLoggingHandler)))
{
throw new InvalidArgumentException("The class $consoleLoggingHandler does not implement LogHandlerInterface.");
}
$this->consoleLoggingHandler = $consoleLoggingHandler;
}
/**
* Gets the current console logging level.
*
* @return LogLevel The current logging level for the console.
*/
public function getConsoleLoggingLevel(): LogLevel
{
return $this->consoleLoggingLevel;
}
/**
* Sets the logging level for console output.
*
* @param LogLevel $consoleLoggingLevel The logging level to set for console output.
* @return void
*/
public function setConsoleLoggingLevel(LogLevel $consoleLoggingLevel): void
{
$this->consoleLoggingLevel = $consoleLoggingLevel;
}
/**
* Checks if file logging is enabled.
*
* @return bool Returns true if file logging is enabled, false otherwise.
*/
public function isFileLoggingEnabled(): bool
{
return $this->fileLoggingEnabled;
}
/**
* Enables or disables file logging.
*
* @param bool $fileLoggingEnabled True to enable file logging, false to disable.
* @return void
*/
public function setFileLoggingEnabled(bool $fileLoggingEnabled): void
{
$this->fileLoggingEnabled = $fileLoggingEnabled;
}
/**
* @return LogHandlerInterface|string
*/
public function getFileLoggingHandler(): LogHandlerInterface|string
{
return $this->fileLoggingHandler;
}
/**
* Sets the file logging handler.
*
* @param string $fileLoggingHandler The file logging handler to be set.
* @return void
*/
public function setFileLoggingHandler(string $fileLoggingHandler): void
{
if($fileLoggingHandler instanceof LogHandlerInterface)
{
$this->consoleLoggingHandler = get_class($fileLoggingHandler);
return;
}
if(!class_exists($fileLoggingHandler))
{
throw new InvalidArgumentException("The class $fileLoggingHandler does not exist.");
}
if(!in_array(LogHandlerInterface::class, class_implements($fileLoggingHandler)))
{
throw new InvalidArgumentException("The class $fileLoggingHandler does not implement LogHandlerInterface.");
}
$this->consoleLoggingHandler = $fileLoggingHandler;
}
/**
* Retrieves the logging level for file outputs.
*
* @return LogLevel The current file logging level.
*/
public function getFileLoggingLevel(): LogLevel
{
return $this->fileLoggingLevel;
}
/**
* Sets the logging level for file-based logging.
*
* @param LogLevel $fileLoggingLevel The logging level to set for file logging.
* @return void
*/
public function setFileLoggingLevel(LogLevel $fileLoggingLevel): void
{
$this->fileLoggingLevel = $fileLoggingLevel;
}
/**
* Get the directory path for file logging.
*
* @return string The directory path where log files are stored.
*/
public function getFileLoggingDirectory(): string
{
return $this->fileLoggingDirectory;
}
/**
* Sets the directory for file logging.
*
* @param string $fileLoggingDirectory The path to the directory where log files will be stored.
* @return void
*/
public function setFileLoggingDirectory(string $fileLoggingDirectory): void
{
$this->fileLoggingDirectory = $fileLoggingDirectory;
}
}

View file

@ -0,0 +1,174 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace LogLib\Objects;
class Backtrace
{
/**
* The function name of the backtrace
*
* @var string|null
* @property_name function
*/
private $Function;
/**
* The line number of the backtrace
*
* @var int|null
* @property_name line
*/
private $Line;
/**
* The file name of the backtrace
*
* @var string|null
* @property_name file
*/
private $File;
/**
* The class name, if any, of the backtrace
*
* @var string|null
* @property_name class
*/
private $Class;
/**
* The current call type. If a method call, "->" is returned.
* If a static method call, "::" is returned. If a function call,
* nothing is returned.
*
* @see CallType
* @var string|null
* @property_name type
*/
private $Type;
/**
* If inside a function, this lists the functions arguments. If inside
* an included file, this lists the included file name(s).
*
* @var array|null
* @property_name args
*/
private $Args;
/**
* Public Constructor
*
* @param array|null $backtrace
*/
public function __construct(?array $backtrace=null)
{
if($backtrace === null)
return;
$this->Function = $backtrace['function'] ?? null;
$this->Line = $backtrace['line'] ?? null;
$this->File = $backtrace['file'] ?? null;
$this->Class = $backtrace['class'] ?? null;
$this->Type = $backtrace['type'] ?? null;
$this->Args = $backtrace['args'] ?? null;
}
/**
* @return string|null
*/
public function getFunction(): ?string
{
return $this->Function;
}
/**
* @param string|null $Function
*/
public function setFunction(?string $Function): void
{
$this->Function = $Function;
}
/**
* @return int|null
*/
public function getLine(): ?int
{
return $this->Line;
}
/**
* @param int|null $Line
*/
public function setLine(?int $Line): void
{
$this->Line = $Line;
}
/**
* @return string|null
*/
public function getFile(): ?string
{
return $this->File;
}
/**
* @param string|null $File
*/
public function setFile(?string $File): void
{
$this->File = $File;
}
/**
* @return string|null
*/
public function getClass(): ?string
{
return $this->Class;
}
/**
* @param string|null $Class
*/
public function setClass(?string $Class): void
{
$this->Class = $Class;
}
/**
* @return string|null
*/
public function getType(): ?string
{
return $this->Type;
}
/**
* @param string|null $Type
*/
public function setType(?string $Type): void
{
$this->Type = $Type;
}
/**
* @return array|null
*/
public function getArgs(): ?array
{
return $this->Args;
}
/**
* @param array|null $Args
*/
public function setArgs(?array $Args): void
{
$this->Args = $Args;
}
}

View file

@ -4,77 +4,54 @@
namespace LogLib\Objects;
use LogLib\Abstracts\LevelType;
use LogLib\Classes\Utilities;
use LogLib\Enums\LogLevel;
use Throwable;
class Event
{
/**
* @var LogLevel
* The level of the event
*
* @see LevelType
* @var string
* @property_name level
*/
private $level;
/**
* @var array|null
*/
private $backtrace;
/**
* @var Throwable|null
*/
private $exception;
public $Level;
/**
* The Unix Timestamp of when the event was created
*
* @var string
*/
private $message;
private $Timestamp;
/**
* Event constructor.
* An array of backtraces, if any, that were created when the event was created
*
* @param string $message
* @param LogLevel $level
* @param Throwable|null $exception
* @param array|null $backtrace
* @var Backtrace[]|null
*/
public function __construct(string $message, LogLevel $level, ?Throwable $exception=null, ?array $backtrace=null)
{
$this->message = $message;
$this->level = $level;
$this->exception = $exception;
$this->backtrace = $backtrace;
}
private $Backtrace;
/**
* Returns the level of the event
* The exception that was thrown, if any
*
* @return LogLevel
* @see LogLevel
* @var Throwable|null
*/
public function getLevel(): LogLevel
{
return $this->level;
}
public $Exception;
/**
* Returns the message of the event
* The message of the event
*
* @return string
* @var string
*/
public function getMessage(): string
{
return $this->message;
}
public $Message;
/**
* Optional. Returns the exception to the event
*
* @return Throwable|null
* Public Constructor
*/
public function getException(): ?Throwable
public function __construct()
{
return $this->exception;
$this->Timestamp = date('c');
}
/**
@ -85,26 +62,31 @@
*/
public function setException(Throwable $e): void
{
$this->exception = Utilities::exceptionToArray($e);
$this->Exception = Utilities::exceptionToArray($e);
}
/**
* @return string
*/
public function getTimestamp(): string
{
return $this->Timestamp;
}
/**
* Returns the backtrace of the event
*
* @return array|null
*/
public function getBacktrace(): ?array
{
return $this->backtrace;
return $this->Backtrace;
}
/**
* Sets the backtrace of the event
*
* @param array|null $backtrace
* @param array|null $Backtrace
*/
public function setBacktrace(?array $backtrace): void
public function setBacktrace(?array $Backtrace): void
{
$this->backtrace = $backtrace;
$this->Backtrace = $Backtrace;
}
}

View file

@ -0,0 +1,36 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace LogLib\Objects;
class Options
{
/**
* The name of the application
*
* @var string
* @property_name application_name
*/
private $ApplicationName;
/**
* Options constructor.
*/
public function __construct(string $application_name)
{
$this->ApplicationName = $application_name;
}
/**
* Returns the name of the Application
*
* @return string
*/
public function getApplicationName(): string
{
return $this->ApplicationName;
}
}

View file

@ -0,0 +1,119 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace LogLib\Objects;
use InvalidArgumentException;
use LogLib\Abstracts\LevelType;
use LogLib\Classes\Utilities;
class RuntimeOptions
{
/**
* Indicates if the console output is enabled
*
* @var bool
* @property_name console_output
*/
private $ConsoleOutput;
/**
* Indicates if ANSI colors should be used in the console output
*
* @var bool
* @property_name display_ansi
*/
private $DisplayAnsi;
/**
* Indicates if LogLib should handle uncaught exceptions
*
* @var bool
* @property_name handle_exceptions
*/
private $HandleExceptions;
/**
* The current log level
*
* @var int
* @see LevelType
*/
private $LogLevel;
/**
* Public Constructor
*/
public function __construct()
{
$this->ConsoleOutput = Utilities::runningInCli();
$this->DisplayAnsi = Utilities::getDisplayAnsi();
$this->HandleExceptions = true;
$this->LogLevel = Utilities::getLogLevel();
}
/**
* @return bool
*/
public function isConsoleOutput(): bool
{
return $this->ConsoleOutput;
}
/**
* @param bool $ConsoleOutput
*/
public function setConsoleOutput(bool $ConsoleOutput): void
{
$this->ConsoleOutput = $ConsoleOutput;
}
/**
* @return bool
*/
public function isDisplayAnsi(): bool
{
return $this->DisplayAnsi;
}
/**
* @param bool $DisplayAnsi
*/
public function setDisplayAnsi(bool $DisplayAnsi): void
{
$this->DisplayAnsi = $DisplayAnsi;
}
/**
* @return bool
*/
public function isHandleExceptions(): bool
{
return $this->HandleExceptions;
}
/**
* @param bool $HandleExceptions
*/
public function setHandleExceptions(bool $HandleExceptions): void
{
$this->HandleExceptions = $HandleExceptions;
}
/**
* @return int
*/
public function getLogLevel(): int
{
return $this->LogLevel;
}
/**
* @param int $LogLevel
*/
public function setLogLevel(int $LogLevel): void
{
$this->LogLevel = $LogLevel;
}
}

View file

@ -1,155 +0,0 @@
<?php
namespace LogLib;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
class Psr implements LoggerInterface
{
/**
* The name of the application
*
* @var string
*/
private string $application;
/**
* Public Constructor
*
* @param string $application
*/
public function __construct(string $application)
{
$this->application = $application;
}
/**
* Handles the emergency log level
*
* @param $message
* @param array $context
* @return void
*/
public function emergency($message, array $context = array()): void
{
Log::fatal($this->application, $message);
}
/**
* Handles the alert log level
*
* @param $message
* @param array $context
* @return void
*/
public function alert($message, array $context = array()): void
{
Log::warning($this->application, $message);
}
/**
* Handles the critical log level
*
* @param $message
* @param array $context
* @return void
*/
public function critical($message, array $context = array()): void
{
Log::fatal($this->application, $message);
}
/**
* Handles the error log level
*
* @param $message
* @param array $context
* @return void
*/
public function error($message, array $context = array()): void
{
Log::error($this->application, $message);
}
/**
* Handles the warning log level
*
* @param $message
* @param array $context
* @return void
*/
public function warning($message, array $context = []): void
{
Log::warning($this->application, $message);
}
/**
* Handles the notice log level
*
* @param $message
* @param array $context
* @return void
*/
public function notice($message, array $context = array()): void
{
Log::info($this->application, $message);
}
/**
* Handles the info log level
*
* @param $message
* @param array $context
* @return void
*/
public function info($message, array $context = array()): void
{
Log::info($this->application, $message);
}
/**
* Handles the debug log level
*
* @param $message
* @param array $context
* @return void
*/
public function debug($message, array $context = array()): void
{
Log::debug($this->application, $message);
}
/**
* Handles a logging event
*
* @param $level
* @param $message
* @param array $context
* @return void
*/
public function log($level, $message, array $context = array()): void
{
switch($level)
{
case LogLevel::CRITICAL:
case LogLevel::ALERT:
case LogLevel::EMERGENCY:
Log::fatal($this->application, $message);
break;
case LogLevel::ERROR:
Log::error($this->application, $message);
break;
case LogLevel::WARNING:
Log::warning($this->application, $message);
break;
case LogLevel::INFO:
case LogLevel::NOTICE:
Log::info($this->application, $message);
break;
case LogLevel::DEBUG:
Log::debug($this->application, $message);
break;
}
}
}

View file

@ -1,124 +0,0 @@
<?php
namespace LogLib;
use ErrorException;
use Exception;
use Throwable;
class Runtime
{
/**
* Registers an exception handler that logs any uncaught exceptions as errors.
*
* @return void
*/
public static function registerExceptionHandler(): void
{
set_exception_handler([__CLASS__, 'exceptionHandler']);
set_error_handler([__CLASS__, 'errorHandler']);
register_shutdown_function([__CLASS__, 'shutdownHandler']);
}
/**
* Handles uncaught exceptions by logging them with a fatal error level.
*
* @param Throwable $throwable The exception or error that was thrown.
* @return void
*/
public static function exceptionHandler(Throwable $throwable): void
{
try
{
Log::Fatal('Runtime', $throwable->getMessage(), $throwable);
}
catch(Exception)
{
return;
}
}
/**
* Handles PHP errors by converting them to exceptions and logging appropriately.
*
* @param int $errno The level of the error raised.
* @param string $errstr The error message.
* @param string $errfile The filename that the error was raised in.
* @param int $errline The line number the error was raised at.
* @return bool True to prevent PHP's internal error handler from being invoked.
*/
public static function errorHandler(int $errno, string $errstr, string $errfile = '', int $errline = 0): bool
{
try
{
// Convert error to exception for consistent handling
$exception = new ErrorException($errstr, 0, $errno, $errfile, $errline);
// Handle different error types
switch ($errno)
{
case E_ERROR:
case E_PARSE:
case E_CORE_ERROR:
case E_COMPILE_ERROR:
case E_USER_ERROR:
Log::error('Runtime', $errstr, $exception);
break;
case E_USER_DEPRECATED:
case E_DEPRECATED:
case E_USER_NOTICE:
case E_NOTICE:
case E_USER_WARNING:
case E_WARNING:
default:
Log::warning('Runtime', $errstr, $exception);
break;
}
}
catch(Exception)
{
return false;
}
// Return true to prevent PHP's internal error handler
return true;
}
/**
* Handles script shutdown by checking for any fatal errors and logging them.
*
* This method is designed to be registered with the `register_shutdown_function`,
* and it inspects the last error that occurred using `error_get_last`. If a fatal
* error is detected, it logs the error details.
*
* @return void
*/
public static function shutdownHandler(): void
{
$error = error_get_last();
if ($error !== null && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR]))
{
try
{
$exception = new ErrorException($error['message'], 0, $error['type'], $error['file'], $error['line']);
Log::error('Fatal Error', $error['message'], $exception);
}
catch(Exception)
{
return;
}
}
}
/**
* Unregisters the currently registered exception handler.
*
* @return void
*/
public static function unregisterExceptionHandler(): void
{
set_exception_handler(null);
}
}

View file

@ -1,74 +0,0 @@
<?php
namespace LogLib;
use PHPUnit\Framework\TestCase;
class LogTest extends TestCase
{
public function testDebug()
{
}
public function testInfo()
{
}
public function testGetRuntimeOptions()
{
}
public function testGetOptions()
{
}
public function testGetApplication()
{
}
public function testUnregisterExceptionHandler()
{
}
public function testUnregister()
{
}
public function testWarning()
{
}
public function testError()
{
}
public function testFatal()
{
}
public function testRegisterExceptionHandler()
{
}
public function testVerbose()
{
}
public function testRegister()
{
}
}

View file

@ -1,5 +1,6 @@
<?php
use LogLib\Abstracts\LevelType;
use LogLib\Log;
use LogLib\Objects\Options;

View file

@ -1,5 +1,6 @@
<?php
use LogLib\Abstracts\LevelType;
use LogLib\Log;
use LogLib\Objects\Options;
@ -15,60 +16,3 @@
Log::warning('net.nosial.optslib', 'This is a warning message');
Log::error('net.nosial.optslib', 'This is an error message');
Log::fatal('net.nosial.optslib', 'This is a fatal message');
class test
{
public function testLogging(): void
{
Log::debug('net.nosial.optslib', 'This is a debug message');
Log::verbose('net.nosial.optslib', 'This is a verbose message');
Log::info('net.nosial.optslib', 'This is an info message');
Log::warning('net.nosial.optslib', 'This is a warning message');
Log::error('net.nosial.optslib', 'This is an error message');
Log::fatal('net.nosial.optslib', 'This is a fatal message');
}
}
$test = new test();
$test->testLogging();
eval('\LogLib\Log::debug(\'net.nosial.optslib\', \'This is a debug message\');');
eval('\LogLib\Log::verbose(\'net.nosial.optslib\', \'This is a verbose message\');');
$callable = static function()
{
Log::info('net.nosial.optslib', 'This is an info message');
Log::warning('net.nosial.optslib', 'This is a warning message');
Log::error('net.nosial.optslib', 'This is an error message');
Log::fatal('net.nosial.optslib', 'This is a fatal message');
};
$callable();
class test2
{
public function testEval(): void
{
eval('\LogLib\Log::debug(\'net.nosial.optslib\', \'This is a debug message\');');
eval('\LogLib\Log::verbose(\'net.nosial.optslib\', \'This is a verbose message\');');
}
public function testCallable(): void
{
$b = static function()
{
Log::info('net.nosial.optslib', 'This is an info message');
Log::warning('net.nosial.optslib', 'This is a warning message');
Log::error('net.nosial.optslib', 'This is an error message');
Log::fatal('net.nosial.optslib', 'This is a fatal message');
};
$b();
}
}
$test2 = new test2();
$test2->testEval();
$test2->testCallable();