Non puoi selezionare più di 25 argomenti
Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
231 righe
7.1 KiB
231 righe
7.1 KiB
<?php |
|
|
|
/** |
|
* Gestore delle deleghe ANAC NPA |
|
*/ |
|
trait NpaLogger |
|
{ |
|
public bool $disableLogs = false; |
|
|
|
/** |
|
* Ottiene il path per i log atomici |
|
* |
|
* @param boolean $create Se true e il path non esiste, viene creato |
|
* @return string Ritorna il path in questions |
|
*/ |
|
private function getAtomicLogPath(bool $create = false): string |
|
{ |
|
global $config; |
|
|
|
$fascicolo = $this->fascicolo["codice"] ?? 0; |
|
$scheda = $this->scheda["codice"] ?? 0; |
|
|
|
$subPath = "{$fascicolo}"; |
|
if ($scheda > 0) { |
|
$subPath .= "/{$scheda}"; |
|
} |
|
|
|
|
|
$domain = $_SESSION["ente"]->getInfo()["dominio"] ?? "global"; |
|
$folder = "{$config["npaFolder"]}/smartLog/{$domain}/{$subPath}"; |
|
|
|
if ($create) { |
|
if (!file_exists($folder)) |
|
mkdir($folder, 0777, true); |
|
} |
|
|
|
return $folder; |
|
} |
|
|
|
/** |
|
* Ottiene i log disponibili per questa scheda o fascicolo |
|
* |
|
* @return array ["endpoint::method" => "filename"] |
|
*/ |
|
public function getAvailableLogs(): array |
|
{ |
|
$filePath = $this->getAtomicLogPath(); |
|
if(!file_exists($filePath)) return []; |
|
$scan = scandir($filePath); |
|
|
|
$retval = []; |
|
foreach ($scan as $file) { |
|
if (is_dir("{$filePath}/$file")) continue; |
|
$file = explode(".", $file)[0]; |
|
$friendlyName = str_replace("_", "::", $file); |
|
$retval[$friendlyName] = $file; |
|
} |
|
|
|
if(!empty($retval)) { |
|
$retval["Tutti i log"] = "combined"; |
|
} |
|
return $retval; |
|
} |
|
|
|
/** |
|
* Aggiunge un nuovo log |
|
* |
|
* @param string $endpoint Endpoint di riferimento |
|
* @param string $method Metodo di riferimento |
|
* @param array $data Dati da loggare |
|
* @param string|null $error Errore, se presente, da loggare |
|
* @return void |
|
*/ |
|
public function appendLog(string $endpoint, string $method, array $data, ?string $error = null): void |
|
{ |
|
if ($this->disableLogs) return; |
|
|
|
if ($error) |
|
$data["error"] = $error; |
|
|
|
foreach ($data as $name => $entry) { |
|
if (is_string($entry)) { |
|
if ($name === "request") { |
|
preg_match_all("/(^.*(GovWay|Agid|Authorization|GET \/|Host:|HTTP\/).*$)/m", $entry, $matches); |
|
$data[$name] = implode("\n", $matches[0] ?? []); |
|
} elseif (valid_json($entry, $rawEntry, true)) { |
|
$data[$name] = $rawEntry; |
|
} |
|
} |
|
} |
|
// Log consultabili |
|
$filePath = $this->getAtomicLogPath(true) . "/{$endpoint}_{$method}.gz"; |
|
|
|
$data["_datetime"] = (new \DateTime())->format(DateTime::ATOM); |
|
$jsonData = json_encode($data) . "\n"; |
|
|
|
$fp = fopen("compress.zlib://{$filePath}", 'ab'); |
|
if ($fp) { |
|
fwrite($fp, $jsonData); |
|
fclose($fp); |
|
} else { |
|
throw new Exception("Impossibile scrivere sui log."); |
|
} |
|
|
|
// Log legacy per archivio |
|
global $config; |
|
$domain = $_SESSION["ente"]->getInfo()["dominio"] ?? "global"; |
|
$filename = date('Ymd') . ".log"; |
|
$npaFolder = $config["npaFolder"] . "/" . $domain; |
|
if (!is_dir($npaFolder)) { |
|
mkdir($npaFolder, 0755, true); |
|
} |
|
$legacyLog = "[" . date('Y-m-d H:i:s') . "]" . PHP_EOL; |
|
$legacyLog .= "\tURL: {$endpoint}::{$method}" . PHP_EOL; |
|
foreach ($data as $name => $entry) { |
|
if ($name[0] === "_") continue; |
|
$legacyLog .= "\t" . substr(strtoupper($name), 0, 3) . ": " . ($name === "request" ? base64_encode($entry) : json_encode($entry)) . PHP_EOL; |
|
} |
|
|
|
error_log($legacyLog . PHP_EOL, 3, "{$npaFolder}/{$filename}"); |
|
} |
|
|
|
/** |
|
* Ruota i log di piattaforma |
|
* |
|
* @return void |
|
*/ |
|
public static function rotateLogs() |
|
{ |
|
if (!defined("__CMDS_JOB_EXEC")) { |
|
return; |
|
} |
|
global $config; |
|
|
|
// Elimina i log più vecchi di 3 mesi |
|
$smartLogFolder = "{$config["npaFolder"]}/smartLog"; |
|
$it = new RecursiveDirectoryIterator($smartLogFolder); |
|
|
|
|
|
$toDelete = []; |
|
foreach (new RecursiveIteratorIterator($it) as $file) { |
|
if ($file->getExtension() == 'gz') { |
|
if ($file->getmTime() < (time() - (90 * 24 * 60 * 60))) { |
|
$toDelete[] = $file->getPathname(); |
|
} |
|
} |
|
} |
|
|
|
|
|
// Comprime i vecchi log legacy |
|
|
|
$today = date('Ymd'); |
|
$it = new RecursiveDirectoryIterator($config["npaFolder"]); |
|
|
|
foreach (new RecursiveIteratorIterator($it) as $file) { |
|
if ($file->getExtension() == 'log') { |
|
if ($file->getBasename() !== "{$today}.log") { |
|
exec("cd {$file->getPath()} && tar -czvf \"{$file->getBasename()}.tar.gz\" \"{$file->getFilename()}\""); |
|
$toDelete[] = $file->getPathname(); |
|
} |
|
} |
|
} |
|
|
|
foreach(array_unique($toDelete) as $filePath) { |
|
try{ |
|
unlink($filePath); |
|
} catch(\Exception $e) { |
|
alertManager::printCliAlert("Impossibile eliminare il file '{$filePath}'"); |
|
alertManager::printCliException($e); |
|
} |
|
} |
|
|
|
|
|
} |
|
|
|
/** |
|
* Ottiene i log da un file dei log atomici |
|
* |
|
* @param string $path Path da caricare |
|
* @return array Ritorna un array con le entry di log |
|
*/ |
|
public function retrieveLogs(string $requestedPath): array |
|
{ |
|
if($requestedPath === "combined") { |
|
$filePath = $this->getAtomicLogPath(); |
|
if(!file_exists($filePath)) return []; |
|
$scan = scandir($filePath); |
|
|
|
$entries = []; |
|
foreach ($scan as $file) { |
|
if(str_ends_with($file, ".gz")) { |
|
$logs = $this->retrieveLogs(str_replace(".gz", "", $file)); |
|
foreach($logs as &$entry) { |
|
$entry = array_merge(["file" => $file], $entry); |
|
} |
|
$entries = array_merge($entries, $logs); |
|
} |
|
} |
|
usort($entries, function($a, $b) { |
|
return $a["_datetime"] < $b["_datetime"]; |
|
}); |
|
|
|
return $entries; |
|
} |
|
$logFolder = $this->getAtomicLogPath(); |
|
// Preveniamo directory trasversal |
|
$realBase = realpath($logFolder); |
|
|
|
$browsingPath = $logFolder . "/" . ltrim($requestedPath, "/") . ".gz" ; |
|
$browsingPath = realpath($browsingPath); |
|
|
|
if ($browsingPath === false || strpos($browsingPath, $realBase) !== 0) { |
|
// Path non valido |
|
$requestedPath = ""; |
|
$browsingPath = $logFolder; |
|
} |
|
$requestedPath = substr($browsingPath, strlen($logFolder)); |
|
|
|
|
|
|
|
$data = []; |
|
$fp = fopen("compress.zlib://{$browsingPath}", 'rb'); |
|
if ($fp) { |
|
while (($line = fgets($fp)) !== false) { |
|
$data[] = json_decode($line, true); |
|
} |
|
fclose($fp); |
|
} |
|
return array_reverse($data); |
|
} |
|
}
|
|
|