277 lines
7.7 KiB
PHP
277 lines
7.7 KiB
PHP
<?php
|
|
/**
|
|
* Eenvoudige logger voor CodePress CMS.
|
|
*
|
|
* Voorziet in gestructureerde logging met loglevels en bestandsuitvoer.
|
|
* Logregels worden naar een tekstbestand geschreven en, indien aanwezig,
|
|
* tevens door de dynamische LogManager gerouteerd.
|
|
*
|
|
* @since 2.6.4
|
|
*/
|
|
|
|
class Logger {
|
|
/**
|
|
* Loglevel voor debug-boodschappen.
|
|
*
|
|
* @since 2.6.4
|
|
* @var string
|
|
*/
|
|
const DEBUG = 'DEBUG';
|
|
|
|
/**
|
|
* Loglevel voor informatieve boodschappen.
|
|
*
|
|
* @since 2.6.4
|
|
* @var string
|
|
*/
|
|
const INFO = 'INFO';
|
|
|
|
/**
|
|
* Loglevel voor waarschuwingen.
|
|
*
|
|
* @since 2.6.4
|
|
* @var string
|
|
*/
|
|
const WARNING = 'WARNING';
|
|
|
|
/**
|
|
* Loglevel voor fouten.
|
|
*
|
|
* @since 2.6.4
|
|
* @var string
|
|
*/
|
|
const ERROR = 'ERROR';
|
|
|
|
/**
|
|
* Pad naar het logbestand, of null indien nog niet geïnitialiseerd.
|
|
*
|
|
* @since 2.6.4
|
|
* @var string|null
|
|
*/
|
|
private static $logFile = null;
|
|
|
|
/**
|
|
* Of debug-logging actief is.
|
|
*
|
|
* @since 2.6.4
|
|
* @var bool
|
|
*/
|
|
private static $debugMode = false;
|
|
|
|
/**
|
|
* Initialiseert de logger.
|
|
*
|
|
* Stelt het pad naar het logbestand in en zorgt dat de bijbehorende
|
|
* map bestaat. Indien geen pad wordt opgegeven valt de logger terug
|
|
* op een standaardpad onder de core-map.
|
|
*
|
|
* @since 2.6.4
|
|
*
|
|
* @param string|null $logFile Pad naar het logbestand. Default null (standaardlocatie).
|
|
* @param bool $debugMode Of debug-logging actief is. Default false.
|
|
* @return void
|
|
*/
|
|
public static function init($logFile = null, $debugMode = false) {
|
|
if ($logFile === null) {
|
|
$logFile = __DIR__ . '/../../logs/codepress.log';
|
|
}
|
|
|
|
self::$logFile = $logFile;
|
|
self::$debugMode = $debugMode;
|
|
|
|
// Ensure log directory exists
|
|
$logDir = dirname(self::$logFile);
|
|
if (!is_dir($logDir)) {
|
|
@mkdir($logDir, 0755, true);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Logt een debug-boodschap (enkel in debug-modus).
|
|
*
|
|
* @since 2.6.4
|
|
*
|
|
* @param string $message Boodschap die gelogd moet worden.
|
|
* @param array $context Aanvullende contextuele data. Default lege array.
|
|
* @return void
|
|
*/
|
|
public static function debug($message, $context = []) {
|
|
if (self::$debugMode) {
|
|
self::write(self::DEBUG, $message, $context);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Logt een informatieve boodschap.
|
|
*
|
|
* @since 2.6.4
|
|
*
|
|
* @param string $message Boodschap die gelogd moet worden.
|
|
* @param array $context Aanvullende contextuele data. Default lege array.
|
|
* @return void
|
|
*/
|
|
public static function info($message, $context = []) {
|
|
self::write(self::INFO, $message, $context);
|
|
}
|
|
|
|
/**
|
|
* Logt een waarschuwing.
|
|
*
|
|
* @since 2.6.4
|
|
*
|
|
* @param string $message Boodschap die gelogd moet worden.
|
|
* @param array $context Aanvullende contextuele data. Default lege array.
|
|
* @return void
|
|
*/
|
|
public static function warning($message, $context = []) {
|
|
self::write(self::WARNING, $message, $context);
|
|
}
|
|
|
|
/**
|
|
* Logt een fout.
|
|
*
|
|
* @since 2.6.4
|
|
*
|
|
* @param string $message Boodschap die gelogd moet worden.
|
|
* @param array $context Aanvullende contextuele data. Default lege array.
|
|
* @return void
|
|
*/
|
|
public static function error($message, $context = []) {
|
|
self::write(self::ERROR, $message, $context);
|
|
}
|
|
|
|
/**
|
|
* Schrijft een logregel naar het bestand en routeert deze door LogManager.
|
|
*
|
|
* De context-array wordt als JSON aan de logregel toegevoegd. Fouten bij
|
|
* het schrijven worden gesilenced (graceful degradation). Wanneer de
|
|
* LogManager class beschikbaar is, wordt de entry tevens naar de
|
|
* dynamische log gestuurd (errors/warnings naar EVENT_ERRORS, verder
|
|
* naar EVENT_SYSTEM).
|
|
*
|
|
* @since 2.6.4
|
|
*
|
|
* @param string $level Loglevel (DEBUG, INFO, WARNING, ERROR).
|
|
* @param string $message Boodschap die gelogd moet worden.
|
|
* @param array $context Aanvullende contextuele data. Default lege array.
|
|
* @return void
|
|
*/
|
|
private static function write($level, $message, $context = []) {
|
|
if (self::$logFile === null) {
|
|
self::init();
|
|
}
|
|
|
|
$timestamp = date('Y-m-d H:i:s');
|
|
$contextStr = !empty($context) ? ' ' . json_encode($context) : '';
|
|
$line = "[$timestamp] [$level] $message$contextStr\n";
|
|
|
|
// Write to file with error suppression (graceful degradation)
|
|
@file_put_contents(self::$logFile, $line, FILE_APPEND | LOCK_EX);
|
|
|
|
// Route through the dynamic log manager (errors/system events)
|
|
if (class_exists('LogManager')) {
|
|
$event = ($level === self::ERROR || $level === self::WARNING)
|
|
? LogManager::EVENT_ERRORS
|
|
: LogManager::EVENT_SYSTEM;
|
|
LogManager::log($event, strtolower($level), $message, $context);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Geeft het pad naar het logbestand.
|
|
*
|
|
* @since 2.6.4
|
|
*
|
|
* @return string|null Pad naar het logbestand of null indien niet geïnitialiseerd.
|
|
*/
|
|
public static function getLogFile() {
|
|
return self::$logFile;
|
|
}
|
|
|
|
/**
|
|
* Verwijdert het logbestand.
|
|
*
|
|
* @since 2.6.4
|
|
*
|
|
* @return bool True indien het bestand succesvol verwijderd is, anders false.
|
|
*/
|
|
public static function clear() {
|
|
if (self::$logFile && file_exists(self::$logFile)) {
|
|
return @unlink(self::$logFile);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Geeft de laatste N regels uit het logbestand.
|
|
*
|
|
* Leest het bestand achterwaarts in chunks zodat grote logbestanden
|
|
* nooit volledig in het geheugen geladen hoeven te worden. De regels
|
|
* worden inclusief afsluitende newlines teruggegeven, oudste eerst.
|
|
*
|
|
* @since 2.6.4
|
|
*
|
|
* @param int $lines Aantal terug te halen regels. Default 100.
|
|
* @return array<string> Logregels (oudste eerst) of lege array indien niet beschikbaar.
|
|
*/
|
|
public static function tail($lines = 100) {
|
|
if (!self::$logFile || !file_exists(self::$logFile)) {
|
|
return [];
|
|
}
|
|
|
|
$lines = max(1, (int)$lines);
|
|
|
|
$handle = @fopen(self::$logFile, 'rb');
|
|
if ($handle === false) {
|
|
return [];
|
|
}
|
|
|
|
if (fseek($handle, 0, SEEK_END) !== 0) {
|
|
fclose($handle);
|
|
return [];
|
|
}
|
|
|
|
$fileSize = ftell($handle);
|
|
if ($fileSize === false || $fileSize === 0) {
|
|
fclose($handle);
|
|
return [];
|
|
}
|
|
|
|
$chunkSize = 8192;
|
|
$position = $fileSize;
|
|
$buffer = '';
|
|
$newlineCount = 0;
|
|
|
|
// Read backwards until we have enough newlines or reach the start
|
|
while ($position > 0 && $newlineCount <= $lines) {
|
|
$readSize = (int)min($chunkSize, $position);
|
|
$position -= $readSize;
|
|
|
|
if (fseek($handle, $position, SEEK_SET) !== 0) {
|
|
break;
|
|
}
|
|
|
|
$chunk = fread($handle, $readSize);
|
|
if ($chunk === false) {
|
|
break;
|
|
}
|
|
|
|
$buffer = $chunk . $buffer;
|
|
$newlineCount = substr_count($buffer, "\n");
|
|
}
|
|
|
|
fclose($handle);
|
|
|
|
if ($buffer === '') {
|
|
return [];
|
|
}
|
|
|
|
// Split while keeping the newline characters, matching file() behaviour
|
|
$result = preg_split('/(?<=\n)/', $buffer, -1, PREG_SPLIT_NO_EMPTY);
|
|
if ($result === false) {
|
|
return [];
|
|
}
|
|
|
|
return array_slice($result, -$lines);
|
|
}
|
|
} |