Naplózás C# és .NET nyelven
A .NET támogatja a nagy teljesítményű, strukturált naplózást az API-n keresztül az ILogger alkalmazások viselkedésének monitorozásához és a problémák diagnosztizálásához. A naplók különböző célhelyekre írhatók különböző naplózási szolgáltatók konfigurálásával. Az alapszintű naplózási szolgáltatók beépítettek, és számos külső szolgáltató is elérhető.
Első lépések
Ez az első példa az alapokat mutatja be, de csak triviális konzolalkalmazásokhoz alkalmas. Ez a minta konzolalkalmazás a következő NuGet-csomagokra támaszkodik:
A következő szakaszban láthatja, hogyan javíthatja a kódot a skálázás, a teljesítmény, a konfiguráció és a tipikus programozási minták figyelembe vételével.
using Microsoft.Extensions.Logging;
using ILoggerFactory factory = LoggerFactory.Create(builder => builder.AddConsole());
ILogger logger = factory.CreateLogger("Program");
logger.LogInformation("Hello World! Logging is {Description}.", "fun");
Az előző példa:
- Létrehoz egy ILoggerFactory. A
ILoggerFactory
rendszer tárolja az összes konfigurációt, amely meghatározza a naplóüzenetek küldésének helyét. Ebben az esetben úgy konfigurálja a konzol naplózási szolgáltatóját , hogy a rendszer a naplóüzeneteket a konzolra írja. - Létrehoz egy ILogger "Program" nevű kategóriát. A kategória az
string
objektum általILogger
naplózott összes üzenethez társított kategória. A naplók keresésekor vagy szűrésekor egy osztályból (vagy kategóriából) származó naplóüzenetek csoportosítására szolgál. - Az üzenet naplózására vonatkozó hívások LogInformation a
Information
szinten. A naplószint a naplózott esemény súlyosságát jelzi, és a kevésbé fontos naplóüzenetek kiszűrésére szolgál. A naplóbejegyzés tartalmaz egy üzenetsablont"Hello World! Logging is {Description}."
és egy kulcs-érték párotDescription = fun
is. A kulcs neve (vagy helyőrzője) a sablon kapcsos zárójeleiben lévő szóból származik, az érték pedig a fennmaradó metódusargumentumból származik.
A példához tartozó projektfájl két NuGet-csomagot tartalmaz:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.1" />
</ItemGroup>
</Project>
Tipp.
Az összes naplózási példa forráskódja letölthető a Mintaböngészőben . További információ: Kódminták tallózása: Naplózás a .NET-ben.
Bejelentkezés nem triviális alkalmazásba
Az előző példában több módosítást is érdemes megfontolni, ha kevésbé triviális forgatókönyvben jelentkezik be:
Ha az alkalmazás függőséginjektálást (DI) vagy gazdagépet, például ASP-t használ. A NET WebApplication-jét vagy általános gazdagépét ezután a saját DI-tárolóikból kell használnia
ILoggerFactory
ésILogger
objektumait használnia ahelyett, hogy közvetlenül létrehozták volna őket. További információ: Integráció a diával és a gazdagépekkel.A fordítási idő forrásának naplózása általában jobb alternatíva az olyan bővítménymetelyek helyett,
ILogger
mint aLogInformation
. A naplózási forrás létrehozása jobb teljesítményt, erősebb gépelést biztosít, és elkerüli az állandók terjesztésétstring
a metódusokban. A kompromisszum az, hogy ennek a technikának a használata egy kicsit több kódot igényel.
using Microsoft.Extensions.Logging;
internal partial class Program
{
static void Main(string[] args)
{
using ILoggerFactory factory = LoggerFactory.Create(builder => builder.AddConsole());
ILogger logger = factory.CreateLogger("Program");
LogStartupMessage(logger, "fun");
}
[LoggerMessage(Level = LogLevel.Information, Message = "Hello World! Logging is {Description}.")]
static partial void LogStartupMessage(ILogger logger, string description);
}
- A naplókategória-nevek ajánlott eljárása a naplóüzenetet létrehozó osztály teljes neve. Ez segít visszakonfigurálni a naplóüzeneteket a létrehozott kódhoz, és jó szintű ellenőrzést biztosít a naplók szűrése során. CreateLogger elfogadja a
Type
, hogy ez az elnevezés könnyen elvégezhető.
using Microsoft.Extensions.Logging;
internal class Program
{
static void Main(string[] args)
{
using ILoggerFactory factory = LoggerFactory.Create(builder => builder.AddConsole());
ILogger logger = factory.CreateLogger<Program>();
logger.LogInformation("Hello World! Logging is {Description}.", "fun");
}
}
- Ha nem a konzolnaplókat használja egyetlen éles monitorozási megoldásként, vegye fel a használni kívánt naplózási szolgáltatókat . Az OpenTelemetry használatával például naplókat küldhet otLP-n keresztül (OpenTelemetry protocol):
using Microsoft.Extensions.Logging;
using OpenTelemetry.Logs;
using ILoggerFactory factory = LoggerFactory.Create(builder =>
{
builder.AddOpenTelemetry(logging =>
{
logging.AddOtlpExporter();
});
});
ILogger logger = factory.CreateLogger("Program");
logger.LogInformation("Hello World! Logging is {Description}.", "fun");
Integráció gazdagépekkel és függőséginjektálással
Ha az alkalmazás függőséginjektálást (DI) vagy gazdagépet, például ASP-t használ. A NET WebApplication-jét vagy az Általános gazdagépet ezután a DI-tárolóban kell használnia ILoggerFactory
és ILogger
objektumokat használnia ahelyett, hogy közvetlenül létrehozta volna őket.
ILogger lekérése a DI-ből
Ez a példa lekéri egy ILogger-objektumot egy üzemeltetett alkalmazásban ASP.NET Minimális API-k használatával:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<ExampleHandler>();
var app = builder.Build();
var handler = app.Services.GetRequiredService<ExampleHandler>();
app.MapGet("/", handler.HandleRequest);
app.Run();
partial class ExampleHandler(ILogger<ExampleHandler> logger)
{
public string HandleRequest()
{
LogHandleRequest(logger);
return "Hello World";
}
[LoggerMessage(LogLevel.Information, "ExampleHandler.HandleRequest was called")]
public static partial void LogHandleRequest(ILogger logger);
}
Az előző példa:
- Létrehozott egy singleton szolgáltatást, amely meghívta
ExampleHandler
és leképezte a bejövő webes kéréseket aExampleHandler.HandleRequest
függvény futtatásához. - A 8. sor meghatározza az ExampleHandler elsődleges konstruktorát , amely a C# 12-ben hozzáadott funkció. A régebbi stílusú C# konstruktor ugyanolyan jól működik, de egy kicsit részletesebb.
- A konstruktor egy típusparamétert
ILogger<ExampleHandler>
határoz meg. ILogger<TCategoryName> származik ILogger , és jelzi, hogy az objektum melyik kategóriávalILogger
rendelkezik. A DI-tároló megkeres egyILogger
megfelelő kategóriát, és konstruktor argumentumként adja meg. Ha még nincsILogger
ilyen kategória, a DI-tároló automatikusan létrehozza azt aILoggerFactory
szolgáltatóból. - A
logger
konstruktorban kapott paramétert a függvénybenHandleRequest
való naplózáshoz használtuk.
Gazdagép által biztosított ILoggerFactory
A gazdagépkészítők inicializálják az alapértelmezett konfigurációt, majd a gazdagép létrehozásakor hozzáadnak egy konfigurált ILoggerFactory
objektumot a gazdagép DI-tárolójába. A gazdagép létrehozása előtt módosíthatja a naplózási konfigurációt más WebApplicationBuilder.Logginggazdagépeken, vagy hasonló API-k használatávalHostApplicationBuilder.Logging. A gazdagépek az alapértelmezett konfigurációs forrásokból származó naplózási konfigurációt is alkalmazzák appsettings.json és környezeti változókként. További információ: Konfiguráció a .NET-ben.
Ez a példa az előzőre bontva testre szabja a ILoggerFactory
megadottt WebApplicationBuilder
. OpenTelemetryt ad hozzá naplózási szolgáltatóként, amely a naplókat otLP-n (OpenTelemetry protokollon) keresztül továbbítja:
var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddOpenTelemetry(logging => logging.AddOtlpExporter());
builder.Services.AddSingleton<ExampleHandler>();
var app = builder.Build();
ILoggerFactory létrehozása diával
Ha gazdagép nélküli DI-tárolót használ, konfigurálhatja AddLogging és hozzáadhatja ILoggerFactory
a tárolót.
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
// Add services to the container including logging
var services = new ServiceCollection();
services.AddLogging(builder => builder.AddConsole());
services.AddSingleton<ExampleService>();
IServiceProvider serviceProvider = services.BuildServiceProvider();
// Get the ExampleService object from the container
ExampleService service = serviceProvider.GetRequiredService<ExampleService>();
// Do some pretend work
service.DoSomeWork(10, 20);
class ExampleService(ILogger<ExampleService> logger)
{
public void DoSomeWork(int x, int y)
{
logger.LogInformation("DoSomeWork was called. x={X}, y={Y}", x, y);
}
}
Az előző példa:
- Létrehozott egy di-szolgáltatástárolót
ILoggerFactory
, amely a konzolra való írásra van konfigurálva - Egyetlentonnát
ExampleService
adott hozzá a tárolóhoz - Létrehozott egy példányt a
ExampleService
DI-tárolóból, amely automatikusan létrehozott egyILogger<ExampleService>
konstruktor argumentumként használandó példányt is. - Meghívva
ExampleService.DoSomeWork
, amely azILogger<ExampleService>
üzenet konzolra való naplózására szolgál.
Naplózás konfigurálása
A naplózási konfiguráció kódban vagy külső forrásokon, például konfigurációs fájlokon és környezeti változókon keresztül van beállítva. A külső konfiguráció használata előnyös, ha lehetséges, mert az alkalmazás újraépítése nélkül módosítható. Egyes feladatok, például a naplózási szolgáltatók beállítása azonban csak kódból konfigurálhatók.
Naplózás konfigurálása kód nélkül
Gazdagépet használó alkalmazások esetében a naplózási konfigurációt általában az "Logging"
appsettings.{Environment}
.json fájlok szakasza biztosítja. A gazdagépet nem használó alkalmazások esetében a külső konfigurációs források explicit módon vannak beállítva, vagy kódban vannak konfigurálva.
Az alábbi appsettings. Development.json fájlt a .NET-feldolgozó szolgáltatássablonjai generálják:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
A fenti JSON-ban:
- A
"Default"
,"Microsoft"
és"Microsoft.Hosting.Lifetime"
a naplószintű kategóriák meg vannak adva. - Az
"Default"
érték minden olyan kategóriára vonatkozik, amely egyébként nincs megadva, így gyakorlatilag az összes alapértelmezett érték az összes kategóriára érvényes"Information"
. Ezt a viselkedést felülbírálhatja egy kategória értékének megadásával. - A
"Microsoft"
kategória az összes olyan kategóriára vonatkozik, amely a következővel"Microsoft"
kezdődik: . - A
"Microsoft"
kategórianaplók naplózásiWarning
szintje magasabb és magasabb. - A
"Microsoft.Hosting.Lifetime"
kategória pontosabb, mint a"Microsoft"
kategória, ezért a"Microsoft.Hosting.Lifetime"
kategória naplók szintjén és magasabb szinten"Information"
naplóz. - Nincs megadva egy adott naplószolgáltató, ezért
LogLevel
a Windows EventLog kivételével az összes engedélyezett naplózási szolgáltatóra vonatkozik.
A Logging
tulajdonság rendelkezhet LogLevel és naplózhatja a szolgáltató tulajdonságait. A LogLevel
megadott kategóriák naplózásának minimális szintjét adja meg. Az előző JSON-ban Information
és Warning
a naplószintek meg vannak adva. LogLevel
A napló súlyosságát jelzi, és 0 és 6 közötti tartományt jelöl:
Trace
= 0, Debug
= 1, Information
= 2, Warning
= 3, Error
= 4, Critical
= 5 és None
= 6.
Ha meg van adva, LogLevel
a naplózás engedélyezve van a megadott szinten és magasabb szinten lévő üzenetekhez. Az előző JSON-ban a Default
kategória naplózása és magasabb szintű naplózása Information
történik. A rendszer például naplózza az Information
Warning
Error
Critical
üzeneteket. Ha nincs LogLevel
megadva, a naplózás alapértelmezés szerint a Information
szintre kerül. További információ: Naplószintek.
A szolgáltatói tulajdonság megadhat egy tulajdonságot LogLevel
. LogLevel
egy szolgáltatónál megadja az adott szolgáltatóhoz naplózni kívánt szinteket, és felülbírálja a nem szolgáltatói naplóbeállításokat. Vegye figyelembe a következő appsettings.json fájlt:
{
"Logging": {
"LogLevel": {
"Default": "Error",
"Microsoft": "Warning"
},
"Debug": {
"LogLevel": {
"Default": "Information",
"Microsoft.Hosting": "Trace"
}
},
"EventSource": {
"LogLevel": {
"Default": "Warning"
}
}
}
}
Beállítások a Logging.{ProviderName}.LogLevel
felülbírálási beállításokban a következőben Logging.LogLevel
: . Az előző JSON-ban a Debug
szolgáltató alapértelmezett naplószintje a következőre Information
van állítva:
Logging:Debug:LogLevel:Default:Information
Az előző beállítás minden Information
kategória naplószintét Logging:Debug:
adja meg, kivéve Microsoft.Hosting
. Ha egy adott kategória szerepel a listában, az adott kategória felülírja az alapértelmezett kategóriát. Az előző JSON-ban a Logging:Debug:LogLevel
kategóriák "Microsoft.Hosting"
és "Default"
a beállítások felülbírálása a következő helyen: Logging:LogLevel
A minimális naplószint az alábbiak bármelyikéhez megadható:
- Konkrét szolgáltatók: Például:
Logging:EventSource:LogLevel:Default:Information
- Konkrét kategóriák: Például:
Logging:LogLevel:Microsoft:Warning
- Minden szolgáltató és minden kategória:
Logging:LogLevel:Default:Warning
A minimális szint alatti naplók nem:
- Átadva a szolgáltatónak.
- Naplózott vagy megjelenített.
Az összes napló letiltásához adja meg a LogLevel.None értéket. LogLevel.None
értéke 6, ami magasabb, mint LogLevel.Critical
(5).
Ha egy szolgáltató támogatja a napló hatóköreit, jelzi, IncludeScopes
hogy engedélyezve vannak-e. További információ: naplóhatókörök
Az alábbi appsettings.json fájl az összes beépített szolgáltató beállításait tartalmazza:
{
"Logging": {
"LogLevel": {
"Default": "Error",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Warning"
},
"Debug": {
"LogLevel": {
"Default": "Information"
}
},
"Console": {
"IncludeScopes": true,
"LogLevel": {
"Microsoft.Extensions.Hosting": "Warning",
"Default": "Information"
}
},
"EventSource": {
"LogLevel": {
"Microsoft": "Information"
}
},
"EventLog": {
"LogLevel": {
"Microsoft": "Information"
}
},
"AzureAppServicesFile": {
"IncludeScopes": true,
"LogLevel": {
"Default": "Warning"
}
},
"AzureAppServicesBlob": {
"IncludeScopes": true,
"LogLevel": {
"Microsoft": "Information"
}
},
"ApplicationInsights": {
"LogLevel": {
"Default": "Information"
}
}
}
}
Az előző példában:
- A kategóriák és szintek nem javasolt értékek. A minta az összes alapértelmezett szolgáltató megjelenítésére szolgál.
- Beállítások a
Logging.{ProviderName}.LogLevel
felülbírálási beállításokban a következőbenLogging.LogLevel
: . A benne lévőDebug.LogLevel.Default
szint például felülbírálja a szintet a következőbenLogLevel.Default
: . - A rendszer minden szolgáltató aliasát használja. Minden szolgáltató meghatároz egy aliast, amely a konfigurációban használható a teljes típusnév helyett. A beépített szolgáltatók aliasai a következők:
Console
Debug
EventSource
EventLog
AzureAppServicesFile
AzureAppServicesBlob
ApplicationInsights
Naplószint beállítása parancssor, környezeti változók és egyéb konfiguráció szerint
A naplószintet bármelyik konfigurációszolgáltató beállíthatja. Létrehozhat például egy megőrzött környezeti változót Logging:LogLevel:Microsoft
, amelynek értéke a következő Information
.
Hozzon létre és rendeljen hozzá egy állandó környezeti változót a naplószintű érték alapján.
:: Assigns the env var to the value
setx "Logging__LogLevel__Microsoft" "Information" /M
A parancssor új példányában olvassa el a környezeti változót.
:: Prints the env var value
echo %Logging__LogLevel__Microsoft%
Az előző környezeti beállítás megmarad a környezetben. A .NET Worker szolgáltatássablonjaival létrehozott alkalmazás használatakor a beállítások teszteléséhez használja a dotnet run
projektkönyvtárban található parancsot a környezeti változó hozzárendelése után.
dotnet run
Tipp.
Egy környezeti változó beállítása után indítsa újra az integrált fejlesztési környezetet (IDE), hogy az újonnan hozzáadott környezeti változók elérhetők legyenek.
A Azure-alkalmazás Szolgáltatásban válassza az Új alkalmazás beállítást a Beállítások > konfiguráció lapján. Azure-alkalmazás szolgáltatásalkalmazás beállításai a következők:
- Inaktív állapotban titkosítva és titkosított csatornán keresztül továbbítva.
- Környezeti változókként van közzétéve.
A .NET-konfigurációs értékek környezeti változók használatával történő beállításáról további információt a környezeti változókban talál.
Naplózás konfigurálása kóddal
A kódba való naplózás konfigurálásához használja az API-t ILoggingBuilder . Ez különböző helyekről érhető el:
- A közvetlen létrehozásakor konfigurálja a
ILoggerFactory
következőt LoggerFactory.Create: . - Ha a DI-t gazdagép nélkül használja, konfigurálja a következőben LoggingServiceCollectionExtensions.AddLogging: .
- Gazdagép használata esetén konfiguráljon HostApplicationBuilder.Loggingvagy WebApplicationBuilder.Logging más gazdagépspecifikus API-kat.
Ez a példa a konzolnaplózási szolgáltató és több szűrő beállítását mutatja be.
using Microsoft.Extensions.Logging;
using var loggerFactory = LoggerFactory.Create(static builder =>
{
builder
.AddFilter("Microsoft", LogLevel.Warning)
.AddFilter("System", LogLevel.Warning)
.AddFilter("LoggingConsoleApp.Program", LogLevel.Debug)
.AddConsole();
});
ILogger logger = loggerFactory.CreateLogger<Program>();
logger.LogDebug("Hello {Target}", "Everyone");
Az előző példában AddFilter a különböző kategóriákhoz engedélyezett naplószintet kell módosítani. AddConsole a konzol naplózási szolgáltatójának hozzáadására szolgál. Alapértelmezés szerint a súlyosságú Debug
naplók nincsenek engedélyezve, de mivel a konfiguráció módosította a szűrőket, a "Hello Mindenki" hibakeresési üzenet jelenik meg a konzolon.
A szűrési szabályok alkalmazása
Amikor létrehoz egy ILogger<TCategoryName> objektumot, az ILoggerFactory objektum szolgáltatónként egyetlen szabályt választ ki, amelyet az adott naplózóra alkalmazni szeretne. A rendszer a kijelölt szabályok alapján szűri a példányok által ILogger
írt összes üzenetet. Az elérhető szabályok közül az egyes szolgáltatók és kategóriapárok legspecifikusabb szabálya van kiválasztva.
A rendszer az alábbi algoritmust használja minden szolgáltatóhoz, amikor létrehoz egy ILogger
adott kategóriát:
- Válassza ki a szolgáltatónak vagy aliasának megfelelő összes szabályt. Ha nem található egyezés, jelölje ki az összes szabályt egy üres szolgáltatóval.
- Az előző lépés eredményéből válassza ki a leghosszabb egyező kategóriaelőtaggal rendelkező szabályokat. Ha nem található egyezés, jelölje ki az összes olyan szabályt, amely nem ad meg kategóriát.
- Ha több szabály van kijelölve, az utolsót vegye figyelembe.
- Ha nincs kiválasztva szabály, a LoggingBuilderExtensions.SetMinimumLevel(ILoggingBuilder, LogLevel) minimális naplózási szintet adja meg.
Naplókategória
ILogger
Objektum létrehozásakor egy kategória van megadva. Ez a kategória szerepel a példány által létrehozott minden egyes naplóüzenetben ILogger
. A kategóriasztring tetszőleges, de a konvenció a teljes osztálynév használata. Például az alábbi objektumhoz hasonló szolgáltatással rendelkező alkalmazásokban a kategória a következő lehet "Example.DefaultService"
:
namespace Example
{
public class DefaultService : IService
{
private readonly ILogger<DefaultService> _logger;
public DefaultService(ILogger<DefaultService> logger) =>
_logger = logger;
// ...
}
}
Ha további kategorizálásra van szükség, a konvenció egy hierarchikus nevet használ egy alkategóriának a teljes osztálynévhez való hozzáfűzésével, és explicit módon adja meg a kategóriát a következő használatával LoggerFactory.CreateLogger:
namespace Example
{
public class DefaultService : IService
{
private readonly ILogger _logger;
public DefaultService(ILoggerFactory loggerFactory) =>
_logger = loggerFactory.CreateLogger("Example.DefaultService.CustomCategory");
// ...
}
}
A rögzített névvel történő hívás CreateLogger
akkor lehet hasznos, ha több osztályban/típusban használják, így az események kategóriák szerint rendszerezhetők.
ILogger<T>
egyenértékű a hívással CreateLogger
a teljes típusnévvel T
.
Naplózási szint
Az alábbi táblázat az LogLevel értékeket, a kényelmi Log{LogLevel}
bővítménymetódust és a javasolt használatot sorolja fel:
Naplózási szint | Érték | Metódus | Leírás |
---|---|---|---|
Nyomkövetés | 0 | LogTrace | A legrészletesebb üzeneteket tartalmazza. Ezek az üzenetek bizalmas alkalmazásadatokat tartalmazhatnak. Ezek az üzenetek alapértelmezés szerint le vannak tiltva, és éles környezetben nem engedélyezettek. |
Debug | 0 | LogDebug | Hibakereséshez és fejlesztéshez. A nagy mennyiség miatt óvatosan használja éles környezetben. |
Tájékoztatás | 2 | LogInformation | Nyomon követi az alkalmazás általános folyamatát. Hosszú távú érték is lehet. |
Figyelmeztetés | 3 | LogWarning | Rendellenes vagy váratlan események esetén. Általában olyan hibákat vagy feltételeket tartalmaznak, amelyek nem okozzák az alkalmazás meghibásodását. |
Hiba | 4 | LogError | Nem kezelhető hibák és kivételek esetén. Ezek az üzenetek az aktuális művelet vagy kérés hibáját jelzik, nem pedig alkalmazásszintű hibát. |
Kritikus | 5 | LogCritical | Azonnali figyelmet igénylő hibák esetén. Példák: adatvesztési forgatókönyvek, lemezterületen kívül. |
Egyik sem | 6 | Azt határozza meg, hogy ne kelljen üzeneteket írni. |
Az előző táblázatban a LogLevel
legalacsonyabbtól a legmagasabb súlyosságig soroljuk fel a listában.
A Napló metódus első paramétere LogLevela napló súlyosságát jelzi. Ahelyett, hogy hívna Log(LogLevel, ...)
, a legtöbb fejlesztő a Log{LogLevel} bővítménymetszeteket hívja meg. A Log{LogLevel}
bővítménymetódusok meghívják a metódust Log
, és megadják a LogLevel
. A következő két naplózási hívás például funkcionálisan egyenértékű, és ugyanazt a naplót hozza létre:
public void LogDetails()
{
var logMessage = "Details for log.";
_logger.Log(LogLevel.Information, AppLogEvents.Details, logMessage);
_logger.LogInformation(AppLogEvents.Details, logMessage);
}
AppLogEvents.Details
az eseményazonosító, amelyet implicit módon egy állandó Int32 érték jelöl. AppLogEvents
egy olyan osztály, amely különböző elnevezett azonosítóállandókat tesz elérhetővé, és a Napló eseményazonosító szakaszában jelenik meg.
A következő kód hozza létre Information
és Warning
naplózza:
public async Task<T> GetAsync<T>(string id)
{
_logger.LogInformation(AppLogEvents.Read, "Reading value for {Id}", id);
var result = await _repository.GetAsync(id);
if (result is null)
{
_logger.LogWarning(AppLogEvents.ReadNotFound, "GetAsync({Id}) not found", id);
}
return result;
}
Az előző kódban az első Log{LogLevel}
paraméter AppLogEvents.Read
a naplóesemény azonosítója. A második paraméter egy üzenetsablon, amely a fennmaradó metódusparaméterek által biztosított argumentumértékek helyőrzőit tartalmazza. A metódusparamétereket a cikk későbbi, üzenetsablon szakaszában ismertetjük.
Konfigurálja a megfelelő naplószintet, és hívja meg a megfelelő Log{LogLevel}
metódusokat annak szabályozásához, hogy egy adott tárolóeszközön mennyi naplókimenet legyen megírva. Példa:
- Éles környezetben:
- A naplózás vagy szintek
Trace
Debug
nagy mennyiségű részletes naplóüzenetet eredményeznek. A költségek szabályozása és az adattárolási korlátok túllépése érdekében naplózzaTrace
ésDebug
szintelje az üzeneteket egy nagy mennyiségű, alacsony költségű adattárba. Fontolja meg a korlátozástTrace
ésDebug
az adott kategóriákat. - A szinteken
Warning
valóCritical
naplózásnak kevés naplóüzenetet kell létrehoznia.- A költségek és a tárolási korlátok általában nem jelentenek problémát.
- A kevés napló nagyobb rugalmasságot biztosít az adattárak választásában.
- A naplózás vagy szintek
- Fejlesztés alatt:
- Állítsa
Warning
értékre. - Hozzáadás
Trace
vagyDebug
üzenetek hibaelhárításkor. A kimenet korlátozásához állítsa beTrace
vagyDebug
csak a vizsgált kategóriákra.
- Állítsa
A következő JSON-készletek Logging:Console:LogLevel:Microsoft:Information
:
{
"Logging": {
"LogLevel": {
"Microsoft": "Warning"
},
"Console": {
"LogLevel": {
"Microsoft": "Information"
}
}
}
}
Naplóesemény azonosítója
Minden napló megadhat egy eseményazonosítót, amely EventId egy olyan struktúra, amely írásvédett Name
tulajdonságokkal rendelkezikId
. A minta forráskódja az osztály használatával határozza meg az AppLogEvents
eseményazonosítókat:
using Microsoft.Extensions.Logging;
internal static class AppLogEvents
{
internal static EventId Create = new(1000, "Created");
internal static EventId Read = new(1001, "Read");
internal static EventId Update = new(1002, "Updated");
internal static EventId Delete = new(1003, "Deleted");
// These are also valid EventId instances, as there's
// an implicit conversion from int to an EventId
internal const int Details = 3000;
internal const int Error = 3001;
internal static EventId ReadNotFound = 4000;
internal static EventId UpdateNotFound = 4001;
// ...
}
Tipp.
További információ az esemény int
EventId
konvertálásáról: EventId.Implicit(Int32 to EventId) operátor.
Az eseményazonosító események egy készletét társítja. Előfordulhat például, hogy az adattár értékeinek 1001
beolvasásával kapcsolatos összes napló.
A naplózási szolgáltató naplózhatja az eseményazonosítót egy azonosító mezőben, a naplózási üzenetben, vagy egyáltalán nem. A hibakeresési szolgáltató nem jeleníti meg az eseményazonosítókat. A konzolszolgáltató zárójelben jeleníti meg az eseményazonosítókat a kategória után:
info: Example.DefaultService.GetAsync[1001]
Reading value for a1b2c3
warn: Example.DefaultService.GetAsync[4000]
GetAsync(a1b2c3) not found
Egyes naplózási szolgáltatók egy mezőben tárolják az eseményazonosítót, amely lehetővé teszi az azonosítóra való szűrést.
Naplóüzenet-sablon
Minden napló API egy üzenetsablont használ. Az üzenetsablon tartalmazhat helyőrzőket, amelyek argumentumai meg vannak adva. Használja a helyőrzők nevét, nem a számokat. A helyőrzők sorrendje, nem a nevük határozza meg, hogy a rendszer mely paramétereket használja az értékek megadásához. Az alábbi kódban a paraméternevek sorrenden kívül vannak az üzenetsablonban:
string p1 = "param1";
string p2 = "param2";
_logger.LogInformation("Parameter values: {p2}, {p1}", p1, p2);
Az előző kód létrehoz egy naplóüzenetet a paraméterértékekkel sorrendben:
Parameter values: param1, param2
Feljegyzés
Ügyeljen arra, hogy több helyőrzőt használjon egyetlen üzenetsablonon belül, mivel azok sorszámalapúak. A nevek nem használhatók az argumentumok helyőrzőkhöz való igazítására.
Ez a megközelítés lehetővé teszi a naplózási szolgáltatók számára a szemantikai vagy strukturált naplózás implementálását. Maguk az argumentumok a naplózási rendszernek lesznek átadva, nem csak a formázott üzenetsablonnak. Ez lehetővé teszi, hogy a naplózási szolgáltatók mezőként tárolják a paraméterértékeket. Fontolja meg a következő naplózó metódust:
_logger.LogInformation("Getting item {Id} at {RunTime}", id, DateTime.Now);
Például az Azure Table Storage-ba való naplózáskor:
- Minden Azure Table-entitás rendelkezhet
ID
ésRunTime
rendelkezhet tulajdonságokkal. - A tulajdonságokkal rendelkező táblák leegyszerűsítik a naplózott adatok lekérdezését. Egy lekérdezés például az összes naplót megkeresheti egy adott
RunTime
tartományon belül anélkül, hogy elemeznie kellene a szöveges üzenetből eltelt időt.
Naplóüzenetsablon formázása
A naplóüzenetsablonok támogatják a helyőrző formázást. A sablonok szabadon megadhatnak bármilyen érvényes formátumot a megadott típusargumentumhoz. Vegyük például a következő Information
naplózó üzenetsablont:
_logger.LogInformation("Logged on {PlaceHolderName:MMMM dd, yyyy}", DateTimeOffset.UtcNow);
// Logged on January 06, 2022
Az előző példában a DateTimeOffset
példány a naplózó üzenetsablonjának megfelelő PlaceHolderName
típus. Ez a név bármi lehet, mivel az értékek sorszámalapúak. A MMMM dd, yyyy
formátum érvényes a DateTimeOffset
típusra.
További információ és DateTime
DateTimeOffset
formázás: Egyéni dátum- és időformátum-sztringek.
Példák
Az alábbi példák bemutatják, hogyan formázhat egy üzenetsablont a {}
helyőrző szintaxis használatával. Emellett a helyőrző szintaxist {}
a kimenettel együtt is megjelenítheti. Végül a sztring interpolációja a csábító helyőrzőkkel is megjelenik:
logger.LogInformation("Number: {Number}", 1); // Number: 1
logger.LogInformation("{{Number}}: {Number}", 3); // {Number}: 3
logger.LogInformation($"{{{{Number}}}}: {{Number}}", 5); // {Number}: 5
Tipp.
- A legtöbb esetben a naplóüzenet-sablon formázását kell használnia naplózáskor. A sztringinterpoláció használata teljesítményproblémákat okozhat.
- Ca2254 kódelemzési szabály : A sablonnak statikus kifejezésnek kell lennie, amely figyelmezteti azokra a helyekre, ahol a naplóüzenetek nem használják a megfelelő formázást.
Naplózási kivételek
A naplózó metódusok túlterheléssel rendelkeznek, amelyek kivételparamétert vesznek fel:
public void Test(string id)
{
try
{
if (id is "none")
{
throw new Exception("Default Id detected.");
}
}
catch (Exception ex)
{
_logger.LogWarning(
AppLogEvents.Error, ex,
"Failed to process iteration: {Id}", id);
}
}
A kivételnaplózás szolgáltatóspecifikus.
Alapértelmezett naplószint
Ha az alapértelmezett naplószint nincs beállítva, az alapértelmezett naplószint értéke .Information
Vegyük például a következő feldolgozói szolgáltatásalkalmazást:
- A .NET-feldolgozósablonokkal létrehozva.
- appsettings.json és alkalmazásbeállításokat. Development.json törölve vagy átnevezve.
Az előző beállítással az adatvédelemre vagy a kezdőlapra való navigálás sok Trace
, Debug
és Information
a kategórianévvel ellátott Microsoft
üzeneteket eredményez.
Az alábbi kód állítja be az alapértelmezett naplószintet, ha az alapértelmezett naplószint nincs beállítva a konfigurációban:
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Logging.SetMinimumLevel(LogLevel.Warning);
using IHost host = builder.Build();
await host.RunAsync();
Szűrőfüggvény
A rendszer meghív egy szűrőfüggvényt minden olyan szolgáltatóhoz és kategóriához, amely nem rendelkezik hozzájuk konfiguráció vagy kód alapján hozzárendelt szabályokkal:
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Logging.AddFilter((provider, category, logLevel) =>
{
return provider.Contains("ConsoleLoggerProvider")
&& (category.Contains("Example") || category.Contains("Microsoft"))
&& logLevel >= LogLevel.Information;
});
using IHost host = builder.Build();
await host.RunAsync();
Az előző kód akkor jeleníti meg a konzolnaplókat, ha a kategória tartalmaz Example
vagy Microsoft
a naplószint magasabb Information
vagy magasabb.
Naplóhatókörök
A hatókörök logikai műveletek halmazát csoportosítják. Ezzel a csoportosítással ugyanazokat az adatokat csatolhatja a csoport részeként létrehozott naplókhoz. A tranzakció feldolgozása során létrehozott naplók például tartalmazhatják a tranzakcióazonosítót.
Hatókör:
- IDisposable A metódus által visszaadott BeginScope típus.
- Addig tart, amíg el nem dobja.
A következő szolgáltatók támogatják a hatóköröket:
Hatókör használata a naplózóhívások blokkban using
való körbefuttatásával:
public async Task<T> GetAsync<T>(string id)
{
T result;
var transactionId = Guid.NewGuid().ToString();
using (_logger.BeginScope(new List<KeyValuePair<string, object>>
{
new KeyValuePair<string, object>("TransactionId", transactionId),
}))
{
_logger.LogInformation(
AppLogEvents.Read, "Reading value for {Id}", id);
var result = await _repository.GetAsync(id);
if (result is null)
{
_logger.LogWarning(
AppLogEvents.ReadNotFound, "GetAsync({Id}) not found", id);
}
}
return result;
}
A következő JSON engedélyezi a konzolszolgáltató hatóköreit:
{
"Logging": {
"Debug": {
"LogLevel": {
"Default": "Information"
}
},
"Console": {
"IncludeScopes": true,
"LogLevel": {
"Microsoft": "Warning",
"Default": "Information"
}
},
"LogLevel": {
"Default": "Debug"
}
}
}
A következő kód lehetővé teszi a konzolszolgáltató hatóköreit:
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Logging.ClearProviders();
builder.Logging.AddConsole(options => options.IncludeScopes = true);
using IHost host = builder.Build();
await host.RunAsync();
Naplók létrehozása a Mainban
A következő kód a gazdagép létrehozása után egy ILogger
példány lekérésével jelentkezik be Main
a DI-ből:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using IHost host = Host.CreateApplicationBuilder(args).Build();
var logger = host.Services.GetRequiredService<ILogger<Program>>();
logger.LogInformation("Host created.");
await host.RunAsync();
Az előző kód két NuGet-csomagra támaszkodik:
A projektfájl a következőhöz hasonlóan nézne ki:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
</ItemGroup>
</Project>
Nincs aszinkron naplózó metódus
A naplózásnak olyan gyorsnak kell lennie, hogy nem éri meg az aszinkron kód teljesítményköltségét. Ha egy naplózási adattár lassú, ne írjon közvetlenül hozzá. Érdemes lehet először egy gyorstárolóba írni a naplóüzeneteket, majd később áthelyezni őket a lassú tárolóba. Ha például az SQL Serverre jelentkezik be, ne tegye ezt közvetlenül egy Log
metódusban, mivel a Log
metódusok szinkronban vannak. Ehelyett szinkronizálva adjon hozzá naplóüzeneteket egy memórián belüli üzenetsorhoz, és egy háttérmunkás húzza ki az üzeneteket az üzenetsorból, hogy elvégezhesse az adatok SQL Serverbe való leküldésének aszinkron munkáját.
Naplószintek módosítása futó alkalmazásokban
A Naplózási API nem tartalmaz olyan forgatókönyvet, amely megváltoztathatja a naplószinteket egy alkalmazás futtatása közben. Egyes konfigurációszolgáltatók azonban képesek újra betölteni a konfigurációt, ami azonnali hatással van a naplózási konfigurációra. A fájlkonfigurációs szolgáltató például alapértelmezés szerint újra betölti a naplózási konfigurációt. Ha egy alkalmazás futtatása közben a konfiguráció kódban módosul, az alkalmazás meghívhatja az IConfigurationRoot.Reload parancsot az alkalmazás naplózási konfigurációjának frissítéséhez.
NuGet-csomagok
ILoggerFactory A ILogger<TCategoryName> .NET SDK-k többsége implicit csomaghivatkozásként tartalmazza az interfészeket és az implementációkat. Kifejezetten elérhetők a következő NuGet-csomagokban is, ha egyébként nem implicit módon hivatkoznak rájuk:
- A felületek a Microsoft.Extensions.Logging.Abstractions fájlban találhatók.
- Az alapértelmezett implementációk a Microsoft.Extensions.Logging fájlban találhatók.
További információ arról, hogy a .NET SDK mely implicit csomaghivatkozásokat tartalmaz, olvassa el a .NET SDK: table to implicit namespace című témakört.