Emergency layer logs fatal errors to var/log/notfall.log and answers 503. The system page checks for a new release on load, shows its notes, runs backup, download, switch, migration and health check in one flow with live progress, and switches back automatically when the new version fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
51 lines
2.3 KiB
PHP
51 lines
2.3 KiB
PHP
<?php
|
|
|
|
namespace App\EventSubscriber;
|
|
|
|
use App\Ops\Notfall;
|
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
|
|
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
|
|
use Symfony\Component\HttpKernel\KernelEvents;
|
|
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
|
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
|
use Symfony\Component\Security\Core\Exception\LogoutException;
|
|
|
|
/**
|
|
* Jeder Serverfehler, den das Framework abfängt, steht auch in var/log/notfall.log (ADR 113).
|
|
*
|
|
* Ohne das gab es auf dem Hosting kein eigenes Protokoll: Symfony schreibt nach stderr, und das
|
|
* landet - wenn überhaupt - im Fehlerlog des Hostings, das ein Betreiber erst suchen muss. 404 und
|
|
* andere gewollte Antworten gehören nicht hinein. Die Antwort selbst wird zur Wartungsseite.
|
|
*/
|
|
final class ErrorLogSubscriber implements EventSubscriberInterface
|
|
{
|
|
public function __construct(private bool $debug = false)
|
|
{
|
|
}
|
|
|
|
public static function getSubscribedEvents(): array
|
|
{
|
|
// Nach der Sicherheitsschicht (Priorität 1): „Zugriff verweigert“ ist dort eine
|
|
// Weiterleitung zur Anmeldung, kein Notfall. Vor der Fehlerseite des Frameworks (-128),
|
|
// damit der Eintrag auch dann entsteht, wenn sie selbst scheitert.
|
|
return [KernelEvents::EXCEPTION => ['onException', -64]];
|
|
}
|
|
|
|
public function onException(ExceptionEvent $event): void
|
|
{
|
|
$fehler = $event->getThrowable();
|
|
if ($event->hasResponse() || $fehler instanceof AuthenticationException || $fehler instanceof AccessDeniedException || $fehler instanceof LogoutException
|
|
|| ($fehler instanceof HttpExceptionInterface && $fehler->getStatusCode() < 500)) {
|
|
return;
|
|
}
|
|
Notfall::protokollieren($fehler, $event->getRequest()->getMethod().' '.$event->getRequest()->getRequestUri());
|
|
// Besucher sehen statt einer englischen „Oops“-Seite die Wartungsseite mit 503: für
|
|
// Suchmaschinen „gleich wieder da“. Im Entwicklungsmodus bleibt die ausführliche Seite.
|
|
if (!$this->debug) {
|
|
$event->setResponse(new Response(Notfall::html(), Response::HTTP_SERVICE_UNAVAILABLE, Notfall::KOPFZEILEN));
|
|
}
|
|
}
|
|
}
|