Tracking: Improve logs rotation in LoginAttemptLogger, set max logs to 90 (days) - refs #3810 BT#18167

pull/5203/head
Yannick Warnier 9 months ago
parent 873933b01a
commit 21ed7a7290
  1. 74
      src/CoreBundle/ServiceHelper/LoginAttemptLogger.php

@ -7,16 +7,20 @@ namespace Chamilo\CoreBundle\ServiceHelper;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use DateTime;
use SplFileObject;
class LoginAttemptLogger
{
private string $logDir;
private TranslatorInterface $translator;
private int $maxLogs;
public function __construct(KernelInterface $kernel, TranslatorInterface $translator)
{
$this->logDir = $kernel->getLogDir() . '/ids';
$this->translator = $translator;
$this->maxLogs = 90; // for how many iterations to keep log files
if (!is_dir($this->logDir)) {
mkdir($this->logDir, 0777, true);
@ -31,15 +35,17 @@ class LoginAttemptLogger
}
$date = new DateTime();
$logFilePrefix = $logDir . '/ids-' . $date->format('Y-m-d');
$logFilePrefix = $logDir . '/ids';
$logFile = $logFilePrefix . '.log';
if (file_exists($logFile) && $date->format('Y-m-d') !== date('Y-m-d', filemtime($logFile))) {
$counter = 1;
while (file_exists($logFilePrefix . '.' . $counter . '.log')) {
$counter++;
// Most of the time, there will be a previous log file
if (file_exists($logFile)) {
// Read the last line of the existing log file to determine if we need rotation
$lastLine = $this->_readLastLine($logFile);
if (!$this->_checkDateIsToday($lastLine)) {
// The last line's date is not today, so we need to rotate
$this->_rotateLogFiles($logFile, $this->maxLogs);
}
rename($logFile, $logFilePrefix . '.' . $counter . '.log');
}
$statusText = $this->translator->trans($status ? 'succeeded' : 'failed');
@ -57,4 +63,60 @@ class LoginAttemptLogger
file_put_contents($logFile, $logMessage, FILE_APPEND | LOCK_EX);
}
/**
* Efficiently read the last line of the provided file, or an empty string
* @param string $logFilePath
* @return string
*/
private function _readLastLine(string $logFilePath): string
{
$fileObject = new SplFileObject($logFilePath, 'r');
$fileObject->seek(PHP_INT_MAX);
$fileObject->seek($fileObject->key() - 1);
$line = $fileObject->current();
if (empty($line)) {
return '';
}
return $line;
}
/**
* Check if the date in a log line is same as today
* @param string $line A line of type "[2024-03-01 09:44:57] [info] [client 127.0.0.1] Some text"
*/
private function _checkDateIsToday(string $line): bool
{
$date = new DateTime();
$today = $date->format('Y-m-d');
$matches = [];
if (!empty($line) && preg_match('/\[(\d{4}-\d{2}-\d{2})\s.*/', $line, $matches)) {
if (0 === strcmp($matches[1], $today)) {
return true;
}
}
return false;
}
/**
* Rotate log files
* @param string $baseLogFile
* @param int $maxLogs
* @return void
*/
private function _rotateLogFiles(string $baseLogFile, int $maxLogs): void
{
for ($i = $maxLogs; $i > 0; $i--) {
$oldLog = $baseLogFile.'.'.$i;
$newLog = $baseLogFile.'.'.($i + 1);
if (file_exists($oldLog)) {
if (file_exists($newLog)) {
unlink($newLog);
}
rename($oldLog, $newLog);
}
}
rename($baseLogFile, $baseLogFile.'.1');
}
}

Loading…
Cancel
Save