Loggning i C# och .NET
.NET stöder hög prestanda, strukturerad loggning via API:et ILogger för att övervaka programmets beteende och diagnostisera problem. Loggar kan skrivas till olika mål genom att konfigurera olika loggningsproviders. Grundläggande loggningsproviders är inbyggda och det finns även många tredjepartsleverantörer tillgängliga.
Kom igång
Det här första exemplet visar grunderna, men det är bara lämpligt för en trivial konsolapp. Den här exempelkonsolappen förlitar sig på följande NuGet-paket:
I nästa avsnitt ser du hur du kan förbättra koden med tanke på skalning, prestanda, konfiguration och typiska programmeringsmönster.
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");
Föregående exempel:
- Skapar en ILoggerFactory. Lagrar
ILoggerFactory
all konfiguration som avgör var loggmeddelanden skickas. I det här fallet konfigurerar du konsolens loggningsprovider så att loggmeddelanden skrivs till konsolen. - Skapar en ILogger med en kategori med namnet "Program". Kategorin är en
string
som är associerad med varje meddelande som loggas avILogger
objektet. Den används för att gruppera loggmeddelanden från samma klass (eller kategori) tillsammans vid sökning eller filtrering av loggar. - Anropar LogInformation för att logga ett meddelande på
Information
nivån. Loggnivån anger allvarlighetsgraden för den loggade händelsen och används för att filtrera bort mindre viktiga loggmeddelanden. Loggposten innehåller även en meddelandemall"Hello World! Logging is {Description}."
och ett nyckel/värde-parDescription = fun
. Nyckelnamnet (eller platshållaren) kommer från ordet inuti klammerparenteserna i mallen och värdet kommer från det återstående metodargumentet.
Den här projektfilen för det här exemplet innehåller två NuGet-paket:
<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="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.0" />
</ItemGroup>
</Project>
Dricks
All källkod för loggningsexemplet är tillgänglig i Exempelwebbläsaren för nedladdning. Mer information finns i Bläddra bland kodexempel: Loggning i .NET.
Logga in en icke-trivial app
Det finns flera ändringar som du bör överväga att göra i föregående exempel när du loggar in i ett mindre trivialt scenario:
Om ditt program använder beroendeinmatning (DI) eller en värd, till exempel ASP. NET:s webapplication eller generiska värd bör du använda
ILoggerFactory
ochILogger
objekt från deras respektive DI-containrar i stället för att skapa dem direkt. Mer information finns i Integrering med DI och Värdar.Loggning av kompileringstidskälla är vanligtvis ett bättre alternativ till
ILogger
tilläggsmetoder somLogInformation
. Loggningskällans generering ger bättre prestanda, starkare typning och undviker att spridastring
konstanter i dina metoder. Kompromissen är att användning av den här tekniken kräver lite mer kod.
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);
}
- Den rekommenderade metoden för loggkategorinamn är att använda det fullständigt kvalificerade namnet på klassen som skapar loggmeddelandet. Detta hjälper till att relatera loggmeddelanden tillbaka till koden som skapade dem och ger en bra kontrollnivå vid filtrering av loggar. CreateLogger accepterar en
Type
för att göra den här namngivningen enkel att göra.
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");
}
}
- Om du inte använder konsolloggar som den enda produktionsövervakningslösningen lägger du till de loggningsproviders som du planerar att använda. Du kan till exempel använda OpenTelemetry för att skicka loggar via OTLP (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");
Integrering med värdar och beroendeinmatning
Om ditt program använder beroendeinmatning (DI) eller en värd, till exempel ASP. NET:s webapplication eller generiska värd bör du använda ILoggerFactory
och ILogger
objekt från DI-containern i stället för att skapa dem direkt.
Hämta en ILogger från DI
Det här exemplet hämtar ett ILogger-objekt i en värdbaserad app med ASP.NET minimala API:er:
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);
}
Föregående exempel:
- Skapade en singleton-tjänst med namnet
ExampleHandler
och mappade inkommande webbbegäranden för att köraExampleHandler.HandleRequest
funktionen. - Rad 8 definierar en primär konstruktor för ExampleHandler, en funktion som läggs till i C# 12. Att använda den äldre C#-konstruktorn skulle fungera lika bra men är lite mer utförligt.
- Konstruktorn definierar en parameter av typen
ILogger<ExampleHandler>
. ILogger<TCategoryName> härleds från ILogger och anger vilken kategori objektetILogger
har. DI-containern letar upp enILogger
med rätt kategori och tillhandahåller den som konstruktorargument. Om det inte finns någonILogger
med den kategorin ännu skapar DI-containern den automatiskt frånILoggerFactory
i tjänstleverantören. - Parametern
logger
som togs emot i konstruktorn användes för loggning iHandleRequest
funktionen.
Värdbaserad ILoggerFactory
Värdskapare initierar standardkonfigurationen och lägger sedan till ett konfigurerat ILoggerFactory
objekt i värdens DI-container när värden skapas. Innan värden skapas kan du justera loggningskonfigurationen via HostApplicationBuilder.Logging, WebApplicationBuilder.Loggingeller liknande API:er på andra värdar. Värdar tillämpar även loggningskonfiguration från standardkonfigurationskällor som appsettings.json och miljövariabler. Mer information finns i Konfiguration i .NET.
Det här exemplet expanderar på föregående för att anpassa den ILoggerFactory
som tillhandahålls av WebApplicationBuilder
. Den lägger till OpenTelemetry som en loggningsprovider som skickar loggarna via OTLP (OpenTelemetry protocol):
var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddOpenTelemetry(logging => logging.AddOtlpExporter());
builder.Services.AddSingleton<ExampleHandler>();
var app = builder.Build();
Skapa en ILoggerFactory med DI
Om du använder en DI-container utan värd använder du AddLogging för att konfigurera och lägga till ILoggerFactory
i containern.
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);
}
}
Föregående exempel:
- Skapade en DI-tjänstcontainer som innehåller en
ILoggerFactory
konfigurerad för att skriva till konsolen - En singleton
ExampleService
har lagts till i containern - Skapade en instans av
ExampleService
från DI-containern som också automatiskt skapade enILogger<ExampleService>
som ska användas som konstruktorargument. - Anropad
ExampleService.DoSomeWork
som användeILogger<ExampleService>
för att logga ett meddelande till konsolen.
Konfigurera loggning
Loggningskonfigurationen anges i kod eller via externa källor, till exempel konfigurationsfiler och miljövariabler. Det är fördelaktigt att använda extern konfiguration när det är möjligt eftersom det kan ändras utan att programmet återskapas. Vissa uppgifter, till exempel att ange loggningsproviders, kan dock bara konfigureras från kod.
Konfigurera loggning utan kod
För appar som använder en värd tillhandahålls loggningskonfiguration ofta i "Logging"
avsnittet apparinställningar.{Environment}
.json filer. För appar som inte använder en värd konfigureras externa konfigurationskällor explicit eller konfigureras i kod i stället.
Följande apparinställningar. Development.json filen genereras av .NET Worker-tjänstmallarna:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
I JSON-koden ovan:
- Kategorierna
"Default"
,"Microsoft"
och"Microsoft.Hosting.Lifetime"
loggnivå anges. - Värdet
"Default"
tillämpas på alla kategorier som inte anges på annat sätt, vilket i praktiken gör alla standardvärden för alla kategorier"Information"
. Du kan åsidosätta det här beteendet genom att ange ett värde för en kategori. - Kategorin
"Microsoft"
gäller för alla kategorier som börjar med"Microsoft"
. - Kategoriloggarna
"Microsoft"
på loggnivåWarning
och högre. - Kategorin
"Microsoft.Hosting.Lifetime"
är mer specifik än"Microsoft"
kategorin, så"Microsoft.Hosting.Lifetime"
kategoriloggarna på loggnivå"Information"
och högre. - En specifik loggprovider har inte angetts, så
LogLevel
den gäller för alla aktiverade loggningsproviders förutom Windows EventLog.
Egenskapen Logging
kan ha LogLevel egenskaper för loggprovidern. LogLevel
Anger den lägsta nivå som ska loggas för valda kategorier. I föregående JSON Information
Warning
och loggnivåer anges. LogLevel
anger loggens allvarlighetsgrad och sträcker sig från 0 till 6:
Trace
= 0, Debug
= 1, Information
= 2, Warning
= 3, Error
= 4, Critical
= 5 och None
= 6.
När en LogLevel
har angetts aktiveras loggning för meddelanden på den angivna nivån och högre. I föregående JSON Default
loggas kategorin för Information
och högre. Till exempel Information
loggas , Warning
, Error
och Critical
meddelanden. Om nej LogLevel
har angetts är loggning standardvärdet för Information
nivån. Mer information finns i Loggnivåer.
En provideregenskap kan ange en LogLevel
egenskap. LogLevel
under en provider anger nivåer för att logga för den providern och åsidosätter logginställningarna som inte är provider. Överväg följande appsettings.json fil:
{
"Logging": {
"LogLevel": {
"Default": "Error",
"Microsoft": "Warning"
},
"Debug": {
"LogLevel": {
"Default": "Information",
"Microsoft.Hosting": "Trace"
}
},
"EventSource": {
"LogLevel": {
"Default": "Warning"
}
}
}
}
Inställningar i Logging.{ProviderName}.LogLevel
åsidosättningsinställningar i Logging.LogLevel
. I föregående JSON Debug
är providerns standardloggnivå inställd Information
på :
Logging:Debug:LogLevel:Default:Information
Föregående inställning anger Information
loggnivån för varje Logging:Debug:
kategori utom Microsoft.Hosting
. När en specifik kategori visas åsidosätter den specifika kategorin standardkategorin. I föregående JSON åsidosätter Logging:Debug:LogLevel
kategorierna "Microsoft.Hosting"
och "Default"
inställningarna i Logging:LogLevel
Minsta loggnivå kan anges för något av följande:
- Specifika leverantörer: Till exempel
Logging:EventSource:LogLevel:Default:Information
- Specifika kategorier: Till exempel
Logging:LogLevel:Microsoft:Warning
- Alla leverantörer och alla kategorier:
Logging:LogLevel:Default:Warning
Loggar under miniminivån är inte:
- Skickas till providern.
- Loggas eller visas.
Om du vill ignorera alla loggar anger du LogLevel.None. LogLevel.None
har värdet 6, vilket är högre än LogLevel.Critical
(5).
Om en provider stöder loggomfattningar anger IncludeScopes
du om de är aktiverade. Mer information finns i loggomfattningar
Följande appsettings.json fil innehåller inställningar för alla inbyggda leverantörer:
{
"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"
}
}
}
}
I föregående exempel:
- Kategorierna och nivåerna är inte föreslagna värden. Exemplet tillhandahålls för att visa alla standardprovidrar.
- Inställningar i
Logging.{ProviderName}.LogLevel
åsidosättningsinställningar iLogging.LogLevel
. Nivån iDebug.LogLevel.Default
åsidosätter till exempel nivån iLogLevel.Default
. - Varje providers alias används. Varje provider definierar ett alias som kan användas i konfigurationen i stället för det fullständigt kvalificerade typnamnet. De inbyggda provideraliasen är:
Console
Debug
EventSource
EventLog
AzureAppServicesFile
AzureAppServicesBlob
ApplicationInsights
Ange loggnivå efter kommandorad, miljövariabler och annan konfiguration
Loggnivån kan anges av någon av konfigurationsprovidrar. Du kan till exempel skapa en bevarad miljövariabel med namnet Logging:LogLevel:Microsoft
med värdet Information
.
Skapa och tilldela en bevarad miljövariabel med tanke på loggnivåvärdet.
:: Assigns the env var to the value
setx "Logging__LogLevel__Microsoft" "Information" /M
I en ny instans av kommandotolken läser du miljövariabeln.
:: Prints the env var value
echo %Logging__LogLevel__Microsoft%
Den föregående miljöinställningen sparas i miljön. Om du vill testa inställningarna när du använder en app som skapats med .NET Worker-tjänstmallarna använder du dotnet run
kommandot i projektkatalogen när miljövariabeln har tilldelats.
dotnet run
Dricks
När du har angett en miljövariabel startar du om din integrerade utvecklingsmiljö (IDE) för att säkerställa att nyligen tillagda miljövariabler är tillgängliga.
I Azure App Service väljer du Ny programinställning på sidan Konfiguration av inställningar>. Azure App Service-programinställningar är:
- Krypterad i vila och överförs via en krypterad kanal.
- Exponeras som miljövariabler.
Mer information om hur du anger .NET-konfigurationsvärden med hjälp av miljövariabler finns i miljövariabler.
Konfigurera loggning med kod
Om du vill konfigurera loggning i kod använder du API:et ILoggingBuilder . Detta kan nås från olika platser:
- När du skapar
ILoggerFactory
direkt konfigurerar du i LoggerFactory.Create. - När du använder DI utan värd konfigurerar du i LoggingServiceCollectionExtensions.AddLogging.
- När du använder en värd konfigurerar du med HostApplicationBuilder.Loggingeller WebApplicationBuilder.Logging andra värdspecifika API:er.
Det här exemplet visar hur du ställer in konsolens loggningsprovider och flera filter.
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");
I föregående exempel AddFilter används för att justera loggnivån som är aktiverad för olika kategorier. AddConsole används för att lägga till konsolens loggningsprovider. Som standard är loggar med Debug
allvarlighetsgrad inte aktiverade, men eftersom konfigurationen justerade filtren visas felsökningsmeddelandet "Hello Everyone" i konsolen.
Så här tillämpas filtreringsregler
När ett ILogger<TCategoryName> objekt skapas ILoggerFactory väljer objektet en enda regel per provider som ska tillämpas på den loggaren. Alla meddelanden som skrivs av en ILogger
instans filtreras baserat på de valda reglerna. Den mest specifika regeln för varje provider och kategoripar väljs från de tillgängliga reglerna.
Följande algoritm används för varje provider när en ILogger
skapas för en viss kategori:
- Välj alla regler som matchar providern eller dess alias. Om ingen matchning hittas väljer du alla regler med en tom provider.
- Från resultatet av föregående steg väljer du regler med det längsta matchande kategoriprefixet. Om ingen matchning hittas väljer du alla regler som inte anger en kategori.
- Om flera regler har valts tar du den sista .
- Om inga regler har valts använder du LoggingBuilderExtensions.SetMinimumLevel(ILoggingBuilder, LogLevel) för att ange den minsta loggningsnivån.
Loggkategori
När ett ILogger
objekt skapas anges en kategori . Den kategorin ingår i varje loggmeddelande som skapas av den instansen av ILogger
. Kategoristrängen är godtycklig, men konventionen är att använda det fullständigt kvalificerade klassnamnet. I ett program med en tjänst som definierats som följande objekt kan kategorin till exempel vara "Example.DefaultService"
:
namespace Example
{
public class DefaultService : IService
{
private readonly ILogger<DefaultService> _logger;
public DefaultService(ILogger<DefaultService> logger) =>
_logger = logger;
// ...
}
}
Om ytterligare kategorisering önskas är konventionen att använda ett hierarkiskt namn genom att lägga till en underkategori i det fullständigt kvalificerade klassnamnet och uttryckligen ange kategorin med hjälp av LoggerFactory.CreateLogger:
namespace Example
{
public class DefaultService : IService
{
private readonly ILogger _logger;
public DefaultService(ILoggerFactory loggerFactory) =>
_logger = loggerFactory.CreateLogger("Example.DefaultService.CustomCategory");
// ...
}
}
Att anropa CreateLogger
med ett fast namn kan vara användbart när det används i flera klasser/typer så att händelserna kan ordnas efter kategori.
ILogger<T>
motsvarar anrop CreateLogger
med det fullständigt kvalificerade typnamnet T
.
Loggnivå
I följande tabell visas LogLevel värdena, metoden för bekvämlighetstillägg Log{LogLevel}
och den föreslagna användningen:
Loggnivå | Värde | Metod | beskrivning |
---|---|---|---|
Spårning | 0 | LogTrace | Innehåller de mest detaljerade meddelandena. Dessa meddelanden kan innehålla känsliga appdata. Dessa meddelanden är inaktiverade som standard och bör inte aktiveras i produktion. |
Debug | 1 | LogDebug | För felsökning och utveckling. Använd med försiktighet i produktionen på grund av den höga volymen. |
Information | 2 | LogInformation | Spårar appens allmänna flöde. Kan ha ett långsiktigt värde. |
Varning! | 3 | LogWarning | För onormala eller oväntade händelser. Innehåller vanligtvis fel eller villkor som inte gör att appen misslyckas. |
Fel | 4 | LogError | För fel och undantag som inte kan hanteras. Dessa meddelanden anger ett fel i den aktuella åtgärden eller begäran, inte ett appomfattande fel. |
Kritisk | 5 | LogCritical | För fel som kräver omedelbar uppmärksamhet. Exempel: scenarier för dataförlust, slut på diskutrymme. |
None | 6 | Anger att inga meddelanden ska skrivas. |
I föregående tabell LogLevel
visas från lägsta till högsta allvarlighetsgrad.
Log-metodens första parameter, LogLevel, anger loggens allvarlighetsgrad. I stället för att anropa Log(LogLevel, ...)
anropa anropar de flesta utvecklare log{LogLevel} -tilläggsmetoderna. Tilläggsmetoderna Log{LogLevel}
Log
anropar metoden och anger LogLevel
. Följande två loggningsanrop är till exempel funktionellt likvärdiga och skapar samma logg:
public void LogDetails()
{
var logMessage = "Details for log.";
_logger.Log(LogLevel.Information, AppLogEvents.Details, logMessage);
_logger.LogInformation(AppLogEvents.Details, logMessage);
}
AppLogEvents.Details
är händelse-ID:t och representeras implicit av ett konstant Int32 värde. AppLogEvents
är en klass som exponerar olika namngivna identifierarkonstanter och som visas i avsnittet Logghändelse-ID .
Följande kod skapar Information
och Warning
loggar:
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;
}
I föregående kod är den första Log{LogLevel}
parametern, AppLogEvents.Read
, logghändelse-ID. Den andra parametern är en meddelandemall med platshållare för argumentvärden som tillhandahålls av de återstående metodparametrarna. Metodparametrarna beskrivs i avsnittet med meddelandemallar senare i den här artikeln.
Konfigurera lämplig loggnivå och anropa rätt Log{LogLevel}
metoder för att styra hur mycket loggutdata som skrivs till ett visst lagringsmedium. Till exempel:
- I produktion:
- Loggning på
Trace
nivåerna ellerDebug
ger en stor mängd detaljerade loggmeddelanden. För att kontrollera kostnader och inte överskrida datalagringsgränser loggarTrace
ochDebug
nivåmeddelanden till ett datalager med hög volym och låg kostnad. Överväg attTrace
begränsa ochDebug
till specifika kategorier. - Loggning på
Warning
viaCritical
nivåer bör ge få loggmeddelanden.- Kostnader och lagringsgränser är vanligtvis inte ett problem.
- Få loggar ger mer flexibilitet i val av datalager.
- Loggning på
- Under utveckling:
- Ange till
Warning
. - Lägg till
Trace
ellerDebug
meddelanden vid felsökning. Om du vill begränsa utdata angerTrace
du ellerDebug
endast för de kategorier som undersöks.
- Ange till
Följande JSON-uppsättningar Logging:Console:LogLevel:Microsoft:Information
:
{
"Logging": {
"LogLevel": {
"Microsoft": "Warning"
},
"Console": {
"LogLevel": {
"Microsoft": "Information"
}
}
}
}
Logghändelse-ID
Varje logg kan ange en händelseidentifierare, EventId är en struktur med en Id
och valfri skrivskyddad Name
egenskap. Exempelkällan använder AppLogEvents
klassen för att definiera händelse-ID:t:
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;
// ...
}
Dricks
Mer information om hur du konverterar en int
till en EventId
finns i EventId.Implicit(Int32 till EventId)-operator.
Ett händelse-ID associerar en uppsättning händelser. Till exempel kan alla loggar som rör läsningsvärden från en lagringsplats vara 1001
.
Loggningsprovidern kan logga händelse-ID:t i ett ID-fält, i loggningsmeddelandet eller inte alls. Felsökningsprovidern visar inte händelse-ID:t. Konsolprovidern visar händelse-ID:t inom hakparenteser efter kategorin:
info: Example.DefaultService.GetAsync[1001]
Reading value for a1b2c3
warn: Example.DefaultService.GetAsync[4000]
GetAsync(a1b2c3) not found
Vissa loggningsleverantörer lagrar händelse-ID:t i ett fält, vilket möjliggör filtrering på ID:t.
Loggmeddelandemall
Varje logg-API använder en meddelandemall. Meddelandemallen kan innehålla platshållare för vilka argument anges. Använd namn för platshållarna, inte siffror. Platshållarnas ordning, inte deras namn, avgör vilka parametrar som används för att ange deras värden. I följande kod är parameternamnen ur sekvens i meddelandemallen:
string p1 = "param1";
string p2 = "param2";
_logger.LogInformation("Parameter values: {p2}, {p1}", p1, p2);
Föregående kod skapar ett loggmeddelande med parametervärdena i följd:
Parameter values: param1, param2
Kommentar
Tänk på när du använder flera platshållare i en enda meddelandemall, eftersom de är ordningsbaserade. Namnen används inte för att justera argumenten mot platshållarna.
Med den här metoden kan loggningsproviders implementera semantisk eller strukturerad loggning. Själva argumenten skickas till loggningssystemet, inte bara den formaterade meddelandemallen. Detta gör det möjligt för loggningsprovidrar att lagra parametervärdena som fält. Överväg följande loggningsmetod:
_logger.LogInformation("Getting item {Id} at {RunTime}", id, DateTime.Now);
När du till exempel loggar till Azure Table Storage:
- Varje Azure Table-entitet kan ha
ID
ochRunTime
egenskaper. - Tabeller med egenskaper förenklar frågor om loggade data. En fråga kan till exempel hitta alla loggar inom ett visst
RunTime
intervall utan att behöva parsa tidsgränsen för textmeddelandet.
Formatering av loggmeddelandemall
Loggmeddelandemallar stöder platshållarformatering. Mallar kan ange valfritt giltigt format för det angivna typargumentet. Tänk till exempel på följande Information
mall för loggningsmeddelande:
_logger.LogInformation("Logged on {PlaceHolderName:MMMM dd, yyyy}", DateTimeOffset.UtcNow);
// Logged on January 06, 2022
I föregående exempel är instansen DateTimeOffset
den typ som motsvarar mallen PlaceHolderName
i loggningsmeddelandet. Det här namnet kan vara vad som helst eftersom värdena är ordningsbaserade. Formatet MMMM dd, yyyy
är giltigt för DateTimeOffset
typen.
Mer information om DateTime
och DateTimeOffset
formatering finns i Anpassade datum- och tidsformatsträngar.
Exempel
I följande exempel visas hur du formaterar en meddelandemall med platshållarsyntaxen {}
. Dessutom visas ett exempel på hur platshållarsyntaxen {}
kan undvikas med dess utdata. Slutligen visas även stränginterpolation med platshållare för mallar:
logger.LogInformation("Number: {Number}", 1); // Number: 1
logger.LogInformation("{{Number}}: {Number}", 3); // {Number}: 3
logger.LogInformation($"{{{{Number}}}}: {{Number}}", 5); // {Number}: 5
Dricks
- I de flesta fall bör du använda formatering av loggmeddelandemallar vid loggning. Användning av stränginterpolation kan orsaka prestandaproblem.
- Kodanalysregel CA2254: Mallen ska vara ett statiskt uttryck som hjälper dig att varna dig om platser där dina loggmeddelanden inte använder korrekt formatering.
Loggfel
Loggningsmetoderna har överlagringar som tar en undantagsparameter:
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);
}
}
Undantagsloggning är providerspecifik.
Standardloggnivå
Om standardloggnivån inte har angetts är Information
standardvärdet för loggnivå .
Tänk till exempel på följande arbetstjänstapp:
- Skapades med .NET Worker-mallarna.
- appsettings.json och apparinställningar. Development.json har tagits bort eller bytt namn.
Med den föregående konfigurationen genererar navigering till sekretess- eller startsidan många Trace
, Debug
och Information
meddelanden med Microsoft
i kategorinamnet.
Följande kod anger standardloggnivån när standardloggnivån inte har angetts i konfigurationen:
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Logging.SetMinimumLevel(LogLevel.Warning);
using IHost host = builder.Build();
await host.RunAsync();
Filterfunktion
En filterfunktion anropas för alla leverantörer och kategorier som inte har regler tilldelade till sig genom konfiguration eller kod:
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();
Föregående kod visar konsolloggar när kategorin innehåller Example
eller Microsoft
och loggnivån är Information
eller högre.
Loggomfattningar
Ett omfång grupperar en uppsättning logiska åtgärder. Den här grupperingen kan användas för att koppla samma data till varje logg som skapas som en del av en uppsättning. Varje logg som skapas som en del av bearbetningen av en transaktion kan till exempel innehålla transaktions-ID:t.
Ett omfång:
- Är en IDisposable typ som returneras av BeginScope metoden.
- Varar tills den tas bort.
Följande leverantörer stöder omfång:
Använd ett omfång genom att omsluta loggningsanrop i ett using
block:
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;
}
Följande JSON aktiverar omfång för konsolprovidern:
{
"Logging": {
"Debug": {
"LogLevel": {
"Default": "Information"
}
},
"Console": {
"IncludeScopes": true,
"LogLevel": {
"Microsoft": "Warning",
"Default": "Information"
}
},
"LogLevel": {
"Default": "Debug"
}
}
}
Följande kod aktiverar omfång för konsolprovidern:
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Logging.ClearProviders();
builder.Logging.AddConsole(options => options.IncludeScopes = true);
using IHost host = builder.Build();
await host.RunAsync();
Skapa loggar i Main
Följande kod loggar in Main
genom att hämta en ILogger
instans från DI när värden har skapats:
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();
Föregående kod förlitar sig på två NuGet-paket:
Projektfilen skulle se ut ungefär så här:
<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>
Inga asynkrona loggningsmetoder
Loggning bör vara så snabb att det inte är värt prestandakostnaden för asynkron kod. Om ett loggningsdatalager är långsamt ska du inte skriva till det direkt. Överväg att skriva loggmeddelandena till en snabb butik först och sedan flytta dem till det långsamma arkivet senare. När du till exempel loggar till SQL Server ska du inte göra det direkt i en Log
metod, eftersom Log
metoderna är synkrona. Lägg i stället synkront till loggmeddelanden i en minnesintern kö och låt en bakgrundsarbetare hämta meddelandena från kön för att utföra det asynkrona arbetet med att skicka data till SQL Server.
Ändra loggnivåer i en app som körs
Loggnings-API:et innehåller inget scenario för att ändra loggnivåer när en app körs. Vissa konfigurationsprovidrar kan dock läsa in konfigurationen igen, vilket omedelbart påverkar loggningskonfigurationen. Till exempel läser filkonfigurationsprovidern in loggningskonfigurationen igen som standard. Om konfigurationen ändras i kod medan en app körs kan appen anropa IConfigurationRoot.Reload för att uppdatera appens loggningskonfiguration.
NuGet-paket
Gränssnitten ILogger<TCategoryName> och ILoggerFactory implementeringarna och ingår i de flesta .NET SDK:er som implicit paketreferens. De är också uttryckligen tillgängliga i följande NuGet-paket när de inte refereras implicit:
- Gränssnitten finns i Microsoft.Extensions.Logging.Abstractions.
- Standardimplementeringarna finns i Microsoft.Extensions.Logging.
Mer information om vilka .NET SDK som innehåller implicita paketreferenser finns i .NET SDK: table to implicit namespace (.NET SDK: table to implicit namespace).
Se även
- Loggningsproviders i .NET
- Implementera en anpassad loggningsprovider i .NET
- Formatering av konsolloggar
- Loggning med höga prestanda i .NET
- Loggningsvägledning för .NET-biblioteksförfattare
- Loggningsbuggar bör skapas på den github.com/dotnet/runtime lagringsplatsen