Delen via


Loggen in C# en .NET

.NET biedt ondersteuning voor hoge prestaties, gestructureerde logboekregistratie via de ILogger API om het gedrag van toepassingen te bewaken en problemen te diagnosticeren. Configureer verschillende logboekproviders om logboeken naar verschillende bestemmingen te schrijven. Basisproviders voor logboekregistratie zijn ingebouwd en er zijn veel externe providers beschikbaar.

Aan de slag

In dit eerste voorbeeld ziet u de basisbeginselen, maar deze is alleen geschikt voor een triviale console-app. Deze voorbeeldconsole-app is afhankelijk van de volgende NuGet-pakketten:

In de volgende sectie ziet u hoe u de code kunt verbeteren, rekening houdend met schaal, prestaties, configuratie en typische programmeerpatronen.

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");

Het voorgaande voorbeeld:

  • Hiermee maakt u een ILoggerFactory. Alle ILoggerFactory configuraties die bepalen waar logboekberichten worden verzonden, worden opgeslagen. In dit geval configureert u de provider voor consolelogboekregistratie , zodat logboekberichten naar de console worden geschreven.
  • Hiermee maakt u een ILogger met een categorie met de naam 'Programma'. De categorie is een string categorie die is gekoppeld aan elk bericht dat door het ILogger object is geregistreerd. Logboekberichten van dezelfde klasse (of categorie) worden gegroepeerd bij het zoeken of filteren van logboeken.
  • Roept LogInformation aan om een bericht op het Information niveau te loggen. Het logboekniveau geeft de ernst van de vastgelegde gebeurtenis aan en filtert minder belangrijke logboekberichten. De logboekvermelding bevat ook een berichtsjabloon"Hello World! Logging is {Description}." en een sleutel-waardepaar Description = fun. De sleutelnaam (of tijdelijke aanduiding) is afkomstig van het woord tussen de accolades in de sjabloon, en de waarde komt van het resterende argument van de methode.

Dit projectbestand voor dit voorbeeld bevat twee NuGet-pakketten:

<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.10" />
    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.10" />
  </ItemGroup>

</Project>

Aanbeveling

Alle voorbeeldbroncode voor logboekregistratie is beschikbaar in de voorbeeldenbrowser om te downloaden. Zie Blader door codevoorbeelden: Logboekregistratie in .NET voor meer informatie.

Aanmelden bij een niet-triviale app

Overweeg deze wijzigingen aan te brengen in het vorige voorbeeld wanneer u zich aanmeldt in een minder triviaal scenario:

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);
}
  • De aanbevolen procedure voor logboekcategorienamen is het gebruik van de volledig gekwalificeerde naam van de klasse die het logboekbericht maakt. Dit helpt logboekberichten terug te relateren aan de code die ze heeft geproduceerd en biedt een goed beheerniveau bij het filteren van logboeken. CreateLogger accepteert een Type om deze naamgeving eenvoudig te maken.
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");
    }
}
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");

Integratie met hosts en afhankelijkheidsinjectie

Als uw toepassing gebruikmaakt van afhankelijkheidsinjectie (DI) of een host zoals ASP. WebApplication of Generic Host van NET, gebruik ILoggerFactory en ILogger objecten uit de DI-container in plaats van ze rechtstreeks te maken.

Een ILogger verkrijgen via DI

In dit voorbeeld wordt een ILogger-object voor een gehoste app opgehaald met behulp van ASP.NET Minimal APIs.

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);
}

Het voorgaande voorbeeld:

  • Er is een singleton-service gemaakt met de naam ExampleHandler, waarbij binnenkomende webaanvragen worden toegewezen om de functie ExampleHandler.HandleRequest uit te voeren.
  • Regel 12 definieert een primaire constructor voor ExampleHandler, een functie die is toegevoegd in C# 12. Het gebruik van de oudere C#-constructor werkt even goed, maar is iets uitgebreider.
  • De constructor definieert een parameter van het type ILogger<ExampleHandler>. ILogger<TCategoryName> is afgeleid van ILogger en geeft aan welke categorie het ILogger object heeft. De DI-container zoekt een ILogger met de juiste categorie en levert deze als het constructorargument. Als er nog geen ILogger met die categorie bestaat, wordt deze automatisch door de ILoggerFactory in de serviceprovider aangemaakt.
  • De logger parameter die in de constructor wordt ontvangen, wordt gebruikt voor logging in de HandleRequest functie.

Door de host geleverde ILoggerFactory

Hostbouwers initialiseren de standaardconfiguratie en voegen vervolgens een geconfigureerd ILoggerFactory object toe aan de DI-container van de host wanneer de host wordt gebouwd. Voordat de host wordt gebouwd, past u de configuratie van logboekregistratie aan via HostApplicationBuilder.Logging, WebApplicationBuilder.Loggingof vergelijkbare API's op andere hosts. Hosts passen ook configuratie van logboekregistratie toe van standaardconfiguratiebronnen, zoals appsettings.json en omgevingsvariabelen. Zie Configuratie in .NET voor meer informatie.

Dit voorbeeld bouwt voort op het vorige om de door ILoggerFactory aangeboden WebApplicationBuilder aan te passen. Er wordt OpenTelemetry toegevoegd als een logboekregistratieprovider die de logboeken via OTLP (OpenTelemetry protocol) verzendt:

var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddOpenTelemetry(logging => logging.AddOtlpExporter());
builder.Services.AddSingleton<ExampleHandler>();
var app = builder.Build();

Een ILoggerFactory maken met DI

Als u een DI-container zonder host gebruikt, gebruikt u AddLogging om deze te configureren en voegt u ILoggerFactory toe aan de container.

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);
    }
}

Het voorgaande voorbeeld:

  • Een DI-servicecontainer gemaakt met een ILoggerFactory dat geconfigureerd is om naar de console te schrijven.
  • Een singleton ExampleService toegevoegd aan de container
  • Er is een exemplaar van de ExampleService gemaakt uit het DI-container, waarbij automatisch een ILogger<ExampleService> als constructorargument werd aangemaakt.
  • Wanneer ExampleService.DoSomeWork wordt aangeroepen, gebruikt het de ILogger<ExampleService> om een bericht naar de console te loggen.

Logboekregistratie configureren

Configuratie van logboekregistratie instellen in code of via externe bronnen, zoals configuratiebestanden en omgevingsvariabelen. Het gebruik van externe configuratie is nuttig, indien mogelijk, omdat u deze kunt wijzigen zonder de toepassing opnieuw te bouwen. Sommige taken, zoals het instellen van logboekregistratieproviders, kunnen echter alleen worden geconfigureerd vanuit code.

Logboekregistratie zonder code configureren

Voor apps die een host gebruiken, biedt het "Logging" gedeelte van appsettings.{Environment}.json bestanden doorgaans logboekregistratieconfiguratie. Voor apps die geen host gebruiken, stelt u in plaats daarvan expliciet externe configuratiebronnen in of configureert u deze in code .

De volgende appsettings. Development.json bestand wordt gegenereerd door de .NET Worker-servicesjablonen:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  }
}

In de voorgaande JSON:

  • De "Default"categorieën en "Microsoft""Microsoft.Hosting.Lifetime" logboekniveaus worden opgegeven.
  • De "Default" waarde is van toepassing op alle categorieën die niet anders zijn opgegeven, waardoor alle standaardwaarden voor alle categorieën "Information"effectief worden gemaakt. Overschrijf dit gedrag door een waarde voor een categorie op te geven.
  • De "Microsoft" categorie is van toepassing op alle categorieën die beginnen met "Microsoft".
  • De "Microsoft" categorie registreert op een logniveau van Warning en hoger.
  • De "Microsoft.Hosting.Lifetime" categorie is specifieker dan de "Microsoft" categorie, dus de "Microsoft.Hosting.Lifetime" categorielogboeken op logboekniveau "Information" en hoger.
  • Er is geen specifieke logboekprovider opgegeven, dus LogLevel geldt dit voor alle ingeschakelde logboekregistratieproviders, met uitzondering van de Windows EventLog.

De eigenschap Logging kan provider- en logeigenschappen LogLevel hebben. De LogLevel specificeert het minimale niveau dat moet worden vastgelegd voor geselecteerde categorieën. In de voorgaande JSON worden de logniveaus Information en Warning opgegeven. LogLevel geeft de ernst van het logboek aan en varieert van 0 tot 6:

Trace = 0, Debug = 1, Information = 2, Warning = 3, Error = 4, Critical = 5 en None = 6.

Wanneer een LogLevel opgegeven is, wordt logboekregistratie ingeschakeld voor berichten op het opgegeven niveau en hoger. In de voorgaande JSON wordt de Default categorie geregistreerd voor Information en hoger. Bijvoorbeeld, Information, Warningen ErrorCritical berichten worden vastgelegd. Als er geen LogLevel is opgegeven, wordt logboekregistratie standaard ingesteld op het Information niveau. Zie Logboekniveaus voor meer informatie.

Een providereigenschap kan een LogLevel eigenschap opgeven. LogLevel onder een provider geeft de niveaus op die moeten worden vastgelegd voor die provider en overschrijft de logboekinstellingen die niet van de provider zijn. Houd rekening met het volgende appsettings.json-bestand :

{
    "Logging": {
        "LogLevel": {
            "Default": "Error",
            "Microsoft": "Warning"
        },
        "Debug": {
            "LogLevel": {
                "Default": "Information",
                "Microsoft.Hosting": "Trace"
            }
        },
        "EventSource": {
            "LogLevel": {
                "Default": "Warning"
            }
        }
    }
}

Instellingen in Logging.{ProviderName}.LogLevel overschrijven instellingen in Logging.LogLevel. In de voorgaande JSON is het standaardlogboekniveau van de Debug provider ingesteld op Information:

Logging:Debug:LogLevel:Default:Information

Met de voorgaande instelling wordt het Information logboekniveau voor elke Logging:Debug: categorie opgegeven, behalve Microsoft.Hosting. Wanneer een specifieke categorie wordt weergegeven, overschrijft de specifieke categorie de standaardcategorie. In de voorgaande JSON overschrijven de Logging:Debug:LogLevel categorieën "Microsoft.Hosting" en "Default" de instellingen in Logging:LogLevel.

Geef het minimale logboekniveau op voor een van deze:

  • Specifieke providers: bijvoorbeeld Logging:EventSource:LogLevel:Default:Information
  • Specifieke categorieën: bijvoorbeeld Logging:LogLevel:Microsoft:Warning
  • Alle aanbieders en alle categorieën: Logging:LogLevel:Default:Warning

Logboeken onder het minimumniveau worden niet weergegeven:

  • Doorgegeven aan de provider.
  • Geregistreerd of weergegeven.

Als u alle logboeken wilt onderdrukken, geeft u LogLevel.None op. LogLevel.None heeft een waarde van 6, die hoger is dan LogLevel.Critical (5).

Als een provider logboekbereiken ondersteunt, IncludeScopes geeft aan of deze zijn ingeschakeld. Zie logboekbereikenvoor meer informatie.

Het volgende appsettings.json bestand bevat instellingen voor alle ingebouwde providers:

{
    "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"
            }
        }
    }
}

In het voorgaande voorbeeld:

  • De categorieën en niveaus zijn geen voorgestelde waarden. In het voorbeeld ziet u alle standaardproviders.
  • Instellingen in Logging.{ProviderName}.LogLevel overschrijven instellingen in Logging.LogLevel. Bijvoorbeeld, het niveau in Debug.LogLevel.Default overschrijdt het niveau in LogLevel.Default.
  • De alias van elke provider wordt gebruikt. Elke provider definieert een alias die u in de configuratie kunt gebruiken in plaats van de volledig gekwalificeerde typenaam. De aliassen van de ingebouwde providers zijn:
    • Console
    • Debug
    • EventSource
    • EventLog
    • AzureAppServicesFile
    • AzureAppServicesBlob
    • ApplicationInsights

Logboekniveau instellen op opdrachtregel, omgevingsvariabelen en andere configuratie

Stel het logboekniveau in met behulp van een van de configuratieproviders. Maak bijvoorbeeld een persistente omgevingsvariabele met de naam Logging:LogLevel:Microsoft met een waarde van Information.

Maak en wijs persistente omgevingsvariabele toe op basis van de waarde van het logboekniveau.

:: Assigns the env var to the value
setx "Logging__LogLevel__Microsoft" "Information" /M

Lees de omgevingsvariabele in een nieuw exemplaar van de opdrachtprompt.

:: Prints the env var value
echo %Logging__LogLevel__Microsoft%

De voorgaande omgevingsinstelling blijft behouden in de omgeving. Als u de instellingen wilt testen wanneer u een app gebruikt die is gemaakt met de .NET Worker-servicesjablonen, gebruikt u de dotnet run opdracht in de projectmap nadat de omgevingsvariabele is toegewezen.

dotnet run

Aanbeveling

Nadat u een omgevingsvariabele hebt ingesteld, start u uw IDE (Integrated Development Environment) opnieuw op om ervoor te zorgen dat nieuw toegevoegde omgevingsvariabelen beschikbaar zijn.

Selecteer op Azure-app Service de optie Nieuwe toepassingsinstelling Azure-app servicetoepassingsinstellingen zijn:

  • Versleuteld at-rest en verzonden via een versleuteld kanaal.
  • Weergegeven als omgevingsvariabelen.

Zie omgevingsvariabelen voor meer informatie over het instellen van .NET-configuratiewaarden met behulp van omgevingsvariabelen.

Logboekregistratie configureren met code

Gebruik de ILoggingBuilder API om logboekregistratie in code te configureren. U kunt deze openen vanaf verschillende locaties:

In dit voorbeeld ziet u hoe u de provider voor consolelogboekregistratie en verschillende filters instelt.

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");

In het voorgaande voorbeeld AddFilterpast u het logboekniveau aan dat is ingeschakeld voor verschillende categorieën. AddConsole voegt de provider voor consolelogging toe. Logboeken met Debug ernst zijn standaard niet ingeschakeld, maar omdat de configuratie de filters heeft aangepast, wordt het foutopsporingsbericht Hallo iedereen weergegeven op de console.

Hoe filterregels worden toegepast

Wanneer een ILogger<TCategoryName> object wordt gemaakt, selecteert het ILoggerFactory object één regel per provider die op die logboekregistratie moet worden toegepast. Het ILogger-exemplaar filtert alle berichten die het schrijft op basis van de geselecteerde regels. De meest specifieke regel voor elk provider- en categoriepaar is geselecteerd op basis van de beschikbare regels.

Het volgende algoritme wordt gebruikt voor elke provider wanneer een ILogger wordt gemaakt voor een bepaalde categorie:

  • Selecteer alle regels die overeenkomen met de aanbieder of het alias. Als er geen overeenkomst wordt gevonden, selecteer alle regels met een lege aanbieder.
  • Selecteer in het resultaat van de vorige stap regels met het langste overeenkomende categorievoorvoegsel. Als er geen overeenkomst wordt gevonden, selecteert u alle regels die geen categorie opgeven.
  • Als er meerdere regels zijn geselecteerd, neemt u de laatste regel.
  • Als er geen regels zijn geselecteerd, gebruikt LoggingBuilderExtensions.SetMinimumLevel(ILoggingBuilder, LogLevel) u deze optie om het minimale logboekregistratieniveau op te geven.

Logboekcategorie

Wanneer een ILogger object wordt gemaakt, wordt er een categorie opgegeven. Deze categorie is opgenomen in elk logboekbericht dat is gemaakt door dat exemplaar van ILogger. De categorietekenreeks is willekeurig, maar de conventie is het gebruik van de volledig gekwalificeerde klassenaam. In een toepassing met een service die is gedefinieerd als het volgende object, kan de categorie bijvoorbeeld zijn "Example.DefaultService":

namespace Example
{
    public class DefaultService : IService
    {
        private readonly ILogger<DefaultService> _logger;

        public DefaultService(ILogger<DefaultService> logger) =>
            _logger = logger;

        // ...
    }
}

Als verdere categorisatie gewenst is, is het de conventie om een hiërarchische naam te gebruiken door een subcategorie toe te voegen aan de volledig gekwalificeerde klassenaam en expliciet de categorie op te geven met behulp van LoggerFactory.CreateLogger:

namespace Example
{
    public class DefaultService : IService
    {
        private readonly ILogger _logger;

        public DefaultService(ILoggerFactory loggerFactory) =>
            _logger = loggerFactory.CreateLogger("Example.DefaultService.CustomCategory");

        // ...
    }
}

Aanroepen van CreateLogger met een vaste naam is handig bij gebruik in meerdere klassen/typen, waardoor de gebeurtenissen op categorie kunnen worden georganiseerd.

ILogger<T> is gelijk aan het aanroepen CreateLogger met de volledig gekwalificeerde typenaam van T.

Logniveau

De volgende tabel bevat de LogLevel waarden, de gemaksextensiemethode Log{LogLevel} en het voorgestelde gebruik:

Logniveau Waarde Wijze Beschrijving
Spoor 0 LogTrace De meest gedetailleerde berichten bevatten. Deze berichten bevatten mogelijk gevoelige app-gegevens. Deze berichten zijn standaard uitgeschakeld en mogen niet worden ingeschakeld in productie.
Fouten opsporen 1 LogDebug Voor foutopsporing en ontwikkeling. Wees voorzichtig bij de productie vanwege het grote volume.
Informatie 2 LogInformation Houdt de algemene stroom van de app bij. Kan een langetermijnwaarde hebben.
Waarschuwing 3 LogWarning Voor abnormale of onverwachte gebeurtenissen. Bevat meestal fouten of voorwaarden die ervoor zorgen dat de app niet mislukt.
Fout 4 LogError Voor fouten en uitzonderingen die niet kunnen worden verwerkt. Deze berichten geven een fout aan in de huidige bewerking of aanvraag, niet een fout in de hele app.
Kritiek 5 LogCritical Voor fouten die onmiddellijk aandacht vereisen. Voorbeelden: scenario's voor gegevensverlies, onvoldoende schijfruimte.
Geen 6 Hiermee geeft u op dat er geen berichten moeten worden geschreven.

In de vorige tabel wordt de LogLevel van laag naar hoog weergegeven op basis van ernst.

De eerste parameter van de logmethode , LogLevelgeeft de ernst van het logboek aan. In plaats van aan te roepen Log(LogLevel, ...), noemen de meeste ontwikkelaars de extensiemethoden Log{LogLevel} . De Log{LogLevel} extensiemethoden roepen de Log methode aan en specificeren de LogLevel. De volgende twee aanroepen voor logboekregistratie zijn bijvoorbeeld functioneel equivalent en produceren hetzelfde logboek:

public void LogDetails()
{
    var logMessage = "Details for log.";

    _logger.Log(LogLevel.Information, AppLogEvents.Details, logMessage);
    _logger.LogInformation(AppLogEvents.Details, logMessage);
}

AppLogEvents.Details is de gebeurtenis-id en wordt impliciet vertegenwoordigd door een constante Int32 waarde. AppLogEvents is een klasse die verschillende benoemde id-constanten weergeeft en wordt weergegeven in de sectie Logboekgebeurtenis-id .

De volgende code creëert Information en Warning logboeken.

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;
}

In de voorgaande code is de eerste Log{LogLevel} parameter, AppLogEvents.Readde gebeurtenis-id van het logboek. De tweede parameter is een berichtsjabloon met tijdelijke aanduidingen voor argumentwaarden die worden geleverd door de resterende methodeparameters. De methodeparameters worden verderop in dit artikel uitgelegd in de sectie berichtsjabloon .

Configureer het juiste logboekniveau en roep de juiste Log{LogLevel} methoden aan om te bepalen hoeveel logboekuitvoer naar een bepaald opslagmedium wordt geschreven. Voorbeeld:

  • In productie:
    • Loggen op de Trace- of Debug-niveaus produceert veel gedetailleerde logboekberichten. Als u de kosten wilt beheersen en niet de limieten voor gegevensopslag wilt overschrijden, log dan Trace- en Debug-niveau berichten naar een gegevensarchief met een hoog volume en lage kosten. Overweeg het beperken Trace van en Debug tot specifieke categorieën.
    • Logging op Warning en Critical niveaus moet weinig logberichten opleveren.
      • Kosten- en opslaglimieten zijn meestal geen probleem.
      • Enkele logboeken bieden meer flexibiliteit in keuzes voor gegevensopslag.
  • In ontwikkeling:
    • Ingesteld op Warning.
    • Voeg Trace of Debug berichten toe bij het oplossen van problemen. Als u de uitvoer wilt beperken, stelt u deze in Trace of Debug alleen voor de categorieën die worden onderzocht.

De volgende JSON-sets Logging:Console:LogLevel:Microsoft:Information:

{
    "Logging": {
        "LogLevel": {
            "Microsoft": "Warning"
        },
        "Console": {
            "LogLevel": {
                "Microsoft": "Information"
            }
        }
    }
}

Logboekgebeurtenis-ID

Elk logboek kan een gebeurtenisidentificator opgeven, de structuur EventId bevat een Id en optionele alleen-lezen Name eigenschappen. De voorbeeldbroncode gebruikt de AppLogEvents klasse om gebeurtenis-id's te definiëren:

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;

    // ...
}

Een gebeurtenis-id koppelt een set gebeurtenissen. Alle logboeken met betrekking tot het lezen van waarden uit een opslagplaats kunnen bijvoorbeeld zijn 1001.

De logboekregistratieprovider kan de gebeurtenis-id registreren in een id-veld, in het logboekbericht of helemaal niet. De foutopsporingsprovider toont geen gebeurtenis-id's. De consoleprovider toont gebeurtenis-ID's tussen vierkante haken na de categorie:

info: Example.DefaultService.GetAsync[1001]
      Reading value for a1b2c3
warn: Example.DefaultService.GetAsync[4000]
      GetAsync(a1b2c3) not found

Sommige logboekproviders slaan de gebeurtenis-id op in een veld, waardoor de id kan worden gefilterd.

Sjabloon voor logboekberichten

Elke logboek-API maakt gebruik van een berichtsjabloon. De berichtsjabloon kan tijdelijke aanduidingen bevatten waarvoor argumenten worden opgegeven. Gebruik namen voor de tijdelijke aanduidingen, niet voor getallen. De volgorde van tijdelijke aanduidingen, niet hun namen, bepaalt welke parameters worden gebruikt om hun waarden op te geven. In de volgende code zijn de parameternamen niet op volgorde in de berichtsjabloon:

string p1 = "param1";
string p2 = "param2";
_logger.LogInformation("Parameter values: {p2}, {p1}", p1, p2);

Met de voorgaande code wordt een logboekbericht gemaakt met de parameterwaarden in volgorde:

Parameter values: param1, param2

Notitie

Houd rekening met het gebruik van meerdere tijdelijke aanduidingen binnen één berichtsjabloon, omdat deze op volgorde zijn gebaseerd. De namen worden niet gebruikt om de argumenten uit te lijnen op de tijdelijke aanduidingen.

Met deze methode kunnen logboekproviders semantische of gestructureerde logboekregistratie implementeren. De argumenten zelf worden doorgegeven aan het logboekregistratiesysteem, niet alleen de opgemaakte berichtsjabloon. Hierdoor kunnen logboekproviders de parameterwaarden opslaan als velden. Houd rekening met de volgende loggermethode:

_logger.LogInformation("Getting item {Id} at {RunTime}", id, DateTime.Now);

Bijvoorbeeld wanneer u zich aanmeldt bij Azure Table Storage:

  • Elke Azure Table-entiteit kan ID- en RunTime-eigenschappen hebben.
  • Tabellen met eigenschappen vereenvoudigen query's op vastgelegde gegevens. Een query kan bijvoorbeeld alle logboeken binnen een bepaald RunTime bereik vinden zonder de time-out van het tekstbericht te hoeven parseren.

Opmaak van sjabloon voor logboekberichten

Logboekberichtsjablonen ondersteunen de opmaak van tijdelijke aanduidingen. Sjablonen kunnen elke geldige notatie opgeven voor het opgegeven typeargument. Denk bijvoorbeeld aan de volgende Information sjabloon voor logboekberichten:

_logger.LogInformation("Logged on {PlaceHolderName:MMMM dd, yyyy}", DateTimeOffset.UtcNow);
// Logged on January 06, 2022

In het voorgaande voorbeeld is het DateTimeOffset exemplaar het type dat overeenkomt met de PlaceHolderName sjabloon voor het logboekbericht. Deze naam kan alles zijn, omdat de waarden ordinaal zijn. De MMMM dd, yyyy notatie is geldig voor het DateTimeOffset type.

Zie voor meer informatie over DateTime- en DateTimeOffset-opmaak Tekenreeksen voor aangepaste datum- en tijdnotatie.

Voorbeelden

In de volgende voorbeelden ziet u hoe u een berichtsjabloon kunt formatteren met behulp van de {} tijdelijke aanduiding syntaxis. Daarnaast wordt een voorbeeld gegeven van het ontduiken van de {}-placeholder-syntaxis, samen met de uitvoer. Ten slotte wordt ook stringinterpolatie met sjabloon tijdelijke aanduidingen weergegeven.

logger.LogInformation("Number: {Number}", 1);               // Number: 1
logger.LogInformation("{{Number}}: {Number}", 3);           // {Number}: 3
logger.LogInformation($"{{{{Number}}}}: {{Number}}", 5);    // {Number}: 5

Aanbeveling

  • In de meeste gevallen moet u sjabloonopmaak voor logboekberichten gebruiken bij logboekregistratie. Het gebruik van tekenreeksinterpolatie kan prestatieproblemen veroorzaken.
  • Codeanalyseregel CA2254: Sjabloon moet een statische expressie zijn om u te waarschuwen bij plaatsen waar uw logboekberichten niet de juiste opmaak gebruiken.

Uitzonderingen in logboeken

De logboekregistratiemethoden hebben overbelastingen die een uitzonderingsparameter gebruiken:

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);
    }
}

Uitzonderingslogboekregistratie is providerspecifiek.

Standaardlogboekniveau

Als het standaardlogboekniveau niet is ingesteld, is Informationde standaardwaarde voor het logboekniveau.

Denk bijvoorbeeld aan de volgende werkservice-app:

  • Gemaakt met de .NET Worker-sjablonen.
  • appsettings.json en appsettings. Development.json verwijderd of hernoemd.

Met de voorgaande installatie produceert het navigeren naar de privacy- of startpagina veel Trace, Debugen Information berichten met Microsoft de categorienaam.

Met de volgende code wordt het standaardlogboekniveau ingesteld wanneer het standaardlogboekniveau niet is ingesteld in de configuratie:

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Logging.SetMinimumLevel(LogLevel.Warning);

using IHost host = builder.Build();

await host.RunAsync();

Filterfunctie

Er wordt een filterfunctie aangeroepen voor alle providers en categorieën waaraan geen regels zijn toegewezen door configuratie of code:

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();

In de voorgaande code worden consolelogs weergegeven wanneer de categorie Example of Microsoft bevat en het logniveau Information of hoger is.

Logboekbereiken

Een bereik groept een set logische bewerkingen. Met deze groepering kunnen dezelfde gegevens worden gekoppeld aan elk logboek dat is gemaakt als onderdeel van een set. Elk logboek dat is gemaakt als onderdeel van het verwerken van een transactie, kan bijvoorbeeld de transactie-id bevatten.

Een bereik:

  • Is een IDisposable type dat wordt geretourneerd door de BeginScope methode.
  • Duurt totdat het wordt verwijderd.

De volgende providers ondersteunen scopes:

Gebruik een bereik door logboekoproepen in een using blok te verpakken:

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;
}

Met de volgende JSON-code worden bereiken voor de consoleprovider mogelijk gemaakt.

{
    "Logging": {
        "Debug": {
            "LogLevel": {
                "Default": "Information"
            }
        },
        "Console": {
            "IncludeScopes": true,
            "LogLevel": {
                "Microsoft": "Warning",
                "Default": "Information"
            }
        },
        "LogLevel": {
            "Default": "Debug"
        }
    }
}

Met de volgende code worden scopes voor de console-provider ingeschakeld.

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Logging.ClearProviders();
builder.Logging.AddSimpleConsole(options => options.IncludeScopes = true);

using IHost host = builder.Build();

await host.RunAsync();

Logboeken maken in Main

De volgende code logt in Main door een ILogger exemplaar vanuit DI te verkrijgen nadat de host is opgebouwd.

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();

De voorgaande code is afhankelijk van twee NuGet-pakketten:

Het projectbestand ziet er ongeveer als volgt uit:

<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>

Geen asynchrone logboekregistratiemethoden

Logboekregistratie moet zo snel zijn dat het de prestatiekosten van asynchrone code niet waard is. Als een gegevensarchief voor logboekregistratie traag is, moet u er niet rechtstreeks naar schrijven. Overweeg eerst de logboekberichten naar een snelle opslag te schrijven en ze later naar een langzamere opslag te verplaatsen. Als u zich bijvoorbeeld aanmeldt bij SQL Server, doet u dit niet rechtstreeks in een Log methode, omdat de Log methoden synchroon zijn. Voeg in plaats daarvan synchroon logboekberichten toe aan een wachtrij in het geheugen en laat een achtergrondmedewerker de berichten uit de wachtrij halen om het asynchrone werk van het pushen van gegevens naar SQL Server uit te voeren.

Logboekniveaus wijzigen in een actieve app

De Logboekregistratie-API bevat geen scenario om logboekniveaus te wijzigen terwijl een app wordt uitgevoerd. Sommige configuratieproviders kunnen de configuratie echter opnieuw laden, wat direct van invloed is op de configuratie van logboekregistratie. De Bestandsconfiguratieprovider laadt bijvoorbeeld standaard de loggingconfiguratie opnieuw. Als u de configuratie in code wijzigt terwijl een app wordt uitgevoerd, kan de app IConfigurationRoot.Reload aanroepen om de logboekregistratieconfiguratie van de app bij te werken.

NuGet-pakketten

ILogger<TCategoryName> De ILoggerFactory interfaces en implementaties zijn opgenomen in de meeste .NET SDK's als impliciete pakketreferentie. Ze zijn ook expliciet beschikbaar in de volgende NuGet-pakketten wanneer er niet anders impliciet naar verwezen wordt.

Zie .NET SDK: tabel naar impliciete naamruimte voor meer informatie over welke .NET SDK impliciete pakketverwijzingen bevat.

Zie ook