Files
adminandClaude Opus 5 cbc9353f0a Protokollseite: die Logs der Hintergrundprozesse im Dashboard
Bisher kam man an die Ausgabe von solarManager.py, dem Runner und den
uebrigen Dauerprozessen nur per SSH heran. Die neue Seite unter
"Protokolle" zeigt sie: links die fuenf Dateien mit Groesse und Alter -
eine, die seit Tagen nicht gewachsen ist, faellt so auf, ohne dass man sie
oeffnet -, rechts die Zeilen mit Volltextsuche, Level-Filter und
optionalem Nachladen.

Nicht in die Datenbank geschrieben, obwohl das naheliegt: ein Log muss
genau dann noch funktionieren, wenn die Datenbank es nicht tut. Ein
Handler, der nach MySQL schreibt, verschluckt ausgerechnet die Meldung
"Datenbank nicht erreichbar" - also die, wegen der man nachsieht. Was
strukturiert ausgewertet werden soll, steht ohnehin in automation_log.

Gelesen wird rueckwaerts in Bloecken: 5000 Zeilen aus der 329 MB grossen
Datei der Wallbox kosten 46 ms, weil nur das Ende angefasst wird. Sucht
man ins Leere, bricht der Server nach 4 MB ab und sagt es auch.

Die beiden Prozesse formatieren unterschiedlich - der eine stellt das
Level voran, der andere den Zeitstempel -, deshalb wird beides gesucht
statt an fester Stelle erwartet. Zeilen ohne eigenes Level erben das der
Zeile darueber, sonst filterte "nur Fehler" die Tracebacks weg, die den
Fehler erklaeren.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 19:26:56 +02:00

126 lines
4.7 KiB
PHP

<?php
/**
* Logseite: hineinsehen, was die Hintergrundprozesse melden.
*
* Links die Dateien mit ihrem Zustand, rechts die Zeilen. Der Zustand ist
* mehr als Schmuck: ein Prozess, dessen Datei seit Tagen nicht gewachsen
* ist, faellt hier auf, ohne dass man sie oeffnet.
*
* Gelesen wird ueber ajax/logs.php, gezeichnet in js/solar/logs.js. Die
* erste Liste steht schon im Dokument, damit die Seite nicht leer aufgeht
* und man beim langsamen Zugriff von unterwegs sofort sieht, was es gibt.
*/
require_once(__DIR__ . "/logdateien.php");
$dateien = [];
$fehler = "";
try {
foreach (array_keys(logDateien()) as $key) {
$dateien[] = logZustand($key);
}
} catch (Throwable $e) {
$fehler = $e->getMessage();
}
?>
<!--begin::App Main-->
<main class="app-main">
<!--begin::App Content Header-->
<div class="app-content-header">
<div class="container-fluid">
<div class="row">
<div class="col-sm-12">
<h3 class="mb-0">Protokolle</h3>
</div>
</div>
</div>
</div>
<!--end::App Content Header-->
<!--begin::App Content-->
<div class="app-content">
<div class="container-fluid">
<?php if ($fehler): ?>
<div class="alert alert-danger">Die Protokolle sind nicht erreichbar: <?= htmlspecialchars($fehler) ?></div>
<?php endif; ?>
<div class="row">
<!-- Dateiliste -->
<div class="col-12 col-lg-3">
<div class="card mb-4">
<div class="card-header pb-2 pt-2">
<h3 class="card-title"><i class="bi bi-journal-text me-2"></i>Prozesse</h3>
<div class="card-tools">
<button type="button" class="btn btn-tool log-zustand-neu" title="Zustand neu einlesen">
<i class="bi bi-arrow-clockwise"></i>
</button>
</div>
</div>
<div class="card-body p-0">
<div class="list-group list-group-flush log-liste"></div>
</div>
</div>
</div>
<!-- Zeilen -->
<div class="col-12 col-lg-9">
<div class="card mb-4">
<div class="card-header pb-2 pt-2">
<h3 class="card-title">
<i class="bi bi-terminal me-2"></i><span class="log-titel">Protokoll</span>
</h3>
<div class="card-tools">
<span class="log-stand small text-secondary me-2"></span>
<button type="button" class="btn btn-tool log-neu" title="Neu laden">
<i class="bi bi-arrow-clockwise"></i>
</button>
</div>
</div>
<div class="card-body pb-2">
<div class="row g-2 align-items-center mb-3">
<div class="col-12 col-md-4">
<div class="input-group input-group-sm">
<span class="input-group-text"><i class="bi bi-search"></i></span>
<input type="search" class="form-control log-suche" placeholder="Text enthält …">
</div>
</div>
<div class="col-6 col-md-3">
<select class="form-select form-select-sm log-level">
<option value="">alle Meldungen</option>
<option value="INFO">ab Info</option>
<option value="WARNING">ab Warnung</option>
<option value="ERROR">nur Fehler</option>
</select>
</div>
<div class="col-6 col-md-2">
<select class="form-select form-select-sm log-anzahl">
<option value="100">100 Zeilen</option>
<option value="300" selected>300 Zeilen</option>
<option value="1000">1000 Zeilen</option>
<option value="5000">5000 Zeilen</option>
</select>
</div>
<div class="col-12 col-md-3">
<div class="form-check form-switch mb-0">
<input class="form-check-input log-folgen" type="checkbox" id="logFolgen">
<label class="form-check-label small" for="logFolgen">alle 10 s nachladen</label>
</div>
</div>
</div>
<div class="log-hinweis small text-secondary mb-2"></div>
<div class="log-ausgabe"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<!--end::App Content-->
</main>
<!--end::App Main-->
<script>
// Zustand der Dateien beim Seitenaufbau. Die Zeilen selbst holt das Skript
// nach - sie sind das Grosse, und welche Datei zuerst gezeigt wird, weiss
// erst der Browser (er merkt sich die zuletzt gewaehlte).
const logDateienStand = <?= json_encode($dateien, JSON_UNESCAPED_UNICODE) ?>;
</script>