Files
michaelschiemer/src/Framework/Logging/Handlers/JsonFileHandler.php
Michael Schiemer cf0ad6e905 refactor: improve logging system and add deployment fixes
- Enhance logging handlers (Console, DockerJson, File, JsonFile, MultiFile)
- Improve exception and line formatters
- Update logger initialization and processor management
- Add Ansible playbooks for staging 502 error troubleshooting
- Update deployment documentation
- Fix serializer and queue components
- Update error kernel and queued log handler
2025-11-02 01:37:49 +01:00

159 lines
4.4 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Framework\Logging\Handlers;
use App\Framework\Config\Environment;
use App\Framework\Core\PathProvider;
use App\Framework\Logging\LogHandler;
use App\Framework\Logging\Formatter\JsonFormatter;
use App\Framework\Logging\Formatter\LogFormatter;
use App\Framework\Logging\LogLevel;
use App\Framework\Logging\LogRecord;
/**
* Handler für die Ausgabe von Log-Einträgen als JSON in Dateien.
* Besonders nützlich für maschinelle Verarbeitung und Log-Aggregatoren.
*
* Nutzt JsonFormatter für einheitliche JSON-Ausgabe.
*
* Standard-Felder für Log-Aggregatoren:
* - @timestamp: Elasticsearch-konformes Zeitstempelfeld
* - severity: RFC 5424 Severity Level (0-7)
* - environment: Deployment-Umgebung (production, staging, development)
* - host: Server-Hostname
* - service: Service-/Anwendungsname
*/
class JsonFileHandler implements LogHandler
{
/**
* @var LogLevel Minimales Level, ab dem dieser Handler aktiv wird
*/
private LogLevel $minLevel;
/**
* @var string Pfad zur Log-Datei
*/
private string $logFile;
/**
* @var JsonFormatter Formatter für die JSON-Ausgabe
*/
private JsonFormatter $formatter;
/**
* @var PathProvider|null PathProvider für die Auflösung von Pfaden
*/
private ?PathProvider $pathProvider = null;
/**
* Erstellt einen neuen JsonFileHandler
*
* @param JsonFormatter $formatter Formatter für die JSON-Ausgabe
* @param string $logFile Pfad zur Log-Datei
* @param LogLevel|int $minLevel Minimales Level, ab dem dieser Handler aktiv wird
* @param PathProvider|null $pathProvider Optional: PathProvider für die Auflösung von Pfaden
*/
public function __construct(
JsonFormatter $formatter,
string $logFile,
LogLevel|int $minLevel = LogLevel::INFO,
?PathProvider $pathProvider = null
) {
$this->pathProvider = $pathProvider;
$this->formatter = $formatter;
// Pfad auflösen, falls PathProvider vorhanden
if ($this->pathProvider !== null && ! str_starts_with($logFile, '/')) {
$logFile = $this->pathProvider->resolvePath($logFile);
}
$this->logFile = $logFile;
$this->minLevel = $minLevel instanceof LogLevel ? $minLevel : LogLevel::fromValue($minLevel);
// Stelle sicher, dass das Verzeichnis existiert
$this->ensureDirectoryExists(dirname($logFile));
}
/**
* Überprüft, ob dieser Handler den Log-Eintrag verarbeiten soll
*/
public function isHandling(LogRecord $record): bool
{
return $record->getLevel()->value >= $this->minLevel->value;
}
/**
* Verarbeitet einen Log-Eintrag
*/
public function handle(LogRecord $record): void
{
// Formatter verwenden für JSON-Formatierung
$json = ($this->formatter)($record);
// JsonFormatter gibt immer string zurück
$output = is_string($json) ? $json : json_encode($json, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
// Stelle sicher, dass ein Newline vorhanden ist
if (!str_ends_with($output, PHP_EOL)) {
$output .= PHP_EOL;
}
$this->write($output);
}
/**
* Gibt den Formatter zurück
*/
public function getFormatter(): LogFormatter
{
return $this->formatter;
}
/**
* Schreibt einen String in die Log-Datei
*/
protected function write(string $output): void
{
file_put_contents($this->logFile, $output, FILE_APPEND);
}
/**
* Stellt sicher, dass ein Verzeichnis existiert
*/
private function ensureDirectoryExists(string $dir): void
{
if (! file_exists($dir)) {
mkdir($dir, 0777, true);
}
}
/**
* Minimales Log-Level setzen
*/
public function setMinLevel(LogLevel|int $level): self
{
$this->minLevel = $level instanceof LogLevel ? $level : LogLevel::fromValue($level);
return $this;
}
/**
* Log-Datei setzen
*/
public function setLogFile(string $logFile): self
{
// Pfad auflösen, falls PathProvider vorhanden
if ($this->pathProvider !== null && ! str_starts_with($logFile, '/')) {
$logFile = $this->pathProvider->resolvePath($logFile);
}
$this->logFile = $logFile;
$this->ensureDirectoryExists(dirname($logFile));
return $this;
}
}