Further work on Monolog improvements

This commit is contained in:
Pinga 2025-02-14 19:56:51 +02:00
parent 15652bad67
commit 595d10349c
7 changed files with 186 additions and 18 deletions

View file

@ -96,6 +96,13 @@ function setupLogger($logFilePath, $channelName = 'app') {
function archiveOldLogs($logFilePath) { function archiveOldLogs($logFilePath) {
$logDir = dirname($logFilePath); $logDir = dirname($logFilePath);
$backupDir = '/opt/backup'; $backupDir = '/opt/backup';
$lockFile = $backupDir . '/log_archive.lock';
// Prevent multiple processes from running archive at the same time
if (file_exists($lockFile)) {
return; // Another process is already archiving
}
touch($lockFile); // Create lock file
if (!is_dir($backupDir)) { if (!is_dir($backupDir)) {
mkdir($backupDir, 0755, true); mkdir($backupDir, 0755, true);
@ -113,12 +120,16 @@ function archiveOldLogs($logFilePath) {
// Open or create ZIP archive // Open or create ZIP archive
$zip = new ZipArchive(); $zip = new ZipArchive();
if ($zip->open($zipPath, ZipArchive::CREATE) === true) { if ($zip->open($zipPath, ZipArchive::CREATE) === true) {
$zip->addFile($file, $filename); if (!$zip->locateName($filename)) { // Prevent duplicate addition
$zip->addFile($file, $filename);
unlink($file); // Delete original log after archiving
}
$zip->close(); $zip->close();
unlink($file); // Delete original log after archiving
} }
} }
} }
unlink($lockFile); // Remove lock when done
} }
function fetchCount($pdo, $tableName) { function fetchCount($pdo, $tableName) {

View file

@ -4,11 +4,20 @@ namespace App\Lib;
use Monolog\ErrorHandler; use Monolog\ErrorHandler;
use Monolog\Handler\RotatingFileHandler; use Monolog\Handler\RotatingFileHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Formatter\LineFormatter;
use Monolog\Handler\FilterHandler;
use Monolog\Handler\WhatFailureGroupHandler;
use MonologPHPMailer\PHPMailerHandler;
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
use Whoops\Handler\PrettyPageHandler; use Whoops\Handler\PrettyPageHandler;
use Whoops\Run; use Whoops\Run;
use Dotenv\Dotenv;
use ZipArchive;
/** /**
* Logger * Namingo CP Logger
*/ */
class Logger extends \Monolog\Logger class Logger extends \Monolog\Logger
{ {
@ -24,7 +33,6 @@ class Logger extends \Monolog\Logger
{ {
parent::__construct($key); parent::__construct($key);
// Set log path and maximum number of files to retain
$LOG_PATH = '/var/log/namingo'; $LOG_PATH = '/var/log/namingo';
$maxFiles = 30; // Number of days to keep logs $maxFiles = 30; // Number of days to keep logs
@ -36,11 +44,73 @@ class Logger extends \Monolog\Logger
]; ];
} }
// Use RotatingFileHandler for automatic rotation // Load Environment Variables from .env
$this->pushHandler(new RotatingFileHandler($config['logFile'], $config['maxFiles'], $config['logLevel'])); $dotenv = Dotenv::createImmutable('/var/www/cp/');
$dotenv->load();
// Console Logging (For Real-Time Debugging)
$consoleHandler = new StreamHandler('php://stdout', \Monolog\Logger::DEBUG);
$consoleFormatter = new LineFormatter(
"[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n",
"Y-m-d H:i:s.u", // Date format
true, // Allow inline line breaks
true // Ignore empty context and extra
);
$consoleHandler->setFormatter($consoleFormatter);
$this->pushHandler($consoleHandler);
// File Logging (Rotating Handler - Keeps 30 Days)
$fileHandler = new RotatingFileHandler($config['logFile'], $config['maxFiles'], $config['logLevel']);
$fileFormatter = new LineFormatter(
"[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n",
"Y-m-d H:i:s.u"
);
$fileHandler->setFormatter($fileFormatter);
$this->pushHandler($fileHandler);
// Archive Old Logs (Move older than 14 days to ZIP)
$this->archiveOldLogs($config['logFile']);
// Pushover Alerts (For CRITICAL, ALERT, EMERGENCY)
if (!empty($_ENV['PUSHOVER_KEY'])) {
try {
$pushoverHandler = new PushoverHandler($_ENV['PUSHOVER_KEY'], \Monolog\Logger::ALERT);
$this->pushHandler($pushoverHandler);
} catch (\Exception $e) {
error_log("PushoverHandler failed: " . $e->getMessage());
}
}
// Email Alerts (For CRITICAL, ALERT, EMERGENCY)
if (!empty($_ENV['MAIL_HOST'])) {
try {
$mail = new PHPMailer(true);
$mail->isSMTP();
$mail->Host = $_ENV['MAIL_HOST'];
$mail->SMTPAuth = true;
$mail->Username = $_ENV['MAIL_USERNAME'];
$mail->Password = $_ENV['MAIL_PASSWORD'];
$mail->SMTPSecure = $_ENV['MAIL_ENCRYPTION'];
$mail->Port = $_ENV['MAIL_PORT'];
$mail->setFrom($_ENV['MAIL_FROM_ADDRESS'], $_ENV['MAIL_FROM_NAME']);
$mail->addAddress($_ENV['MAIL_FROM_ADDRESS']); // Send to admin email
// Attach PHPMailer to Monolog
$mailerHandler = new PHPMailerHandler($mail);
$mailerHandler->setFormatter(new LineFormatter());
// Filter Emails to ALERT, CRITICAL, EMERGENCY Only
$filteredMailHandler = new FilterHandler($mailerHandler, \Monolog\Logger::ALERT, \Monolog\Logger::EMERGENCY);
$safeMailHandler = new WhatFailureGroupHandler([$filteredMailHandler]);
$this->pushHandler($safeMailHandler);
} catch (Exception $e) {
error_log("Failed to initialize PHPMailer: " . $e->getMessage());
}
}
} }
/** /**
* Get an instance of the logger
* @param string $key * @param string $key
* @param null $config * @param null $config
* @return mixed * @return mixed
@ -60,11 +130,9 @@ class Logger extends \Monolog\Logger
public static function systemLogs($enable = true) public static function systemLogs($enable = true)
{ {
if ($enable) { if ($enable) {
// Output pretty HTML error
self::htmlError(); self::htmlError();
} else { } else {
// Register system errors to rotating log file $logger = new Logger('errors');
$logger = new Logger('errors'); // Key 'errors' remains for compatibility
ErrorHandler::register($logger); ErrorHandler::register($logger);
} }
} }
@ -78,4 +146,48 @@ class Logger extends \Monolog\Logger
$run->pushHandler(new PrettyPageHandler()); $run->pushHandler(new PrettyPageHandler());
$run->register(); $run->register();
} }
/**
* Archive Old Logs (Older than 14 Days)
*/
private function archiveOldLogs($logFilePath)
{
$logDir = dirname($logFilePath);
$backupDir = '/opt/backup';
$lockFile = $backupDir . '/log_archive.lock';
// Prevent multiple processes from running archive at the same time
if (file_exists($lockFile)) {
return; // Another process is already archiving
}
touch($lockFile); // Create lock file
if (!is_dir($backupDir)) {
mkdir($backupDir, 0755, true);
}
$logFiles = glob($logDir . '/*.log'); // Get all log files
$thresholdDate = strtotime('-14 days'); // Logs older than 14 days
foreach ($logFiles as $file) {
if (filemtime($file) < $thresholdDate) {
$filename = basename($file);
$monthYear = date('F-Y', filemtime($file));
$zipPath = $backupDir . "/logs-{$monthYear}.zip";
// Open or create ZIP archive
$zip = new ZipArchive();
if ($zip->open($zipPath, ZipArchive::CREATE) === true) {
if (!$zip->locateName($filename)) { // Prevent duplicate addition
$zip->addFile($file, $filename);
unlink($file); // Delete original log after archiving
}
$zip->close();
}
}
}
unlink($lockFile); // Remove lock when done
}
} }

View file

@ -49,7 +49,8 @@
"utopia-php/system": "^0.9.0", "utopia-php/system": "^0.9.0",
"bjeavons/zxcvbn-php": "^1.4", "bjeavons/zxcvbn-php": "^1.4",
"moneyphp/money": "^4.6", "moneyphp/money": "^4.6",
"phpmailer/phpmailer": "^6.9" "phpmailer/phpmailer": "^6.9",
"filips123/monolog-phpmailer": "^2.0"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {

View file

@ -88,6 +88,13 @@ function setupLogger($logFilePath, $channelName = 'app') {
function archiveOldLogs($logFilePath) { function archiveOldLogs($logFilePath) {
$logDir = dirname($logFilePath); $logDir = dirname($logFilePath);
$backupDir = '/opt/backup'; $backupDir = '/opt/backup';
$lockFile = $backupDir . '/log_archive.lock';
// Prevent multiple processes from running archive at the same time
if (file_exists($lockFile)) {
return; // Another process is already archiving
}
touch($lockFile); // Create lock file
if (!is_dir($backupDir)) { if (!is_dir($backupDir)) {
mkdir($backupDir, 0755, true); mkdir($backupDir, 0755, true);
@ -105,12 +112,16 @@ function archiveOldLogs($logFilePath) {
// Open or create ZIP archive // Open or create ZIP archive
$zip = new ZipArchive(); $zip = new ZipArchive();
if ($zip->open($zipPath, ZipArchive::CREATE) === true) { if ($zip->open($zipPath, ZipArchive::CREATE) === true) {
$zip->addFile($file, $filename); if (!$zip->locateName($filename)) { // Prevent duplicate addition
$zip->addFile($file, $filename);
unlink($file); // Delete original log after archiving
}
$zip->close(); $zip->close();
unlink($file); // Delete original log after archiving
} }
} }
} }
unlink($lockFile); // Remove lock when done
} }
function isIpWhitelisted($ip, $pdo) { function isIpWhitelisted($ip, $pdo) {

View file

@ -99,6 +99,13 @@ function setupLogger($logFilePath, $channelName = 'app') {
function archiveOldLogs($logFilePath) { function archiveOldLogs($logFilePath) {
$logDir = dirname($logFilePath); $logDir = dirname($logFilePath);
$backupDir = '/opt/backup'; $backupDir = '/opt/backup';
$lockFile = $backupDir . '/log_archive.lock';
// Prevent multiple processes from running archive at the same time
if (file_exists($lockFile)) {
return; // Another process is already archiving
}
touch($lockFile); // Create lock file
if (!is_dir($backupDir)) { if (!is_dir($backupDir)) {
mkdir($backupDir, 0755, true); mkdir($backupDir, 0755, true);
@ -116,12 +123,16 @@ function archiveOldLogs($logFilePath) {
// Open or create ZIP archive // Open or create ZIP archive
$zip = new ZipArchive(); $zip = new ZipArchive();
if ($zip->open($zipPath, ZipArchive::CREATE) === true) { if ($zip->open($zipPath, ZipArchive::CREATE) === true) {
$zip->addFile($file, $filename); if (!$zip->locateName($filename)) { // Prevent duplicate addition
$zip->addFile($file, $filename);
unlink($file); // Delete original log after archiving
}
$zip->close(); $zip->close();
unlink($file); // Delete original log after archiving
} }
} }
} }
unlink($lockFile); // Remove lock when done
} }
function checkLogin($db, $clID, $pw) { function checkLogin($db, $clID, $pw) {

View file

@ -88,6 +88,13 @@ function setupLogger($logFilePath, $channelName = 'app') {
function archiveOldLogs($logFilePath) { function archiveOldLogs($logFilePath) {
$logDir = dirname($logFilePath); $logDir = dirname($logFilePath);
$backupDir = '/opt/backup'; $backupDir = '/opt/backup';
$lockFile = $backupDir . '/log_archive.lock';
// Prevent multiple processes from running archive at the same time
if (file_exists($lockFile)) {
return; // Another process is already archiving
}
touch($lockFile); // Create lock file
if (!is_dir($backupDir)) { if (!is_dir($backupDir)) {
mkdir($backupDir, 0755, true); mkdir($backupDir, 0755, true);
@ -105,12 +112,16 @@ function archiveOldLogs($logFilePath) {
// Open or create ZIP archive // Open or create ZIP archive
$zip = new ZipArchive(); $zip = new ZipArchive();
if ($zip->open($zipPath, ZipArchive::CREATE) === true) { if ($zip->open($zipPath, ZipArchive::CREATE) === true) {
$zip->addFile($file, $filename); if (!$zip->locateName($filename)) { // Prevent duplicate addition
$zip->addFile($file, $filename);
unlink($file); // Delete original log after archiving
}
$zip->close(); $zip->close();
unlink($file); // Delete original log after archiving
} }
} }
} }
unlink($lockFile); // Remove lock when done
} }
function mapContactToVCard($contactDetails, $role, $c) { function mapContactToVCard($contactDetails, $role, $c) {

View file

@ -88,6 +88,13 @@ function setupLogger($logFilePath, $channelName = 'app') {
function archiveOldLogs($logFilePath) { function archiveOldLogs($logFilePath) {
$logDir = dirname($logFilePath); $logDir = dirname($logFilePath);
$backupDir = '/opt/backup'; $backupDir = '/opt/backup';
$lockFile = $backupDir . '/log_archive.lock';
// Prevent multiple processes from running archive at the same time
if (file_exists($lockFile)) {
return; // Another process is already archiving
}
touch($lockFile); // Create lock file
if (!is_dir($backupDir)) { if (!is_dir($backupDir)) {
mkdir($backupDir, 0755, true); mkdir($backupDir, 0755, true);
@ -105,12 +112,16 @@ function archiveOldLogs($logFilePath) {
// Open or create ZIP archive // Open or create ZIP archive
$zip = new ZipArchive(); $zip = new ZipArchive();
if ($zip->open($zipPath, ZipArchive::CREATE) === true) { if ($zip->open($zipPath, ZipArchive::CREATE) === true) {
$zip->addFile($file, $filename); if (!$zip->locateName($filename)) { // Prevent duplicate addition
$zip->addFile($file, $filename);
unlink($file); // Delete original log after archiving
}
$zip->close(); $zip->close();
unlink($file); // Delete original log after archiving
} }
} }
} }
unlink($lockFile); // Remove lock when done
} }
function parseQuery($data) { function parseQuery($data) {