Server einrichten
So ist Serilog in dieser Anwendung (FMH.Komponente.WebUI) konfiguriert — die Ausschnitte stammen unverändert aus Program.cs, appsettings.json und der Projektdatei.
Pakete
<ItemGroup>
<PackageReference Include="Serilog.AspNetCore" />
<PackageReference Include="Serilog.Enrichers.ClientInfo" />
<PackageReference Include="Serilog.Settings.Configuration" />
<PackageReference Include="Serilog.Sinks.Seq" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FMH.Komponente.Serilog.Ingestion\FMH.Komponente.Serilog.Ingestion.csproj" />
</ItemGroup>
| Paket | Wofür |
|---|---|
Serilog.AspNetCore |
UseSerilog am Host, Request-Logging, Console-Sink |
Serilog.Settings.Configuration |
ReadFrom.Configuration(...) — der Serilog-Abschnitt der appsettings |
Serilog.Sinks.Seq |
Zielsystem Seq |
Serilog.Enrichers.ClientInfo |
WithClientIp() und WithRequestHeader(...) |
FMH.Komponente.Serilog.Ingestion |
der Endpunkt /siwflog für die Browser-Meldungen |
Die Versionen stehen zentral in Directory.Packages.props; im Projekt wird nur der Paketname angegeben.
Schritt 1: Serilog als Logging-Pipeline
builder.Host.UseSerilog((context, services, config) => config.Enrich.WithRequestHeader("User-Agent")
.Enrich.WithClientIp()
.ReadFrom.Configuration(configuration)
.WriteTo.Console(theme: ConsoleTheme.None));
ReadFrom.Configuration holt Mindestlevel, feste Eigenschaften und Sinks aus den appsettings; WriteTo.Console kommt zusätzlich im Code dazu, damit auch ohne Seq etwas sichtbar ist.
Schritt 2: den Endpunkt für den Browser öffnen
Das ist der Schritt, der am leichtesten vergessen wird:
using FMH.Komponente.Serilog.Ingestion;
var app = builder.Build();
app.UseSiwfLogIngestion();
Ohne app.UseSiwfLogIngestion() protokolliert der Server unverändert weiter — aber POST /siwflog läuft ins Leere und jede Meldung aus dem Browser geht verloren. Der Fehler ist still: es gibt keine Ausnahme, nur fehlende Einträge.
Die Erweiterungsmethode liegt im Namespace FMH.Komponente.Serilog.Ingestion.
Wo in der Pipeline
In dieser Anwendung steht der Aufruf direkt nach builder.Build() und damit vor UseHeaderSecurity, UseHttpsRedirection, UseRouting und UseAuthorization. Zwei Folgen, die man kennen sollte:
- Der Endpunkt ist anonym erreichbar. Wer das nicht will, verschiebt den Aufruf hinter
UseAuthorization— dann muss der Browser allerdings authentifiziert sein, bevor er etwas melden darf. - Er ist nicht geroutet. Die Middleware vergleicht den Pfad selbst und reicht alles Übrige weiter.
Schritt 3: appsettings
"Serilog": {
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft": "Error"
}
},
"Properties": {
"Release": "0.0.0.0-development",
"App": "FMH.Komponente.WebUI"
},
"WriteTo": [
{
"Name": "Seq",
"Args": {
"ServerUrl": "http://127.0.0.1:5341",
"ApiKey": ""
}
}
]
}
Properties landet an jedem Ereignis — so lassen sich in Seq mehrere Anwendungen und Releases auseinanderhalten. Der Sink wird über seinen Namen gefunden; ein Using-Abschnitt ist nicht nötig, solange das Sink-Paket referenziert ist.
Der klassische Logging:LogLevel-Abschnitt steht in dieser Anwendung noch daneben, wirkt neben Serilog aber praktisch nicht mehr.
Optionen der Ingestion-Middleware
UseSiwfLogIngestion() kommt hier ohne Argumente aus. Alle Werte lassen sich über ein Lambda setzen:
app.UseSiwfLogIngestion(optionen =>
{
optionen.EndpointPath = "/protokoll";
optionen.EventBodyLimitBytes = 256 * 1024;
optionen.ClientLevelSwitch = new LoggingLevelSwitch(LogEventLevel.Warning);
});
| Option | Standard | Wirkung |
|---|---|---|
EndpointPath |
/siwflog |
Der Pfad, auf den die Middleware hört. Exakter Vergleich — /siwflog/ oder /siwflog/mehr treffen nicht. Wird er geändert, muss auch der Client umgestellt werden. |
Logger |
Log.Logger |
Ziel-Logger. Ohne Angabe der globale Logger; deshalb muss UseSerilog vorher laufen. |
OriginPropertyName |
Origin |
Jedes Ereignis wird mit Origin = "Client" angereichert. Schickt der Browser die Eigenschaft selbst mit, wird sie verworfen — die Herkunft lässt sich nicht fälschen. null schaltet die Markierung ab. |
EventBodyLimitBytes |
null |
Obergrenze je Zeile. Standard ist unbegrenzt — für einen öffentlich erreichbaren Endpunkt einen Wert setzen. Zu lange Zeilen werden einzeln verworfen und über SelfLog gemeldet. |
ClientLevelSwitch |
null |
Filtert eingehende Ereignisse und schickt das akzeptierte Mindestlevel in der Antwort zurück. Nur der WASM-Sink wertet diesen Rückkanal aus. |
Was der Endpunkt antwortet
- Erfolg:
201 Created, ohne Inhalt. - Mit
ClientLevelSwitch:201und im Rumpf{"MinimumLevelAccepted":"Warning"}. - Eine defekte Zeile im Stapel wird übersprungen und über
SelfLoggemeldet; die übrigen Ereignisse des Stapels kommen trotzdem an, die Antwort bleibt201.
Fehler beim Verarbeiten werden also bewusst nicht an den Browser zurückgemeldet — Logging darf die Anwendung nicht stören. Wer beim Einrichten prüfen will, ob wirklich etwas ankommt, schaltet Serilog.Debugging.SelfLog ein:
Serilog.Debugging.SelfLog.Enable(Console.Error);