Blazor WASM anbinden
In einer Blazor-WebAssembly-Oberfläche gibt es kein FMH-Layout und damit kein fmh-web-log. An seine Stelle tritt FMH.Komponente.Serilog.Sinks.Blazor.WASM — ein Serilog-Sink, der im Browser läuft und an denselben Endpunkt sendet.
Im Repo gibt es keine Blazor-WASM-Anwendung. Diese Anleitung beschreibt die Einbindung in ein eigenes Projekt; die gezeigten Aufrufe sind durch die Tests des Pakets abgedeckt.
Paket
<ItemGroup>
<ProjectReference Include="..\FMH.Komponente.Serilog.Sinks.Blazor.WASM\FMH.Komponente.Serilog.Sinks.Blazor.WASM.csproj" />
</ItemGroup>
Das Paket bringt Serilog, Serilog.Formatting.Compact und Serilog.Sinks.PeriodicBatching mit.
Einrichten
In Program.cs der WASM-Anwendung, vor await builder.Build().RunAsync():
using FMH.Komponente.Serilog.Sinks.Blazor.WASM;
using Serilog;
var httpClient = new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) };
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.Enrich.WithProperty("App", "Meine.Wasm.Anwendung")
.WriteTo.BrowserHttp(httpClient)
.CreateLogger();
Danach steht der übliche Serilog-Weg offen:
Log.Information("Benutzer {benutzerId} hat das Formular geöffnet", benutzerId);
Die BaseAddress ist Pflicht
Der Standard-Endpunkt heisst siwflog — relativ, ohne führenden Schrägstrich. Er wird gegen die BaseAddress des HttpClient aufgelöst. Fehlt sie, wirft der erste Versand eine InvalidOperationException.
Das ist der Unterschied zu fmh-web-log, das /siwflog absolut verwendet. Beide landen bei der Standardkonfiguration am selben Ort; wer EndpointPath auf dem Server ändert, muss aber an beide Seiten denken.
Parameter
.WriteTo.BrowserHttp(
httpClient,
endpointUrl: "siwflog",
restrictedToMinimumLevel: LevelAlias.Minimum,
batchPostingLimit: 1000,
period: TimeSpan.FromSeconds(2),
eventBodyLimitBytes: 256 * 1024,
controlLevelSwitch: null,
queueSizeLimit: 100000)
| Parameter | Standard | Wirkung |
|---|---|---|
endpointUrl |
siwflog |
Zieladresse, relativ zur BaseAddress |
restrictedToMinimumLevel |
Verbose |
Filter vor dem Sink |
batchPostingLimit |
1000 | Ereignisse je Anfrage |
period |
2 Sekunden | Abstand zwischen zwei Anfragen |
eventBodyLimitBytes |
262144 | Obergrenze je Ereignis, gemessen in Bytes (UTF-8). Zu grosse Ereignisse werden einzeln verworfen und über SelfLog gemeldet — der Rest des Stapels geht durch. |
controlLevelSwitch |
null |
Schalter, den der Server steuern darf (siehe unten) |
queueSizeLimit |
100000 | Grösse der Warteschlange. Ein negativer Wert wird abgewiesen. |
Es gibt eine zweite Überladung ohne HttpClient: Sie legt selbst einen an und gibt ihn beim Entsorgen wieder frei. Dann lassen sich zusätzlich messageHandler und defaultRequestHeaders mitgeben — Letzteres etwa für einen Mandanten-Header. Ohne eigenen HttpClient fehlt allerdings die BaseAddress; in dem Fall muss endpointUrl absolut sein.
Der Server darf das Level absenken
Setzt die Ingestion-Middleware ein ClientLevelSwitch, antwortet sie mit dem akzeptierten Mindestlevel:
{"MinimumLevelAccepted":"Warning"}
Der Sink liest das aus und schaltet den übergebenen controlLevelSwitch entsprechend. Damit lässt sich die Gesprächigkeit aller Browser zentral drosseln, ohne die Anwendung neu auszuliefern:
var serverSchalter = new LoggingLevelSwitch();
Log.Logger = new LoggerConfiguration()
.MinimumLevel.ControlledBy(serverSchalter)
.WriteTo.BrowserHttp(httpClient, controlLevelSwitch: serverSchalter)
.CreateLogger();
Gibt der Server die Steuerung wieder ab (Antwort ohne diese Angabe), stellt der Sink das ursprüngliche Level wieder her.
Damit das greift, muss derselbe Schalter über MinimumLevel.ControlledBy(...) an der Pipeline hängen — der Sink filtert nicht selbst.
Fehlerverhalten
Antwortet der Server nicht mit 2xx, wirft der Sink eine LoggingFailedException. Das ist Absicht: Der umschliessende PeriodicBatchingSink fängt sie ab und wiederholt den Stapel mit wachsendem Abstand. Einen eigenen Wiederholungsmechanismus gibt es im Sink nicht.
Anders als fmh-web-log hält der Sink keinen Offline-Puffer über einen Seitenwechsel hinweg — die Warteschlange lebt nur im Arbeitsspeicher.
Zum Schluss der Anwendung sollte der Puffer geleert werden:
Log.CloseAndFlush();