Logging im Browser
Das Modul fmh-web-log aus dem Paket Basis protokolliert aus dem Browser heraus an den Endpunkt /siwflog. Es ist über das Layout bereits eingebunden — es gibt nichts zu registrieren.
Einbindung
_HeadIncludes.cshtml der Basis lädt das Modul, sobald das Layout BasisAssetKonstanten.HeadIncludes rendert:
<link rel="modulepreload" href="/_content/FMH.Komponente.Basis/fmh-web-log/index.js"/>
<script type="module" async src="/_content/FMH.Komponente.Basis/fmh-web-log/index.js" asp-append-version="true"></script>
Es ist ein natives ES-Modul ohne Build-Schritt und läuft deshalb bewusst nicht über den WebOptimizer: das Bundling versteht import/export nicht.
Daneben existiert wwwroot/js/fmh-web-log.js. Diese Datei ist nur ein Shim für Altprojekte, die noch ein klassisches <script src="…"> verwenden; sie lädt index.js per dynamischem import() nach. In neuen Projekten wird sie nicht gebraucht.
Verwenden
Beim Laden des Moduls entsteht window.log — eine Init-Funktion gibt es nicht:
window.log.info("Benutzer {BenutzerId} hat das Formular geöffnet", benutzerId);
window.log.warn("Für den Upload wurde keine Id zurückgegeben. Initiere Reload");
window.log.error("Fehler beim Abrufen der Einstellungen {@Exception}", e);
Die Meldungen sind Serilog-Vorlagen, keine fertigen Zeichenketten: Die benannten Platzhalter werden als eigene Eigenschaften übertragen und lassen sich in Seq einzeln durchsuchen. {@…} serialisiert ein Objekt.
Verfügbare Stufen — verbose, debug, info, warn, error, fatal.
Was automatisch protokolliert wird
Ohne eigenes Zutun meldet das Modul:
- unbehandelte Fehler über
window.onerror, - nicht behandelte Promise-Ablehnungen über
window.onunhandledrejection, - jeden Aufruf von
console.error(die Funktion wird dafür umschlossen).
Bekannte Infrastruktur-Fälle — etwa die anonyme Meldung "Script Error." eines Contentblockers — werden dabei als Warnung statt als Fehler eingestuft, damit sie die echten Fehler nicht überdecken.
Jedes Ereignis trägt zusätzlich ScreenSize, Url und einen Hash der Meldung.
Versand und Offline-Verhalten
| Verhalten | Standard |
|---|---|
| Stapelgrösse | 10 Ereignisse |
| Wartezeit bis zum Senden | 3 Sekunden |
| Zeitlimit je Anfrage | 5 Sekunden |
| Erneuter Versuch nach Fehler | 120 Sekunden |
| Zwischenspeicher | localStorage, bis 2000 Einträge |
Gesendet wird als POST mit Content-Type: application/vnd.serilog.clef, eine JSON-Zeile je Ereignis. Ist der Browser offline oder antwortet der Server nicht mit 2xx, wandern die Ereignisse zurück in den Zwischenspeicher und werden später erneut versucht — auch über einen Seitenwechsel hinweg. Gleiche Meldungen werden dabei zusammengefasst und gezählt, statt den Speicher zu fluten.
Eigene Einstellungen
Für den Regelfall ist nichts zu tun. Soll das Mindestlevel angehoben oder eine störende Meldung unterdrückt werden:
window.log.setOptions({
level: 3000, // erst ab Information senden
disallow: "^Heartbeat" // regulärer Ausdruck auf die Meldungsvorlage
});
Die Stufen sind Verbose 1000, Debug 2000, Information 3000, Warning 4000, Error 5000, Fatal 6000; voreingestellt ist 1000, es wird also alles gesendet.
Für einen abweichenden Endpunkt oder andere Stapelgrössen wird der Appender selbst ausgetauscht:
import { SerilogAppender } from '/_content/FMH.Komponente.Basis/fmh-web-log/appender/SerilogAppender.js';
window.log.setOptions({
appenders: [new SerilogAppender('Client', '/protokoll', {}, { batchSize: 25 })]
});
Zwischenspeicher des Browsers
Das Modul besteht aus mehreren Dateien, die index.js per import nachlädt. asp-append-version versioniert aber nur die Adresse der Einstiegsdatei — die importierten Dateien holt der Browser über ihren unveränderten Pfad und würde sie beliebig lange aus dem Zwischenspeicher bedienen.
Deshalb setzt Program.cs für alle Anfragen, deren Pfad fmh-web-log enthält, einen Revalidierungs-Header:
app.UseStaticFiles(
new StaticFileOptions
{
OnPrepareResponse = context =>
{
if (context.Context.Request.Path.Value?.Contains(
"fmh-web-log",
StringComparison.OrdinalIgnoreCase) == true)
{
context.Context.Response.Headers[HeaderNames.CacheControl] = "no-cache, must-revalidate";
}
},
});
Der Browser darf die Dateien weiterhin behalten, muss sie aber bei jedem Laden gegen den ETag prüfen: unverändert kostet das ein 304, geändert kommt sofort die neue Fassung an. Dieser Block gehört in jede Anwendung, die das Modul verwendet — sonst kommen Änderungen unvorhersehbar spät beim Benutzer an.
Zu beachten
log.enrichWithProperty(...)existiert, tut aber nichts — die Methode hat einen leeren Rumpf. Eigenschaften an jedem Ereignis setzt man über die Vorlage oder, für Microsoft Clarity, über die globale VariableclarityProperties.- Der Endpunkt ist im Client als
/siwflogabsolut verdrahtet. WerEndpointPathauf dem Server ändert, muss den Appender wie oben austauschen.