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
This commit is contained in:
2025-11-02 01:37:49 +01:00
parent 2defdf2baf
commit cf0ad6e905
23 changed files with 612 additions and 556 deletions

View File

@@ -28,16 +28,91 @@ final readonly class StackFrame implements \JsonSerializable
*/
public static function fromArray(array $frame): self
{
// Bereinige Args, um nicht-serialisierbare Objekte zu entfernen
$args = isset($frame['args']) ? self::sanitizeArgs($frame['args']) : [];
return new self(
file: $frame['file'] ?? 'unknown',
line: $frame['line'] ?? 0,
function: $frame['function'] ?? null,
class: $frame['class'] ?? null,
type: $frame['type'] ?? null,
args: $frame['args'] ?? []
args: $args
);
}
/**
* Bereinigt Args, um nicht-serialisierbare Objekte (wie ReflectionClass) zu entfernen
*
* @param array<int, mixed> $args
* @return array<int, mixed>
*/
private static function sanitizeArgs(array $args): array
{
return array_map(
fn($arg) => self::sanitizeValue($arg),
$args
);
}
/**
* Bereinigt einzelnen Wert, entfernt nicht-serialisierbare Objekte
*/
private static function sanitizeValue(mixed $value): mixed
{
// Closures können nicht serialisiert werden
if ($value instanceof \Closure) {
// Versuche ReflectionFunction zu verwenden, um Closure-Details zu bekommen
try {
$reflection = new \ReflectionFunction($value);
$file = $reflection->getFileName();
$line = $reflection->getStartLine();
return sprintf('Closure(%s:%d)', basename($file), $line);
} catch (\Throwable) {
return 'Closure';
}
}
// Reflection-Objekte können nicht serialisiert werden
if (is_object($value)) {
$className = get_class($value);
if ($value instanceof \ReflectionClass
|| $value instanceof \ReflectionMethod
|| $value instanceof \ReflectionProperty
|| $value instanceof \ReflectionFunction
|| $value instanceof \ReflectionParameter
|| $value instanceof \ReflectionType
|| str_starts_with($className, 'Reflection')) {
// Ersetze durch String-Repräsentation
return sprintf('ReflectionObject(%s)', $className);
}
// Anonyme Klassen können auch Probleme verursachen
if (str_contains($className, '@anonymous')) {
// Versuche den Parent-Type zu extrahieren
$parentClass = get_parent_class($value);
if ($parentClass !== false) {
return sprintf('Anonymous(%s)', $parentClass);
}
return 'Anonymous';
}
// Andere Objekte durch Klassenname ersetzen
return $className;
}
// Arrays rekursiv bereinigen
if (is_array($value)) {
return array_map(
fn($item) => self::sanitizeValue($item),
$value
);
}
// Primitives bleiben unverändert
return $value;
}
/**
* Gibt Kurzform des File-Pfads zurück (relativ zum Project Root wenn möglich)
*/
@@ -131,24 +206,26 @@ final readonly class StackFrame implements \JsonSerializable
/**
* Serialisiert Arguments für Log-Ausgabe
*
* Note: Args sind bereits beim Erstellen bereinigt, aber für toArray()
* formatieren wir sie nochmal kompakter.
*
* @return array<int, mixed>
*/
private function serializeArgs(): array
{
return array_map(
fn($arg) => $this->serializeValue($arg),
fn($arg) => $this->formatValueForOutput($arg),
$this->args
);
}
/**
* Serialisiert einzelnen Wert (verhindert zu große Ausgaben)
* Formatiert Wert für Log-Ausgabe (kompaktere Darstellung)
*/
private function serializeValue(mixed $value): mixed
private function formatValueForOutput(mixed $value): mixed
{
return match (true) {
is_object($value) => get_class($value),
is_array($value) => sprintf('array(%d)', count($value)),
is_resource($value) => sprintf('resource(%s)', get_resource_type($value)),
is_string($value) && strlen($value) > 100 => substr($value, 0, 100) . '...',