This is a viewer only at the moment see the article on how this works.
To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk
This is a preview from the server running through my markdig pipeline
Loggning är OF KURS en kritisk del av applikationer men jag ser ofta att det missförstås / missbrukas i ASP.NET applikationer. Detta är delpost och delmanifest om hur man effektivt loggar in ASP.NET program.
Detta är inte en komplett guide till loggning; det finns LOTS av dem där ute; det handlar mer om att välja en effektiv loggningsstrategi för dina ASP.NET-program.
I huvudsak loggning bör vara ANVÄNDBAR; vare sig det är loggning medan du utvecklar eller loggar in produktion bör det vara användbart för dig / ditt team / dina användare.
Alltför ofta ses loggning som "bara göra det när det finns undantag". Jag tror att detta missförstår vad avverkning bör vara.
LÖSNING ÄR INTE bara FÖR UNDANTAG
I allmänhet bör du kunna köra en betydande del av din ansökan lokalt; i detta sammanhang log.LogInformation
är din vän.
Under de 30 år jag har skrivit kod har jag sett några exempel på bra loggning och sätt fler exempel på dålig loggning.
Principer för god avverkning:
Kom ihåg; loggning drar ALLTID ner din programprestanda; du bör logga vad du behöver för att diagnostisera ett problem men inte mer i produktion / där prestanda är kritisk (t.ex., kör inte ett prestandatest när du använder full Debug Logging).
I ASP.NET har du redan en build in Loging System; Microsoft.Extensions.Logging
....................................... Detta är ett bra loggsystem, men det är inte lika flexibelt som Serilog. Serilog är ett mer flexibelt loggsystem som gör att du kan logga till flera sänkor (utgångar) och berika dina loggar med ytterligare information.
Detta är loggningen som sker när din ansökan startar. Det är det första som händer, och det är det första du ska se när du kör din ansökan. I ASP.NET speciellt när du använder konfiguration är det viktigt att du förstår vad som händer när din ansökan startar. Det är en super gemensam källa till problem i ASP.NET-applikationer.
Till exempel i Serilog kan du göra detta:
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.WriteTo.File("logs/boot-*.txt", rollingInterval: RollingInterval.Day, retainedFileCountLimit: 7)
.CreateBootstrapLogger();
OBS: Detta är begränsat eftersom du inte har tillgång till konfigurationen vid denna punkt så till exempel att använda AppInsights du sannolikt behöver en #if RELEASE
block för att ställa in lämplig nyckel.
Vad detta gör är att ge dig data om eventuella startproblem i din ansökan; det skriver både till konsol och till en fil. Det är också viktigt att se till att du inte sparar ALLA loggfiler; du kan se här sparar vi bara 7 dagars loggar.
Du kommer också att vilja avsluta din start metod (i denna app använder jag den nya Program.cs
metod) i ett försök/fånga och logga eventuella undantag som händer där.
try
{
..all your startup code
}
catch (Exception ex)
{
if(args.Contains("migrate"))
{
Log.Information("Migration complete");
return;
}
Log.Fatal(ex, "Application terminated unexpectedly");
}
finally
{
Log.CloseAndFlush();
}
Log.CloseAndFlush () är viktigt eftersom det säkerställer att alla loggar skrivs till disk (din app kraschar så annars kommer den att avsluta innan den gör detta).
Här upptäcker jag också om appen körs i ett migreringsläge och i så fall loggar jag det och avslutar.
Log.Fatal
är den allvarligaste loggnivån; den används när programmet är på väg att krascha.
Alla undantag är inte ödesdigra - du bör använda Log.Error
För sådana (om de inte avser APP (inte begäran) kan inte fortsätta förbi denna punkt).
I ASP.NET (och.NET Mer allmänt) har du ett antal loggnivåer:
Log.Fatal
- Detta är den allvarligaste loggnivån; det används när din ansökan är på väg att krascha.Log.Error
- Detta används när ett undantag inträffar som innebär att APP (inte begäran) inte kan fortsätta förbi den punkten.Log.Warning
- Detta används när något händer som inte är ett fel men är något du bör vara medveten om (till exempel en skadad tjänst / något inte helt rätt men inte ett fel.Log.Information
- Detta används för allmän information om vad som händer i din ansökan.Log.Debug
- Detta används för information som bara är användbar när du debuggar din applikation (det är ALLA under utveckling men bör stängas av i produktionen).För produktion skulle jag i allmänhet ställa in loggningen att vara Log.Fatal
, Log.Error
och Log.Warning
Endast.
I motsats till startloggning är detta loggningen som sker när programmet körs. Detta är loggningen som berättar vad som händer i din ansökan vid varje given tidpunkt.
Till exempel för att använda dessa i Serilog du skulle göra detta:
"Serilog": {
"Enrich": ["FromLogContext", "WithThreadId", "WithThreadName", "WithProcessId", "WithProcessName", "FromLogContext"],
"MinimumLevel": "Warning",
"WriteTo": [
{
"Name": "Seq",
"Args":
{
"serverUrl": "http://seq:5341",
"apiKey": ""
}
},
{
"Name": "Console"
},
{
"Name": "File",
"Args": {
"path": "logs/applog-.txt",
"rollingInterval": "Day"
}
}
],
"Properties": {
"ApplicationName": "mostlylucid"
}
},
Som ni ser är jag ett ganska stort fan av Serilog; det är ett bra loggbibliotek som är mycket flexibelt. En av de saker jag gillar med det är förmågan att berika dina loggar med ytterligare information. Detta kan vara mycket användbart för att diagnostisera problem i din ansökan. I ovanstående exempel kan du se att jag berikar mina loggar med tråd-ID, trådnamn, process-ID och processnamn. Detta kan vara mycket användbart för att diagnostisera problem i din ansökan.
Jag ställer också in loggningen att gå till flera'sänkor' (utmatningar); i detta fall skickar jag den till konsolen, till en fil och till Seq (en loggningstjänst).
Att ha flera diskbänkar är praktiskt om man misslyckas, i detta fall min föredragna loggning tjänst är Seq, så jag skickar det dit först. Om det misslyckas skickar jag det till konsolen och till en fil.
Jag ställer också in egenskapen ApplicationName i loggarna; detta kan vara användbart om du har flera program loggning till samma tjänst (som för distribuerade program du ofta kommer att; tillsammans med en korrelation ID att knyta ihop loggarna för en enda begäran).
Till exempel om du har en JS-front och en.NET-backend kan du ställa in korrelations-ID i den främre änden och skicka det till backend. Detta gör att du kan se alla loggar för en enda begäran på ett ställe. ELLER om du använder HtttpClient i ditt gränssnitt kan du skicka korrelations-ID i rubrikerna till den andra tjänsten.
Det finns stor täckning om hur du kan göra detta här: https://josef.codes/append-correlation-id-to-all-log-entries-in-asp-net-core/ men jag kommer att täcka det i ett kommande inlägg.
Strukturerad loggning är ett sätt att logga som gör det lättare att söka och filtrera dina loggar. I Serilog kan du göra detta genom att använda Log.Information("This is a log message with {Property1} and {Property2}", property1, property2);
Syntax. Detta gör det lättare att söka efter loggar med en viss egenskap.
Med hjälp av Serilog kan du också använda LogContext.PushProperty
att lägga till egenskaper till dina loggar som endast är relevanta för en viss omfattning. Detta kan vara mycket användbart för att diagnostisera problem i din ansökan.
Serilog är superflexibel på så sätt att det gör att du kan konfigurera den i kod såväl som genom konfiguration. Till exempel för att använda konfigurationen ovan skulle du göra detta:
builder.Host.UseSerilog((context, services, configuration) =>
{
configuration
.MinimumLevel.Warning()
.Enrich.FromLogContext()
.Enrich.WithThreadId()
.Enrich.WithThreadName()
.Enrich.WithProcessId()
.Enrich.WithProcessName()
.WriteTo.Seq("http://seq:5341", apiKey: "")
.WriteTo.Console()
.WriteTo.File("logs/applog-.txt", rollingInterval: RollingInterval.Day)
.Enrich.WithProperty("ApplicationName", "mostlylucid");
});
Detta är samma som konfigurationen ovan men i kod. Detta är användbart om du vill ställa in din inloggningskod; det är verkligen upp till dig hur du gör det.
I ASP.NET kan du använda Exception Filters för att fånga undantag och logga in dem. Detta är ett bra sätt att se till att du loggar alla undantag i din ansökan. Hur som helst är det inte en ersättning för metodnivå loggning; du bör fortfarande logga på metodnivå så att du kan se vad som händer i din ansökan i detalj; Undantagsfiltret visar bara vad som händer när hela begäran stacken har blivit osårbar och kan ofta vara mycket förvirrande att räkna ut vad som har hänt.
Detta ändrades i ASP.NET Core 8 och det finns ett TON du kan göra med dessa nya funktioner.
Fel igen samma principer gäller; du bör logga på metodnivå så att du kan se vad som händer i din ansökan i detalj; Undantagsfilter / statushanterare visar bara vad som händer när hela begäran stacken har blivit osårbar och kan ofta vara mycket förvirrande att räkna ut vad som har hänt.
Loggning bör vara lämplig för miljön; i utveckling du loggar allt så att du kan se vad som händer vid varje punkt i din ansökan men i Test du behöver mindre loggning (kanske logginformation här) och i produktion du behöver ännu mindre (Varning och ovan).
Det är frestande att logga allt i produktionen, men det är en dålig idé. Du bör logga allt du behöver för att diagnostisera ett problem men inte längre. I molnleverantörer kan du enkelt få betalt för den mängd data du skickar till loggtjänsten så du bör vara försiktig med vad du loggar och hur länge du behåller dessa loggar (Application Insights lagrar loggar för 90 dagar som standard; detta är ofta för lång tid och kommer att kosta dig så länge som loggdata lagras).
För en mycket "aktiv" app du bara inte behöver långsiktig loggning av den data; du har en bra uppfattning om vad som händer i appen från de senaste dagarna av loggar.
När den vanliga frågan jag ser i produktionen är loggning misslyckade förfrågningar; även om dessa kan vara intressant (ingen vill ha en 404 / 401) dessa kan vara en enorm mängd data och kan vara mycket dyrt att lagra. Du bör bara logga saker du har för avsikt att fixa, för en 404 kan det vara så att detta är viktigt eftersom det kan indikera en bruten länk i din ansökan; för en 401 kan det vara så att detta är viktigt eftersom det kan indikera ett trasigt autentiseringssystem.
SOM jag nämnde ovan hanteras dessa bättre i koden de faktiskt sker i (i fallet med 401); det kan vara så att dessa också ska loggas som en Warning
eller Error
i den kod som faktiskt genererar 401.
För att ställa in Begär Loggning i Serilog kan du göra detta:
app.UseSerilogRequestLogging();
Detta kommer att logga alla förfrågningar till din ansökan; det är ett bra sätt att se vad som händer i din ansökan på en hög nivå; men återigen bör du vara försiktig med vad du loggar och hur länge du behåller dessa loggar för.
För Application Insights kan du fortfarande vilja logga med hjälp av Informationsnivå eftersom det kommer att ge dig nifty User Journey funktionen; Detta är ett bra sätt att se hur användare använder din ansökan och kan vara mycket användbart för att diagnostisera problem; dock igen dessa snabbt rack upp kostnader så du bör vara försiktig med vad du loggar och hur länge du behåller dessa loggar för.
Så det är det, en snabb genomgång av hur man loggar in ASP.NET program. Mycket av det är en reaktion på övernitiska, värdelösa stockar jag ser i många produktionsapplikationer. I utvecklingen vill du se hur appen körs; i produktionen vill du se hur appen misslyckas. Loggning är alltför ofta en värdelös, dyr del av applikationsutveckling. Som med allt i programvaruutveckling loggning bör fokuseras på användaren; oavsett om det är du / andra utvecklare medan du arbetar på appen i din IDE / lokalt eller reda ut problem i produktionen snabbt och effektivt.