Movatterモバイル変換


[0]ホーム

URL:


Skip to main content

This browser is no longer supported.

Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.

Download Microsoft EdgeMore info about Internet Explorer and Microsoft Edge
Table of contentsExit editor mode

Logging in C# and .NET

Feedback

In this article

.NET supports high performance, structured logging via theILogger API to help monitor application behavior and diagnose issues. Configure differentlogging providers to write logs to different destinations. Basic logging providers are built-in, and many third-party providers are available.

Get started

This first example shows the basics, but it's only suitable for a trivial console app. This sample console app relies on the following NuGet packages:

In the next section you see how to improve the code considering scale, performance, configuration, and typical programming patterns.

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

The preceding example:

  • Creates anILoggerFactory. TheILoggerFactory stores all the configuration that determines where log messages are sent. In this case, configure the consolelogging provider so that log messages are written to the console.
  • Creates anILogger with a category named "Program". Thecategory is astring that's associated with each message logged by theILogger object. It groups log messages from the same class (or category) together when searching or filtering logs.
  • CallsLogInformation to log a message at theInformation level. Thelog level indicates the severity of the logged event and filters out less important log messages. The log entry also includes amessage template"Hello World! Logging is {Description}." and a key-value pairDescription = fun. The key name (or placeholder) comes from the word inside the curly braces in the template, and the value comes from the remaining method argument.

This project file for this example includes two NuGet packages:

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

Tip

All of the logging example source code is available in theSamples Browser for download. For more information, seeBrowse code samples: Logging in .NET.

Logging in a non-trivial app

Consider making these changes to the previous example when logging in a less trivial scenario:

  • If your application usesDependency Injection (DI) or a host such as ASP.NET'sWebApplication orGeneric Host, useILoggerFactory andILogger objects from their respective DI containers rather than creating them directly. For more information, seeIntegration with DI and Hosts.

  • Loggingcompile-time source generation is usually a better alternative toILogger extension methods likeLogInformation. Logging source generation offers better performance, stronger typing, and avoids spreadingstring constants throughout your methods. The tradeoff is that using this technique requires a bit more code.

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);}
  • The recommended practice for log category names is to use the fully qualified name of the class that's creating the log message. This helps relate log messages back to the code that produced them and offers a good level of control when filtering logs.CreateLogger accepts aType to make this naming easy to do.
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");

Integration with hosts and dependency injection

If your application usesDependency Injection (DI) or a host such as ASP.NET'sWebApplication orGeneric Host, useILoggerFactory andILogger objects from the DI container rather than creating them directly.

Get an ILogger from DI

This example gets an ILogger object in a hosted app usingASP.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);}

The preceding example:

  • Created a singleton service calledExampleHandler and mapped incoming web requests to run theExampleHandler.HandleRequest function.
  • Line 12 defines aprimary constructor for the ExampleHandler, a feature added in C# 12. Using the older style C# constructor works equally well but is a little more verbose.
  • The constructor defines a parameter of typeILogger<ExampleHandler>.ILogger<TCategoryName> derives fromILogger and indicates which category theILogger object has. The DI container locates anILogger with the correct category and supplies it as the constructor argument. If noILogger with that category exists yet, the DI container automatically creates it from theILoggerFactory in the service provider.
  • Thelogger parameter received in the constructor is used for logging in theHandleRequest function.

Host-provided ILoggerFactory

Host builders initializedefault configuration, then add a configuredILoggerFactory object to the host's DI container when the host is built. Before the host is built, adjust the logging configuration viaHostApplicationBuilder.Logging,WebApplicationBuilder.Logging, or similar APIs on other hosts. Hosts also apply logging configuration from default configuration sources likeappsettings.json and environment variables. For more information, seeConfiguration in .NET.

This example expands on the previous one to customize theILoggerFactory provided byWebApplicationBuilder. It addsOpenTelemetry as a logging provider transmitting the logs overOTLP (OpenTelemetry protocol):

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

Create an ILoggerFactory with DI

If you're using a DI container without a host, useAddLogging to configure and addILoggerFactory to the container.

using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Logging;// Add services to the container including loggingvar services = new ServiceCollection();services.AddLogging(builder => builder.AddConsole());services.AddSingleton<ExampleService>();IServiceProvider serviceProvider = services.BuildServiceProvider();// Get the ExampleService object from the containerExampleService service = serviceProvider.GetRequiredService<ExampleService>();// Do some pretend workservice.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);    }}

The preceding example:

  • Created a DI service container containing anILoggerFactory configured to write to the console
  • Added a singletonExampleService to the container
  • Created an instance of theExampleService from the DI container, which also automatically created anILogger<ExampleService> to use as the constructor argument.
  • InvokedExampleService.DoSomeWork, which used theILogger<ExampleService> to log a message to the console.

Configure logging

Set logging configuration in code or via external sources, such as config files and environment variables. Using external configuration is beneficial when possible because you can change it without rebuilding the application. However, some tasks, such as setting logging providers, can only be configured from code.

Configure logging without code

For apps thatuse a host, the"Logging" section ofappsettings.{Environment}.json files commonly provides logging configuration. For apps that don't use a host,set up external configuration sources explicitly orconfigure them in code instead.

The followingappsettings.Development.json file is generated by the .NET Worker service templates:

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

In the preceding JSON:

  • The"Default","Microsoft", and"Microsoft.Hosting.Lifetime" log level categories are specified.
  • The"Default" value applies to all categories that aren't otherwise specified, effectively making all default values for all categories"Information". Override this behavior by specifying a value for a category.
  • The"Microsoft" category applies to all categories that start with"Microsoft".
  • The"Microsoft" category logs at a log level ofWarning and higher.
  • The"Microsoft.Hosting.Lifetime" category is more specific than the"Microsoft" category, so the"Microsoft.Hosting.Lifetime" category logs at log level"Information" and higher.
  • A specific log provider isn't specified, soLogLevel applies to all the enabled logging providers except for theWindows EventLog.

TheLogging property can haveLogLevel and log provider properties. TheLogLevel specifies the minimumlevel to log for selected categories. In the preceding JSON,Information andWarning log levels are specified.LogLevel indicates the severity of the log and ranges from 0 to 6:

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

When aLogLevel is specified, logging is enabled for messages at the specified level and higher. In the preceding JSON, theDefault category is logged forInformation and higher. For example,Information,Warning,Error, andCritical messages are logged. If noLogLevel is specified, logging defaults to theInformation level. For more information, seeLog levels.

A provider property can specify aLogLevel property.LogLevel under a provider specifies levels to log for that provider, and overrides the non-provider log settings. Consider the followingappsettings.json file:

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

Settings inLogging.{ProviderName}.LogLevel override settings inLogging.LogLevel. In the preceding JSON, theDebug provider's default log level is set toInformation:

Logging:Debug:LogLevel:Default:Information

The preceding setting specifies theInformation log level for everyLogging:Debug: category exceptMicrosoft.Hosting. When a specific category is listed, the specific category overrides the default category. In the preceding JSON, theLogging:Debug:LogLevel categories"Microsoft.Hosting" and"Default" override the settings inLogging:LogLevel.

Specify the minimum log level for any of these:

  • Specific providers: For example,Logging:EventSource:LogLevel:Default:Information
  • Specific categories: For example,Logging:LogLevel:Microsoft:Warning
  • All providers and all categories:Logging:LogLevel:Default:Warning

Any logs below the minimum levelaren't:

  • Passed to the provider.
  • Logged or displayed.

To suppress all logs, specifyLogLevel.None.LogLevel.None has a value of 6, which is higher thanLogLevel.Critical (5).

If a provider supportslog scopes,IncludeScopes indicates whether they're enabled. For more information, seelog scopes.

The followingappsettings.json file contains settings for all of the built-in 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 the preceding sample:

  • The categories and levels aren't suggested values. The sample shows all the default providers.
  • Settings inLogging.{ProviderName}.LogLevel override settings inLogging.LogLevel. For example, the level inDebug.LogLevel.Default overrides the level inLogLevel.Default.
  • Each provider'salias is used. Each provider defines analias that you can use in configuration in place of the fully qualified type name. The built-in providers' aliases are:
    • Console
    • Debug
    • EventSource
    • EventLog
    • AzureAppServicesFile
    • AzureAppServicesBlob
    • ApplicationInsights

Set log level by command line, environment variables, and other configuration

Set the log level using any of theconfiguration providers. For example, create a persisted environment variable namedLogging:LogLevel:Microsoft with a value ofInformation.

Create and assign persisted environment variable, given the log level value.

:: Assigns the env var to the valuesetx "Logging__LogLevel__Microsoft" "Information" /M

In anew instance of theCommand Prompt, read the environment variable.

:: Prints the env var valueecho %Logging__LogLevel__Microsoft%

The preceding environment setting persists in the environment. To test the settings when using an app created with the .NET Worker service templates, use thedotnet run command in the project directory after the environment variable is assigned.

dotnet run

Tip

After setting an environment variable, restart your integrated development environment (IDE) to ensure that newly added environment variables are available.

OnAzure App Service, selectNew application setting on theSettings > Configuration page. Azure App Service application settings are:

  • Encrypted at rest and transmitted over an encrypted channel.
  • Exposed as environment variables.

For more information on setting .NET configuration values using environment variables, seeenvironment variables.

Configure logging with code

To configure logging in code, use theILoggingBuilder API. You can access it from different places:

This example shows setting the consolelogging provider and severalfilters.

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 the preceding example,AddFilteradjusts the log level that's enabled for various categories.AddConsole adds the console logging provider. By default, logs withDebug severity aren't enabled, but because the configuration adjusted the filters, the debug message "Hello Everyone" is displayed on the console.

How filtering rules are applied

When anILogger<TCategoryName> object is created, theILoggerFactory object selects a single rule per provider to apply to that logger. TheILogger instance filters all messages it writes based on the selected rules. The most specific rule for each provider and category pair is selected from the available rules.

The following algorithm is used for each provider when anILogger is created for a given category:

  • Select all rules that match the provider or its alias. If no match is found, select all rules with an empty provider.
  • From the result of the preceding step, select rules with longest matching category prefix. If no match is found, select all rules that don't specify a category.
  • If multiple rules are selected, take thelast one.
  • If no rules are selected, useLoggingBuilderExtensions.SetMinimumLevel(ILoggingBuilder, LogLevel) to specify the minimum logging level.

Log category

When anILogger object is created, acategory is specified. That category is included with each log message created by that instance ofILogger. The category string is arbitrary, but the convention is to use the fully qualified class name. For example, in an application with a service defined like the following object, the category might be"Example.DefaultService":

namespace Example{    public class DefaultService : IService    {        private readonly ILogger<DefaultService> _logger;        public DefaultService(ILogger<DefaultService> logger) =>            _logger = logger;        // ...    }}

If further categorization is desired, the convention is to use a hierarchical name by appending a subcategory to the fully qualified class name, and explicitly specify the category usingLoggerFactory.CreateLogger:

namespace Example{    public class DefaultService : IService    {        private readonly ILogger _logger;        public DefaultService(ILoggerFactory loggerFactory) =>            _logger = loggerFactory.CreateLogger("Example.DefaultService.CustomCategory");        // ...    }}

CallingCreateLogger with a fixed name is useful when used in multiple classes/types so the events can be organized by category.

ILogger<T> is equivalent to callingCreateLogger with the fully qualified type name ofT.

Log level

The following table lists theLogLevel values, the convenienceLog{LogLevel} extension method, and the suggested usage:

LogLevelValueMethodDescription
Trace0LogTraceContain the most detailed messages. These messages might contain sensitive app data. These messages are disabled by default and shouldnot be enabled in production.
Debug1LogDebugFor debugging and development. Use with caution in production due to the high volume.
Information2LogInformationTracks the general flow of the app. Might have long-term value.
Warning3LogWarningFor abnormal or unexpected events. Typically includes errors or conditions that don't cause the app to fail.
Error4LogErrorFor errors and exceptions that can't be handled. These messages indicate a failure in the current operation or request, not an app-wide failure.
Critical5LogCriticalFor failures that require immediate attention. Examples: data loss scenarios, out of disk space.
None6Specifies that no messages should be written.

In the previous table, theLogLevel is listed from lowest to highest severity.

TheLog method's first parameter,LogLevel, indicates the severity of the log. Rather than callingLog(LogLevel, ...), most developers call theLog{LogLevel} extension methods. TheLog{LogLevel} extension methods call theLog method and specify theLogLevel. For example, the following two logging calls are functionally equivalent and produce the same log:

public void LogDetails(){    var logMessage = "Details for log.";    _logger.Log(LogLevel.Information, AppLogEvents.Details, logMessage);    _logger.LogInformation(AppLogEvents.Details, logMessage);}

AppLogEvents.Details is the event ID, and is implicitly represented by a constantInt32 value.AppLogEvents is a class that exposes various named identifier constants and is displayed in theLog event ID section.

The following code createsInformation andWarning logs:

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 the preceding code, the firstLog{LogLevel} parameter,AppLogEvents.Read, is theLog event ID. The second parameter is a message template with placeholders for argument values provided by the remaining method parameters. The method parameters are explained in themessage template section later in this article.

Configure the appropriate log level and call the correctLog{LogLevel} methods to control how much log output is written to a particular storage medium. For example:

  • In production:
    • Logging at theTrace orDebug levels produces a high-volume of detailed log messages. To control costs and not exceed data storage limits, logTrace andDebug level messages to a high-volume, low-cost data store. Consider limitingTrace andDebug to specific categories.
    • Logging atWarning throughCritical levels should produce few log messages.
      • Costs and storage limits usually aren't a concern.
      • Few logs allow more flexibility in data store choices.
  • In development:
    • Set toWarning.
    • AddTrace orDebug messages when troubleshooting. To limit output, setTrace orDebug only for the categories under investigation.

The following JSON setsLogging:Console:LogLevel:Microsoft:Information:

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

Log event ID

Each log can specify anevent identifier, theEventId is a structure with anId and optionalName readonly properties. The sample source code uses theAppLogEvents class to define event IDs:

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

Tip

For more information on converting anint to anEventId, seeEventId.Implicit(Int32 to EventId) Operator.

An event ID associates a set of events. For example, all logs related to reading values from a repository might be1001.

The logging provider might log the event ID in an ID field, in the logging message, or not at all. The Debug provider doesn't show event IDs. The console provider shows event IDs in brackets after the category:

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

Some logging providers store the event ID in a field, which allows for filtering on the ID.

Log message template

Each log API uses a message template. The message template can contain placeholders for which arguments are provided. Use names for the placeholders, not numbers. The order of placeholders, not their names, determines which parameters are used to provide their values. In the following code, the parameter names are out of sequence in the message template:

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

The preceding code creates a log message with the parameter values in sequence:

Parameter values: param1, param2

Note

Be mindful when using multiple placeholders within a single message template, as they're ordinal-based. The names aren't used to align the arguments to the placeholders.

This approach lets logging providers implementsemantic or structured logging. The arguments themselves are passed to the logging system, not just the formatted message template. This enables logging providers to store the parameter values as fields. Consider the following logger method:

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

For example, when logging to Azure Table Storage:

  • Each Azure Table entity can haveID andRunTime properties.
  • Tables with properties simplify queries on logged data. For example, a query can find all logs within a particularRunTime range without having to parse the time out of the text message.

Log message template formatting

Log message templates support placeholder formatting. Templates can specifyany valid format for the given type argument. For example, consider the followingInformation logger message template:

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

In the preceding example, theDateTimeOffset instance is the type that corresponds to thePlaceHolderName in the logger message template. This name can be anything as the values are ordinal-based. TheMMMM dd, yyyy format is valid for theDateTimeOffset type.

For more information onDateTime andDateTimeOffset formatting, seeCustom date and time format strings.

Examples

The following examples show how to format a message template using the{} placeholder syntax. Additionally, an example of escaping the{} placeholder syntax is shown with its output. Finally, string interpolation with templating placeholders is also shown:

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

Tip

  • In most cases, you should use log message template formatting when logging. Use of string interpolation can cause performance issues.
  • Code analysis ruleCA2254: Template should be a static expression helps alert you to places where your log messages don't use proper formatting.

Log exceptions

The logger methods have overloads that take an exception parameter:

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

Exception logging is provider-specific.

Default log level

If the default log level isn't set, the default log level value isInformation.

For example, consider the following worker service app:

  • Created with the .NET Worker templates.
  • appsettings.json andappsettings.Development.json deleted or renamed.

With the preceding setup, navigating to the privacy or home page produces manyTrace,Debug, andInformation messages withMicrosoft in the category name.

The following code sets the default log level when the default log level isn't set in configuration:

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);builder.Logging.SetMinimumLevel(LogLevel.Warning);using IHost host = builder.Build();await host.RunAsync();

Filter function

A filter function is invoked for all providers and categories that don't have rules assigned to them by configuration or 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();

The preceding code displays console logs when the category containsExample orMicrosoft and the log level isInformation or higher.

Log scopes

Ascope groups a set of logical operations. This grouping can attach the same data to each log that's created as part of a set. For example, every log created as part of processing a transaction can include the transaction ID.

A scope:

The following providers support scopes:

Use a scope by wrapping logger calls in ausing 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;}

The following JSON enables scopes for the console provider:

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

The following code enables scopes for the console provider:

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);builder.Logging.ClearProviders();builder.Logging.AddSimpleConsole(options => options.IncludeScopes = true);using IHost host = builder.Build();await host.RunAsync();

Create logs in Main

The following code logs inMain by getting anILogger instance from DI after building the host:

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

The preceding code relies on two NuGet packages:

Its project file looks similar to the following:

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

No asynchronous logger methods

Logging should be so fast that it isn't worth the performance cost of asynchronous code. If a logging datastore is slow, don't write to it directly. Consider writing the log messages to a fast store initially, then moving them to the slow store later. For example, when logging to SQL Server, don't do so directly in aLog method, since theLog methods are synchronous. Instead, synchronously add log messages to an in-memory queue and have a background worker pull the messages out of the queue to do the asynchronous work of pushing data to SQL Server.

Change log levels in a running app

The Logging API doesn't include a scenario to change log levels while an app is running. However, some configuration providers can reload configuration, which takes immediate effect on logging configuration. For example, theFile Configuration Provider reloads logging configuration by default. If you change the configuration in code while an app is running, the app can callIConfigurationRoot.Reload to update the app's logging configuration.

NuGet packages

TheILogger<TCategoryName> andILoggerFactory interfaces and implementations are included in most .NET SDKs as implicit package reference. They're also available explicitly in the following NuGet packages when not otherwise implicitly referenced:

For more information about which .NET SDK includes implicit package references, see.NET SDK: table to implicit namespace.

See also

Collaborate with us on GitHub
The source for this content can be found on GitHub, where you can also create and review issues and pull requests. For more information, seeour contributor guide.

Feedback

Was this page helpful?

YesNoNo

Need help with this topic?

Want to try using Ask Learn to clarify or guide you through this topic?

Suggest a fix?

  • Last updated on

In this article

Was this page helpful?

YesNo
NoNeed help with this topic?

Want to try using Ask Learn to clarify or guide you through this topic?

Suggest a fix?