diff --git a/.openpublishing.redirection.core.json b/.openpublishing.redirection.core.json index b669b8d5860d4..51a772404282d 100644 --- a/.openpublishing.redirection.core.json +++ b/.openpublishing.redirection.core.json @@ -1165,6 +1165,42 @@ "source_path_from_root": "/docs/core/extensions/dependency-injection-usage.md", "redirect_url": "/dotnet/core/extensions/dependency-injection/usage" }, + { + "source_path_from_root": "/docs/core/extensions/high-performance-logging.md", + "redirect_url": "/dotnet/core/extensions/logging/high-performance-logging" + }, + { + "source_path_from_root": "/docs/core/extensions/console-log-formatter.md", + "redirect_url": "/dotnet/core/extensions/logging/console-log-formatter" + }, + { + "source_path_from_root": "/docs/core/extensions/custom-logging-provider.md", + "redirect_url": "/dotnet/core/extensions/logging/custom-provider" + }, + { + "source_path_from_root": "/docs/core/extensions/logging-library-authors.md", + "redirect_url": "/dotnet/core/extensions/logging/library-guidance" + }, + { + "source_path_from_root": "/docs/core/extensions/log-buffering.md", + "redirect_url": "/dotnet/core/extensions/logging/log-buffering" + }, + { + "source_path_from_root": "/docs/core/extensions/log-sampling.md", + "redirect_url": "/dotnet/core/extensions/logging/log-sampling" + }, + { + "source_path_from_root": "/docs/core/extensions/logging.md", + "redirect_url": "/dotnet/core/extensions/logging/overview" + }, + { + "source_path_from_root": "/docs/core/extensions/logging-providers.md", + "redirect_url": "/dotnet/core/extensions/logging/providers" + }, + { + "source_path_from_root": "/docs/core/extensions/logger-message-generator.md", + "redirect_url": "/dotnet/core/extensions/logging/source-generation" + }, { "source_path_from_root": "/docs/core/getting-started.md", "redirect_url": "/dotnet/core/get-started", diff --git a/docs/core/diagnostics/diagnostic-resource-monitoring.md b/docs/core/diagnostics/diagnostic-resource-monitoring.md index 3e659c592770e..afe0371e9b7d9 100644 --- a/docs/core/diagnostics/diagnostic-resource-monitoring.md +++ b/docs/core/diagnostics/diagnostic-resource-monitoring.md @@ -14,7 +14,7 @@ The measurements can be consumed in two ways: - Using the interface. This interface is deprecated, so use the metrics-based approach instead. If you still need to listen to metric values manually, see [Migrate to metrics-based resource monitoring](#migrate-to-metrics-based-resource-monitoring). > [!IMPORTANT] -> The package assumes that the consumer will register logging providers with the `Microsoft.Extensions.Logging` package. If you don't register logging, the call to `AddResourceMonitoring` will throw an exception. Furthermore, you can enable internal library logging by configuring the [`Debug`](xref:Microsoft.Extensions.Logging.LogLevel.Debug) log level for the `Microsoft.Extensions.Diagnostics.ResourceMonitoring` category as per the [guide](../extensions/logging.md#log-category). +> The package assumes that the consumer will register logging providers with the `Microsoft.Extensions.Logging` package. If you don't register logging, the call to `AddResourceMonitoring` will throw an exception. Furthermore, you can enable internal library logging by configuring the [`Debug`](xref:Microsoft.Extensions.Logging.LogLevel.Debug) log level for the `Microsoft.Extensions.Diagnostics.ResourceMonitoring` category as per the [guide](../extensions/logging/overview.md#log-category). ## Use .NET metrics of resource monitoring diff --git a/docs/core/diagnostics/index.md b/docs/core/diagnostics/index.md index 1820a07b2077c..0696816809ed1 100644 --- a/docs/core/diagnostics/index.md +++ b/docs/core/diagnostics/index.md @@ -31,7 +31,7 @@ Instrumentation is code that is added to a software project to record what it is [Logging](logging-tracing.md) is a technique where code is instrumented to produce a log, a record of interesting events that occurred while the program was running. Often a baseline set of log events are configured on by default and more extensive logging can be enabled on-demand to diagnose particular problems. Performance overhead is variable depending on how much data is being logged. -For most cases, whether adding logging to an existing project or creating a new project, the [ILogger infrastructure](../extensions/logging.md) is a good default choice. `ILogger` supports fast structured logging, flexible configuration, and a collection of [common sinks](../extensions/logging-providers.md#built-in-logging-providers) including the console, which is what you see when running an ASP.NET app. Additionally, the `ILogger` interface can also serve as a facade over many [third party logging implementations](../extensions/logging-providers.md#third-party-logging-providers) that offer rich functionality and extensibility. +For most cases, whether adding logging to an existing project or creating a new project, the [ILogger infrastructure](../extensions/logging/overview.md) is a good default choice. `ILogger` supports fast structured logging, flexible configuration, and a collection of [common sinks](../extensions/logging/providers.md#built-in-logging-providers) including the console, which is what you see when running an ASP.NET app. Additionally, the `ILogger` interface can also serve as a facade over many [third party logging implementations](../extensions/logging/providers.md#third-party-logging-providers) that offer rich functionality and extensibility. ### Metrics diff --git a/docs/core/diagnostics/logging-tracing.md b/docs/core/diagnostics/logging-tracing.md index f720f25d85746..c6d9d16f8087e 100644 --- a/docs/core/diagnostics/logging-tracing.md +++ b/docs/core/diagnostics/logging-tracing.md @@ -14,7 +14,7 @@ Code can be instrumented to produce a log, which serves as a record of interesti ### ILogger -For most cases, whether adding logging to an existing project or creating a new project, the [ILogger infrastructure](../extensions/logging.md) is a good default choice. `ILogger` supports fast [structured logging](#structured-and-unstructured-logging), flexible configuration, and a collection of [common sinks](../extensions/logging-providers.md#built-in-logging-providers) including the console, which is what you see when running an ASP.NET app. Additionally, the `ILogger` interface can also serve as a facade over many [third party logging implementations](../extensions/logging-providers.md#third-party-logging-providers) that offer rich functionality and extensibility. +For most cases, whether adding logging to an existing project or creating a new project, the [ILogger infrastructure](../extensions/logging/overview.md) is a good default choice. `ILogger` supports fast [structured logging](#structured-and-unstructured-logging), flexible configuration, and a collection of [common sinks](../extensions/logging/providers.md#built-in-logging-providers) including the console, which is what you see when running an ASP.NET app. Additionally, the `ILogger` interface can also serve as a facade over many [third party logging implementations](../extensions/logging/providers.md#third-party-logging-providers) that offer rich functionality and extensibility. ILogger provides the logging story for the OpenTelemetry implementation for .NET, which enables egress of logs from your application to a variety of APM systems for further analysis. diff --git a/docs/core/diagnostics/metrics-strongly-typed.md b/docs/core/diagnostics/metrics-strongly-typed.md index 15339e5a96d4f..9abe78bb05891 100644 --- a/docs/core/diagnostics/metrics-strongly-typed.md +++ b/docs/core/diagnostics/metrics-strongly-typed.md @@ -120,4 +120,4 @@ Adhering to these requirements ensures that the source generator can successfull - [Source generated metrics in .NET](metrics-generator.md) - [Creating metrics in .NET (Instrumentation tutorial)](metrics-instrumentation.md) - [Collecting metrics in .NET (Using MeterListener and exporters)](metrics-collection.md) -- [Logging source generation in .NET](../extensions/logger-message-generator.md) (for a similar source-generation approach applied to logging) +- [Compile-time logging source generation](../extensions/logging/source-generation.md) (for a similar source-generation approach applied to logging) diff --git a/docs/core/diagnostics/observability-otlp-example.md b/docs/core/diagnostics/observability-otlp-example.md index 5fbb819632f2c..2d526c6049e19 100644 --- a/docs/core/diagnostics/observability-otlp-example.md +++ b/docs/core/diagnostics/observability-otlp-example.md @@ -115,7 +115,7 @@ Each time you request the page, it increments the count for the number of greeti ### 8.1 Log output -The logging statements from the code are output using `ILogger`. By default, the [Console Provider](../extensions/logging.md?tabs=command-line#configure-logging) is enabled so that output is directed to the console. +The logging statements from the code are output using `ILogger`. By default, the [Console Provider](../extensions/logging/overview.md?tabs=command-line#configure-logging) is enabled so that output is directed to the console. There are a few options for how logs can be egressed from .NET: diff --git a/docs/core/diagnostics/observability-prgrja-example.md b/docs/core/diagnostics/observability-prgrja-example.md index c68c30c8e940a..5e4f3f3e1b836 100644 --- a/docs/core/diagnostics/observability-prgrja-example.md +++ b/docs/core/diagnostics/observability-prgrja-example.md @@ -68,7 +68,7 @@ Each time you request the page, it increments the count for the number of greeti ### 6.1 Log output -The logging statements from the code are output using `ILogger`. By default, the [Console Provider](../extensions/logging.md?tabs=command-line#configure-logging) is enabled so that output is directed to the console. +The logging statements from the code are output using `ILogger`. By default, the [Console Provider](../extensions/logging/overview.md?tabs=command-line#configure-logging) is enabled so that output is directed to the console. There are a few options for how logs can be egressed from .NET: diff --git a/docs/core/diagnostics/observability-with-otel.md b/docs/core/diagnostics/observability-with-otel.md index d80794a9d6c67..1b5b194f71b91 100644 --- a/docs/core/diagnostics/observability-with-otel.md +++ b/docs/core/diagnostics/observability-with-otel.md @@ -18,7 +18,7 @@ Observability in the context of a distributed system is the ability to monitor a Observability is commonly done using a combination of: -- [Logs](../extensions/logging.md), which record individual operations, such as an incoming request, a failure in a specific component, or an order being placed. +- [Logs](../extensions/logging/overview.md), which record individual operations, such as an incoming request, a failure in a specific component, or an order being placed. - [Metrics](./metrics.md), which are measuring counters and gauges such as number of completed requests, active requests, widgets that have been sold; or a histogram of the request latency. - [Distributed tracing](./distributed-tracing.md), which tracks requests and activities across components in a distributed system so that you can see where time is spent and track down specific failures. @@ -56,7 +56,7 @@ There are OpenTelemetry implementations for most languages and platforms, includ The .NET OpenTelemetry implementation is a little different from other platforms, as .NET provides logging, metrics, and activity APIs in the framework. That means OTel doesn't need to provide APIs for library authors to use. The .NET OTel implementation uses these platform APIs for instrumentation: -- for [logging](../extensions/logging.md) +- for [logging](../extensions/logging/overview.md) - for [metrics](./metrics-instrumentation.md) - and for [distributed tracing](./distributed-tracing.md) diff --git a/docs/core/extensions/generic-host.md b/docs/core/extensions/generic-host.md index 4137dc979fcbb..c76f7487a7599 100644 --- a/docs/core/extensions/generic-host.md +++ b/docs/core/extensions/generic-host.md @@ -321,7 +321,7 @@ To ensure a smooth transition of clients to a new destination when working with ## See also - [Dependency injection in .NET](dependency-injection/overview.md) -- [Logging in .NET](logging.md) +- [Logging in .NET](logging/overview.md) - [Configuration in .NET](configuration.md) - [Worker Services in .NET](workers.md) - [ASP.NET Core Web Host](/aspnet/core/fundamentals/host/web-host) diff --git a/docs/core/extensions/high-performance-logging.md b/docs/core/extensions/high-performance-logging.md deleted file mode 100644 index d4d3d120a3d0a..0000000000000 --- a/docs/core/extensions/high-performance-logging.md +++ /dev/null @@ -1,163 +0,0 @@ ---- -title: High-performance logging -description: Learn how to use LoggerMessage to create cacheable delegates that require fewer object allocations for high-performance logging scenarios. -ms.date: 10/20/2025 ---- - -# High-performance logging in .NET - -The class exposes functionality to create cacheable delegates that require fewer object allocations and reduced computational overhead compared to [logger extension methods](xref:Microsoft.Extensions.Logging.LoggerExtensions), such as and . For high-performance logging scenarios, use the pattern. - - provides the following performance advantages over logger extension methods: - -- Logger extension methods require "boxing" (converting) value types, such as `int`, into `object`. The pattern avoids boxing by using static fields and extension methods with strongly typed parameters. -- Logger extension methods must parse the message template (named format string) every time a log message is written. only requires parsing a template once when the message is defined. - -> [!IMPORTANT] -> Instead of using the [LoggerMessage class](xref:Microsoft.Extensions.Logging.LoggerMessage) to create high-performance logs, you can use the [LoggerMessage attribute](xref:Microsoft.Extensions.Logging.LoggerMessageAttribute) in .NET 6 and later versions. The `LoggerMessageAttribute` provides source-generation logging support designed to deliver a highly usable and highly performant logging solution for modern .NET applications. For more information, see [Compile-time logging source generation (.NET Fundamentals)](./logger-message-generator.md). - -The sample app demonstrates features with a priority queue processing worker service. The app processes work items in priority order. As these operations occur, log messages are generated using the pattern. - -[!INCLUDE [logging-samples-browser](includes/logging-samples-browser.md)] - -## Define a logger message - -Use [Define(LogLevel, EventId, String)](xref:Microsoft.Extensions.Logging.LoggerMessage.Define%2A) to create an delegate for logging a message. overloads permit passing up to six type parameters to a named format string (template). - -The string provided to the method is a template and not an interpolated string. Placeholders are filled in the order that the types are specified. Placeholder names in the template should be descriptive and consistent across templates. They serve as property names within structured log data. We recommend [Pascal casing](../../standard/design-guidelines/capitalization-conventions.md) for placeholder names. For example, `{Item}`, `{DateTime}`. - -Each log message is an held in a static field created by [LoggerMessage.Define](xref:Microsoft.Extensions.Logging.LoggerMessage.Define%2A). For example, the sample app creates a field to describe a log message for the processing of work items: - -:::code language="csharp" source="snippets/logging/worker-service-options/Extensions/LoggerExtensions.cs" id="FailedProcessingField"::: - -For the , specify: - -- The log level. -- A unique event identifier () with the name of the static extension method. -- The message template (named format string). - -As work items are dequeued for processing, the worker service app sets the: - -- Log level to . -- Event ID to `13` with the name of the `FailedToProcessWorkItem` method. -- Message template (named format string) to a string. - -:::code language="csharp" source="snippets/logging/worker-service-options/Extensions/LoggerExtensions.cs" id="FailedProcessingAssignment"::: - -The method is used to configure and define an delegate, which represents a log message. - -Structured logging stores may use the event name when it's supplied with the event ID to enrich logging. For example, [Serilog](https://github.com/serilog/serilog-extensions-logging) uses the event name. - -The is invoked through a strongly typed extension method. The `PriorityItemProcessed` method logs a message every time a work item is processed. `FailedToProcessWorkItem` is called if and when an exception occurs: - -:::code language="csharp" source="snippets/logging/worker-service-options/Worker.cs" range="9-33" highlight="17-20"::: - -Inspect the app's console output: - -```console -crit: WorkerServiceOptions.Example.Worker[13] - Epic failure processing item! - System.Exception: Failed to verify communications. - at WorkerServiceOptions.Example.Worker.ExecuteAsync(CancellationToken stoppingToken) in - ..\Worker.cs:line 27 -``` - -To pass parameters to a log message, define up to six types when creating the static field. The sample app logs the work item details when processing items by defining a `WorkItem` type for the field: - -:::code language="csharp" source="snippets/logging/worker-service-options/Extensions/LoggerExtensions.cs" id="ProcessingItemField"::: - -The delegate's log message template receives its placeholder values from the types provided. The sample app defines a delegate for adding a work item where the item parameter is a `WorkItem`: - -:::code language="csharp" source="snippets/logging/worker-service-options/Extensions/LoggerExtensions.cs" id="ProcessingItemAssignment"::: - -The static extension method for logging that a work item is being processed, `PriorityItemProcessed`, receives the work item argument value and passes it to the delegate: - -:::code language="csharp" source="snippets/logging/worker-service-options/Extensions/LoggerExtensions.cs" id="ProcessingItemMethod"::: - -In the worker service's `ExecuteAsync` method, `PriorityItemProcessed` is called to log the message: - -:::code language="csharp" source="snippets/logging/worker-service-options/Worker.cs" range="9-33" highlight="14"::: - -Inspect the app's console output: - -```console -info: WorkerServiceOptions.Example.Worker[1] - Processing priority item: Priority-Extreme (50db062a-9732-4418-936d-110549ad79e4): 'Verify communications' -``` - -## Define logger message scope - -The [DefineScope(string)](xref:Microsoft.Extensions.Logging.LoggerMessage.DefineScope%2A) method creates a delegate for defining a [log scope](logging.md#log-scopes). overloads permit passing up to six type parameters to a named format string (template). - -As is the case with the method, the string provided to the method is a template and not an interpolated string. Placeholders are filled in the order that the types are specified. Placeholder names in the template should be descriptive and consistent across templates. They serve as property names within structured log data. We recommend [Pascal casing](../../standard/design-guidelines/capitalization-conventions.md) for placeholder names. For example, `{Item}`, `{DateTime}`. - -Define a [log scope](logging.md#log-scopes) to apply to a series of log messages using the method. Enable `IncludeScopes` in the console logger section of *appsettings.json*: - -:::code language="json" source="snippets/logging/worker-service-options/appsettings.json" highlight="3-5"::: - -To create a log scope, add a field to hold a delegate for the scope. The sample app creates a field named `s_processingWorkScope` (*Internal/LoggerExtensions.cs*): - -:::code language="csharp" source="snippets/logging/worker-service-options/Extensions/LoggerExtensions.cs" id="ProcessingWorkField"::: - -Use to create the delegate. Up to six types can be specified for use as template arguments when the delegate is invoked. The sample app uses a message template that includes the date time in which processing started: - -:::code language="csharp" source="snippets/logging/worker-service-options/Extensions/LoggerExtensions.cs" id="ProcessingWorkAssignment"::: - -Provide a static extension method for the log message. Include any type parameters for named properties that appear in the message template. The sample app takes in a `DateTime` for a custom time stamp to log and returns `_processingWorkScope`: - -:::code language="csharp" source="snippets/logging/worker-service-options/Extensions/LoggerExtensions.cs" id="ProcessingWorkMethod"::: - -The scope wraps the logging extension calls in a [using](../../csharp/language-reference/statements/using.md) block: - -:::code language="csharp" source="snippets/logging/worker-service-options/Worker.cs" range="9-33" highlight="4"::: - -Inspect the log messages in the app's console output. The following result shows priority ordering of log messages with the log scope message included: - -```console -info: WorkerServiceOptions.Example.Worker[1] - => Processing scope, started at: 04/11/2024 11:27:52 - Processing priority item: Priority-Extreme (7d153ef9-8894-4282-836a-8e5e38319fb3): 'Verify communications' -info: Microsoft.Hosting.Lifetime[0] - Application started. Press Ctrl+C to shut down. -info: Microsoft.Hosting.Lifetime[0] - Hosting environment: Development -info: Microsoft.Hosting.Lifetime[0] - Content root path: D:\source\repos\dotnet-docs\docs\core\extensions\snippets\logging\worker-service-options -info: WorkerServiceOptions.Example.Worker[1] - => Processing scope, started at: 04/11/2024 11:27:52 - Processing priority item: Priority-High (dbad6558-60cd-4eb1-8531-231e90081f62): 'Validate collection' -info: WorkerServiceOptions.Example.Worker[1] - => Processing scope, started at: 04/11/2024 11:27:52 - Processing priority item: Priority-Medium (1eabe213-dc64-4e3a-9920-f67fe1dfb0f6): 'Propagate selections' -info: WorkerServiceOptions.Example.Worker[1] - => Processing scope, started at: 04/11/2024 11:27:52 - Processing priority item: Priority-Medium (1142688d-d4dc-4f78-95c5-04ec01cbfac7): 'Enter pooling [contention]' -info: WorkerServiceOptions.Example.Worker[1] - => Processing scope, started at: 04/11/2024 11:27:52 - Processing priority item: Priority-Low (e85e0c4d-0840-476e-b8b0-22505c08e913): 'Health check network' -info: WorkerServiceOptions.Example.Worker[1] - => Processing scope, started at: 04/11/2024 11:27:52 - Processing priority item: Priority-Deferred (07571363-d559-4e72-bc33-cd8398348786): 'Ping weather service' -info: WorkerServiceOptions.Example.Worker[1] - => Processing scope, started at: 04/11/2024 11:27:52 - Processing priority item: Priority-Deferred (2bf74f2f-0198-4831-8138-03368e60bd6b): 'Set process state' -info: Microsoft.Hosting.Lifetime[0] - Application is shutting down... -``` - -## Log level guarded optimizations - -Another performance optimization can be made by checking the , with before an invocation to the corresponding `Log*` method. When logging isn't configured for the given `LogLevel`, the following statements are true: - -- isn't called. -- An allocation of `object[]` representing the parameters is avoided. -- Value type boxing is avoided. - -For more information: - -- [Micro benchmarks in the .NET runtime](https://github.com/dotnet/runtime/issues/51927#issuecomment-842993859) -- [Background and motivation for log level checks](https://github.com/dotnet/runtime/issues/45290#issue-752502603) - -## See also - -- [Logging in .NET](logging.md) diff --git a/docs/core/extensions/httpclient-factory.md b/docs/core/extensions/httpclient-factory.md index c520b733f38e1..a1ecbf4ce1e23 100644 --- a/docs/core/extensions/httpclient-factory.md +++ b/docs/core/extensions/httpclient-factory.md @@ -377,7 +377,7 @@ builder.ConfigurePrimaryHttpMessageHandler((handler, provider) => [hcf-issues]: httpclient-factory-troubleshooting.md [di]: dependency-injection/overview.md -[logging]: logging.md +[logging]: logging/overview.md [config]: configuration.md [httpclient]: ../../fundamentals/networking/http/httpclient.md [http-retry]: ../../architecture/microservices/implement-resilient-applications/implement-http-call-retries-exponential-backoff-polly.md diff --git a/docs/core/extensions/localization.md b/docs/core/extensions/localization.md index 8c484a14237dc..c3d179b9f798d 100644 --- a/docs/core/extensions/localization.md +++ b/docs/core/extensions/localization.md @@ -243,5 +243,5 @@ The sample application does not provide resource files for `"fr-CA"`, but when c - [Package and deploy resources in .NET apps](package-and-deploy-resources.md) - [`Microsoft.Extensions.Localization`](https://www.nuget.org/packages/microsoft.extensions.localization) - [Dependency injection in .NET](dependency-injection/overview.md) -- [Logging in .NET](logging.md) +- [Logging in .NET](logging/overview.md) - [ASP.NET Core localization](/aspnet/core/fundamentals/localization) diff --git a/docs/core/extensions/console-log-formatter.md b/docs/core/extensions/logging/console-log-formatter.md similarity index 65% rename from docs/core/extensions/console-log-formatter.md rename to docs/core/extensions/logging/console-log-formatter.md index 1cce4839c2af1..adc414086bf26 100644 --- a/docs/core/extensions/console-log-formatter.md +++ b/docs/core/extensions/logging/console-log-formatter.md @@ -6,28 +6,25 @@ ms.date: 10/20/2025 # Console log formatting -In .NET 5, support for custom formatting was added to console logs in the `Microsoft.Extensions.Logging.Console` namespace. There are three predefined formatting options available: [`Simple`](#simple), [`Systemd`](#systemd), and [`Json`](#json). +The `Microsoft.Extensions.Logging.Console` namespace provides support for custom formatting in console logs. There are three predefined formatting options available: [`Simple`](#simple), [`Systemd`](#systemd), and [`Json`](#json). > [!IMPORTANT] -> Previously, the enum allowed for selecting the desired log format, either human readable which was the `Default`, or single line which is also known as `Systemd`. However, these were **not** customizable, and are now deprecated. +> Prior to .NET 5, the enum allowed for selecting the desired log format, either human readable which was the `Default`, or single line which is also known as `Systemd`. However, these were **not** customizable, and are now deprecated. In this article, you will learn about console log formatters. The sample source code demonstrates how to: -- Register a new formatter -- Select a registered formatter to use - - Either through code, or [configuration](configuration.md) -- Implement a custom formatter - - Update configuration via - - Enable custom color formatting +- Register a new formatter. +- Select a registered formatter to use, either through code or [configuration](../configuration.md). +- Implement a custom formatter. You update configuration via and enable custom color formatting. [!INCLUDE [logging-samples-browser](includes/logging-samples-browser.md)] ## Register formatter -The [`Console` logging provider](logging-providers.md#console) has several predefined formatters, and exposes the ability to author your own custom formatter. To register any of the available formatters, use the corresponding `Add{Type}Console` extension method: +The [`Console` logging provider](providers.md#console) has several predefined formatters, and exposes the ability to author your own custom formatter. To register any of the available formatters, use the corresponding `Add{Type}Console` extension method: | Available types | Method to register type | -|--|--| +|-----------------|-------------------------| | | | | | | | | | @@ -36,7 +33,7 @@ The [`Console` logging provider](logging-providers.md#console) has several prede To use the `Simple` console formatter, register it with `AddSimpleConsole`: -:::code language="csharp" source="snippets/logging/console-formatter-simple/Program.cs" highlight="5-10"::: +:::code language="csharp" source="../snippets/logging/console-formatter-simple/Program.cs" highlight="5-10"::: In the preceding sample source code, the formatter was registered. It provides logs with the ability to not only wrap information such as time and log level in each log message, but also allows for ANSI color embedding and indentation of messages. @@ -48,13 +45,13 @@ When this sample app is run, the log messages are formatted as shown below: The console logger: -- Uses the "Syslog" log level format and severities -- Does **not** format messages with colors -- Always logs messages in a single line +- Uses the "Syslog" log level format and severities. +- Does **not** format messages with colors. +- Always logs messages in a single line. -This is commonly useful for containers, which often make use of `Systemd` console logging. With .NET 5, the `Simple` console logger also enables a compact version that logs in a single line, and also allows for disabling colors as shown in an earlier sample. +This is commonly useful for containers, which often make use of `Systemd` console logging. The `Simple` console logger also enables a compact version that logs in a single line, and also allows for disabling colors as shown in an earlier sample. -:::code language="csharp" source="snippets/logging/console-formatter-systemd/Program.cs" highlight="5-9"::: +:::code language="csharp" source="../snippets/logging/console-formatter-systemd/Program.cs" highlight="5-9"::: The example produces output similar to the following log messages: @@ -62,7 +59,7 @@ The example produces output similar to the following log messages: ### Json -To write logs in a JSON format, the `Json` console formatter is used. The sample source code shows how an ASP.NET Core app might register it. Using the `webapp` template, create a new ASP.NET Core app with the [dotnet new](../tools/dotnet-new.md) command: +To write logs in a JSON format, the `Json` console formatter is used. The sample source code shows how an ASP.NET Core app might register it. Using the `webapp` template, create a new ASP.NET Core app with the [dotnet new](../../tools/dotnet-new.md) command: ```dotnetcli dotnet new webapp -o Console.ExampleFormatters.Json @@ -87,27 +84,27 @@ info: Microsoft.Hosting.Lifetime[0] By default, the `Simple` console log formatter is selected with default configuration. You change this by calling `AddJsonConsole` in the *Program.cs*: -:::code language="csharp" source="snippets/logging/console-formatter-json/Program.cs" highlight="5-13"::: +:::code language="csharp" source="../snippets/logging/console-formatter-json/Program.cs" highlight="5-13"::: Alternatively, you can also configure this using logging configuration, such as that found in the _appsettings.json_ file: -:::code language="json" source="snippets/logging/console-formatter-json/appsettings.json" highlight="14-23"::: +:::code language="json" source="../snippets/logging/console-formatter-json/appsettings.json" highlight="14-23"::: Run the app again, with the above change, the log message is now formatted as JSON: -:::code language="json" source="snippets/logging/console-formatter-json/example-output.txt"::: +:::code language="json" source="../snippets/logging/console-formatter-json/example-output.txt"::: > [!TIP] -> The `Json` console formatter, by default, logs each message in a single line. In order to make it more readable while configuring the formatter, set to `true`. +> The `Json` console formatter, by default, logs each message in a single line. To make it more readable while configuring the formatter, set to `true`. > [!CAUTION] -> When using the Json console formatter, do not pass in log messages that have already been serialized as JSON. The logging infrastructure itself already manages the serialization of log messages, so if you're to pass in a log message that is already serialized—it will be double serialized, thus causing malformed output. +> When using the JSON console formatter, don't pass in log messages that have already been serialized as JSON. The logging infrastructure itself manages the serialization of log messages. So if you pass in a log message that's already serialized, it will be double serialized, thus causing malformed output. ## Set formatter with configuration -The previous samples have shown how to register a formatter programmatically. Alternatively, this can be done with [configuration](configuration.md). Consider the previous web application sample source code, if you update the *appsettings.json* file rather than calling `ConfigureLogging` in the *Program.cs* file, you could get the same outcome. The updated `appsettings.json` file would configure the formatter as follows: +The previous samples showed how to register a formatter programmatically. Alternatively, this can be done with [configuration](../configuration.md). Consider the previous web application sample source code, if you update the *appsettings.json* file rather than calling `ConfigureLogging` in the *Program.cs* file, you could get the same outcome. The updated `appsettings.json` file would configure the formatter as follows: -:::code language="json" source="snippets/logging/console-formatter-json/appsettings.json" highlight="14-23"::: +:::code language="json" source="../snippets/logging/console-formatter-json/appsettings.json" highlight="14-23"::: The two key values that need to be set are `"FormatterName"` and `"FormatterOptions"`. If a formatter with the value set for `"FormatterName"` is already registered, that formatter is selected, and its properties can be configured as long as they are provided as a key inside the `"FormatterOptions"` node. The predefined formatter names are reserved under : @@ -119,32 +116,31 @@ The two key values that need to be set are `"FormatterName"` and `"FormatterOpti To implement a custom formatter, you need to: -- Create a subclass of , this represents your custom formatter -- Register your custom formatter with +- Create a subclass of that represents your custom formatter. +- Register your custom formatter with: - - Create an extension method to handle this for you: -:::code language="csharp" source="snippets/logging/console-formatter-custom/ConsoleLoggerExtensions.cs" highlight="10-11"::: +:::code language="csharp" source="../snippets/logging/console-formatter-custom/ConsoleLoggerExtensions.cs" highlight="10-11"::: The `CustomOptions` are defined as follows: -:::code language="csharp" source="snippets/logging/console-formatter-custom/CustomOptions.cs"::: +:::code language="csharp" source="../snippets/logging/console-formatter-custom/CustomOptions.cs"::: In the preceding code, the options are a subclass of . The `AddConsoleFormatter` API: -- Registers a subclass of `ConsoleFormatter` -- Handles configuration: - - Uses a change token to synchronize updates, based on the [options pattern](options.md), and the [IOptionsMonitor](xref:Microsoft.Extensions.Options.IOptionsMonitor%601) interface +- Registers a subclass of `ConsoleFormatter`. +- Handles configuration. It uses a change token to synchronize updates, based on the [options pattern](../options.md), and the [IOptionsMonitor](xref:Microsoft.Extensions.Options.IOptionsMonitor%601) interface. -:::code language="csharp" source="snippets/logging/console-formatter-custom/Program.cs" highlight="6-7"::: +:::code language="csharp" source="../snippets/logging/console-formatter-custom/Program.cs" highlight="6-7"::: Define a `CustomFormatter` subclass of `ConsoleFormatter`: -:::code language="csharp" source="snippets/logging/console-formatter-custom/CustomFormatter.cs" highlight="22-38"::: +:::code language="csharp" source="../snippets/logging/console-formatter-custom/CustomFormatter.cs" highlight="22-38"::: The preceding `CustomFormatter.Write` API dictates what text gets wrapped around each log message. A standard `ConsoleFormatter` should be able to wrap around scopes, time stamps, and severity level of logs at a minimum. Additionally, you can encode ANSI colors in the log messages, and provide desired indentations as well. The implementation of the `CustomFormatter.Write` lacks these capabilities. @@ -156,13 +152,13 @@ For inspiration on further customizing formatting, see the existing implementati ### Custom configuration options -To further customize the logging extensibility, your derived class can be configured from any [configuration provider](configuration-providers.md). For example, you could use the [JSON configuration provider](configuration-providers.md#json-configuration-provider) to define your custom options. First define your subclass. +To further customize the logging extensibility, your derived class can be configured from any [configuration provider](../configuration-providers.md). For example, you could use the [JSON configuration provider](../configuration-providers.md#json-configuration-provider) to define your custom options. First define your subclass. -:::code language="csharp" source="snippets/logging/console-formatter-custom-with-config/CustomWrappingConsoleFormatterOptions.cs"::: +:::code language="csharp" source="../snippets/logging/console-formatter-custom-with-config/CustomWrappingConsoleFormatterOptions.cs"::: The preceding console formatter options class defines two custom properties, representing a prefix and suffix. Next, define the *appsettings.json* file that will configure your console formatter options. -:::code language="json" source="snippets/logging/console-formatter-custom-with-config/appsettings.json" highlight="8,14-17"::: +:::code language="json" source="../snippets/logging/console-formatter-custom-with-config/appsettings.json" highlight="8,14-17"::: In the preceding JSON config file: @@ -175,7 +171,7 @@ In the preceding JSON config file: Consider the following `CustomDatePrefixingFormatter`: -:::code language="csharp" source="snippets/logging/console-formatter-custom-with-config/CustomTimePrefixingFormatter.cs"::: +:::code language="csharp" source="../snippets/logging/console-formatter-custom-with-config/CustomTimePrefixingFormatter.cs"::: In the preceding formatter implementation: @@ -185,7 +181,7 @@ In the preceding formatter implementation: To use custom configuration options, with custom formatter implementations, add when calling . -:::code language="csharp" source="snippets/logging/console-formatter-custom-with-config/Program.cs" highlight="9-11"::: +:::code language="csharp" source="../snippets/logging/console-formatter-custom-with-config/Program.cs" highlight="9-11"::: The following console output is similar to what you might expect to see from using this `CustomTimePrefixingFormatter`. @@ -200,15 +196,15 @@ In order to properly enable color capabilities in your custom logging formatter, Create a `CustomColorOptions` that derives from `SimpleConsoleFormatterOptions`: -:::code language="csharp" source="snippets/logging/console-formatter-custom/CustomColorOptions.cs" highlight="5"::: +:::code language="csharp" source="../snippets/logging/console-formatter-custom/CustomColorOptions.cs" highlight="5"::: Next, write some extension methods in a `TextWriterExtensions` class that allow for conveniently embedding ANSI coded colors within formatted log messages: -:::code language="csharp" source="snippets/logging/console-formatter-custom/TextWriterExtensions.cs"::: +:::code language="csharp" source="../snippets/logging/console-formatter-custom/TextWriterExtensions.cs"::: A custom color formatter that handles applying custom colors could be defined as follows: -:::code language="csharp" source="snippets/logging/console-formatter-custom/CustomColorFormatter.cs" highlight="13-16,50-63"::: +:::code language="csharp" source="../snippets/logging/console-formatter-custom/CustomColorFormatter.cs" highlight="13-16,50-63"::: When you run the application, the logs will show the `CustomPrefix` message in the color green when `FormatterOptions.ColorBehavior` is `Enabled`. @@ -227,6 +223,6 @@ When you run the application, the logs will show the `CustomPrefix` message in t ## See also -- [Logging in .NET](logging.md) -- [Implement a custom logging provider in .NET](custom-logging-provider.md) +- [Logging in .NET](overview.md) +- [Implement a custom logging provider in .NET](custom-provider.md) - [High-performance logging in .NET](high-performance-logging.md) diff --git a/docs/core/extensions/custom-logging-provider.md b/docs/core/extensions/logging/custom-provider.md similarity index 79% rename from docs/core/extensions/custom-logging-provider.md rename to docs/core/extensions/logging/custom-provider.md index 88c1a9e25edd1..ab770f44b7be3 100644 --- a/docs/core/extensions/custom-logging-provider.md +++ b/docs/core/extensions/logging/custom-provider.md @@ -7,7 +7,7 @@ ms.topic: how-to # Implement a custom logging provider in .NET -There are many [logging providers](logging-providers.md) available for common logging needs. You may need to implement a custom when one of the available providers doesn't suit your application needs. In this article, you'll learn how to implement a custom logging provider that can be used to colorize logs in the console. +There are many [logging providers](providers.md) available for common logging needs. You might need to implement a custom when one of the available providers doesn't suit your application needs. In this article, you learn how to implement a custom logging provider that can be used to colorize logs in the console. > [!TIP] > The custom logging provider example source code is available in the **Docs GitHub repo**. For more information, see [GitHub: .NET Docs - Console Custom Logging](https://github.com/dotnet/docs/tree/main/docs/core/extensions/snippets/configuration/console-custom-logging). @@ -16,7 +16,7 @@ There are many [logging providers](logging-providers.md) available for common lo The sample creates different color console entries per log level and event ID using the following configuration type: -:::code language="csharp" source="snippets/configuration/console-custom-logging/ColorConsoleLoggerConfiguration.cs"::: +:::code language="csharp" source="../snippets/configuration/console-custom-logging/ColorConsoleLoggerConfiguration.cs"::: The preceding code sets the default level to `Information`, the color to `Green`, and the `EventId` is implicitly `0`. @@ -24,7 +24,7 @@ The preceding code sets the default level to `Information`, the color to `Green` The `ILogger` implementation category name is typically the logging source. For example, the type where the logger is created: -:::code language="csharp" source="snippets/configuration/console-custom-logging/ColorConsoleLogger.cs"::: +:::code language="csharp" source="../snippets/configuration/console-custom-logging/ColorConsoleLogger.cs"::: The preceding code: @@ -33,7 +33,7 @@ The preceding code: It's a good practice to call within implementations since `Log` can be called by any consumer, and there are no guarantees that it was previously checked. The `IsEnabled` method should be very fast in most implementations. -:::code language="csharp" source="snippets/configuration/console-custom-logging/ColorConsoleLogger.cs" range="15-16"::: +:::code language="csharp" source="../snippets/configuration/console-custom-logging/ColorConsoleLogger.cs" range="15-16"::: The logger is instantiated with the `name` and a `Func`, which returns the current config—this handles updates to the config values as monitored through the callback. @@ -44,22 +44,22 @@ The logger is instantiated with the `name` and a `Func creates a single instance of the `ColorConsoleLogger` per category name and stores it in the [`ConcurrentDictionary`](/dotnet/api/system.collections.concurrent.concurrentdictionary-2). Additionally, the interface is required to update changes to the underlying `ColorConsoleLoggerConfiguration` object. To control the configuration of the `ColorConsoleLogger`, you define an alias on its provider: -:::code language="csharp" source="snippets/configuration/console-custom-logging/ColorConsoleLoggerProvider.cs" range="6-8" highlight="6-7"::: +:::code language="csharp" source="../snippets/configuration/console-custom-logging/ColorConsoleLoggerProvider.cs" range="6-8" highlight="6-7"::: The `ColorConsoleLoggerProvider` class defines two class-scoped attributes: - : The `ColorConsoleLogger` type is _not supported_ in the `"browser"`. - : Configuration sections can define options using the `"ColorConsole"` key. -The configuration can be specified with any valid [configuration provider](configuration-providers.md). Consider the following _appsettings.json_ file: +The configuration can be specified with any valid [configuration provider](../configuration-providers.md). Consider the following _appsettings.json_ file: -:::code language="json" source="snippets/configuration/console-custom-logging/appsettings.json"::: +:::code language="json" source="../snippets/configuration/console-custom-logging/appsettings.json"::: This configures the log levels to the following values: @@ -75,7 +75,7 @@ By convention, registering services for dependency injection happens as part of To add the custom logging provider and corresponding logger, add an with from the : -:::code language="csharp" source="snippets/configuration/console-custom-logging/Program.cs" highlight="6-14"::: +:::code language="csharp" source="../snippets/configuration/console-custom-logging/Program.cs" highlight="6-14"::: The `ILoggingBuilder` creates one or more `ILogger` instances. The `ILogger` instances are used by the framework to log the information. @@ -86,7 +86,7 @@ The configuration from the _appsettings.json_ file overrides the following value By convention, extension methods on `ILoggingBuilder` are used to register the custom provider: -:::code language="csharp" source="snippets/configuration/console-custom-logging/Extensions/ColorConsoleLoggerExtensions.cs"::: +:::code language="csharp" source="../snippets/configuration/console-custom-logging/Extensions/ColorConsoleLoggerExtensions.cs"::: Running this simple application will render color output to the console window similar to the following image: @@ -94,7 +94,7 @@ Running this simple application will render color output to the console window s ## See also -- [Logging in .NET](logging.md) -- [Logging providers in .NET](logging-providers.md) -- [Dependency injection in .NET](dependency-injection/overview.md) +- [Logging in .NET](overview.md) +- [Logging providers in .NET](providers.md) +- [Dependency injection in .NET](../dependency-injection/overview.md) - [High-performance logging in .NET](high-performance-logging.md) diff --git a/docs/core/extensions/logging/high-performance-logging.md b/docs/core/extensions/logging/high-performance-logging.md new file mode 100644 index 0000000000000..7eda6a304d6cc --- /dev/null +++ b/docs/core/extensions/logging/high-performance-logging.md @@ -0,0 +1,225 @@ +--- +title: High-performance logging +description: Learn how to use source-generated logging with LoggerMessageAttribute to create high-performance logs with minimal overhead in .NET apps. +ms.date: 02/02/2026 +ai-usage: ai-assisted +--- + +# High-performance logging in .NET + +For high-performance logging scenarios in .NET 6 and later versions, use the with [compile-time source generation](source-generation.md). This approach provides the best performance by eliminating boxing, temporary allocations, and message template parsing at runtime. + +Source-generated logging provides the following performance advantages over [logger extension methods](xref:Microsoft.Extensions.Logging.LoggerExtensions), such as and : + +- **Eliminates boxing:** Logger extension methods require "boxing" (converting) value types, such as `int`, into `object`. Source-generated logging avoids boxing by using strongly typed parameters. +- **Parses templates at compile time:** Logger extension methods must parse the message template (named format string) every time a log message is written. Source-generated logging parses templates once at compile time. +- **Reduces allocations:** The source generator creates optimized code that minimizes object allocations and temporary memory usage. + +The sample app demonstrates high-performance logging features with a priority queue processing worker service. The app processes work items in priority order. As these operations occur, log messages are generated using source-generated logging. + +[!INCLUDE [logging-samples-browser](includes/logging-samples-browser.md)] + +## Define logger messages with source generation + +To create high-performance log messages in .NET 6 and later, define `partial` methods decorated with . The source generator creates the implementation at compile time. + +### Basic logging method + +For a simple log message, define a partial method with the attribute specifying the event ID, log level, and message template: + +```csharp +public static partial class Log +{ + [LoggerMessage( + EventId = 13, + Level = LogLevel.Critical, + Message = "Epic failure processing item!")] + public static partial void FailedToProcessWorkItem( + ILogger logger, Exception ex); +} +``` + +The message template uses placeholders that are filled by method parameters. Placeholder names should be descriptive and consistent across templates. They serve as property names within structured log data. We recommend [Pascal casing](../../../standard/design-guidelines/capitalization-conventions.md) for placeholder names. For example, `{Item}`, `{DateTime}`. + +Call the logging method from your code. For example, when an exception occurs during work item processing: + +```csharp +try +{ + // Process work item. +} +catch (Exception ex) +{ + Log.FailedToProcessWorkItem(logger, ex); +} +``` + +This code produces console output like: + +```console +crit: WorkerServiceOptions.Example.Worker[13] + Epic failure processing item! + System.Exception: Failed to verify communications. +``` + +### Logging with parameters + +To pass parameters to a log message, add them as method parameters. The parameter names match the placeholders in the message template: + +```csharp +public static partial class Log +{ + [LoggerMessage( + EventId = 1, + Level = LogLevel.Information, + Message = "Processing priority item: {Item}")] + public static partial void PriorityItemProcessed( + ILogger logger, WorkItem item); +} +``` + +Call the method with the logger and parameter values: + +```csharp +var workItem = queue.Dequeue(); +Log.PriorityItemProcessed(logger, workItem); +``` + +This code produces console output like: + +```console +info: WorkerServiceOptions.Example.Worker[1] + Processing priority item: Priority-Extreme (50db062a-9732-4418-936d-110549ad79e4): 'Verify communications' +``` + +Structured logging stores can use the event name when it's supplied with the event ID to enrich logging. For example, [Serilog](https://github.com/serilog/serilog-extensions-logging) uses the event name. + +## Define logger message scope with source generation + +You can define [log scopes](overview.md#log-scopes) to wrap a series of log messages with additional context. With source-generated logging, you combine the `LoggerMessageAttribute` methods with the standard `ILogger.BeginScope` method. + +Enable `IncludeScopes` in the console logger section of *appsettings.json*: + +:::code language="json" source="../snippets/logging/worker-service-options/appsettings.json" highlight="3-5"::: + +Create source-generated logging methods and wrap them in a scope using `BeginScope`: + +```csharp +public static partial class Log +{ + [LoggerMessage( + EventId = 1, + Level = LogLevel.Information, + Message = "Processing priority item: {Item}")] + public static partial void PriorityItemProcessed( + ILogger logger, WorkItem item); +} +``` + +Use the logging method within a scope in your application code: + +```csharp +using (_logger.BeginScope("Processing scope, started at: {DateTime}", DateTime.Now)) +{ + Log.PriorityItemProcessed(_logger, workItem); +} +``` + +Inspect the log messages in the app's console output. The following result shows priority ordering of log messages with the log scope message included: + +```console +info: WorkerServiceOptions.Example.Worker[1] + => Processing scope, started at: 04/11/2024 11:27:52 + Processing priority item: Priority-Extreme (7d153ef9-8894-4282-836a-8e5e38319fb3): 'Verify communications' +``` + +## Legacy approach: LoggerMessage.Define (for .NET Framework and .NET Core 3.1) + +Before source-generated logging was introduced in .NET 6, the recommended high-performance logging approach was to use the method to create cacheable delegates. While this approach is still supported for backward compatibility, new code should use source-generated logging with `LoggerMessageAttribute` instead. + +The class exposes functionality to create cacheable delegates that require fewer object allocations and reduced computational overhead compared to [logger extension methods](xref:Microsoft.Extensions.Logging.LoggerExtensions), such as and . provides the following performance advantages over logger extension methods: + +- Logger extension methods require "boxing" (converting) value types, such as `int`, into `object`. The pattern avoids boxing by using static fields and extension methods with strongly typed parameters. +- Logger extension methods must parse the message template (named format string) every time a log message is written. only requires parsing a template once when the message is defined. + +> [!NOTE] +> If you're maintaining code that uses `LoggerMessage.Define`, consider migrating to [source-generated logging](source-generation.md). For .NET Framework or .NET Core 3.1 applications, continue using `LoggerMessage.Define`. + +### Define a logger message + +Use [Define(LogLevel, EventId, String)](xref:Microsoft.Extensions.Logging.LoggerMessage.Define%2A) to create an delegate for logging a message. overloads permit passing up to six type parameters to a named format string (template). + +The string provided to the method is a template and not an interpolated string. Placeholders are filled in the order that the types are specified. Placeholder names in the template should be descriptive and consistent across templates. They serve as property names within structured log data. We recommend [Pascal casing](../../../standard/design-guidelines/capitalization-conventions.md) for placeholder names. For example, `{Item}`, `{DateTime}`. + +Each log message is an held in a static field created by [LoggerMessage.Define](xref:Microsoft.Extensions.Logging.LoggerMessage.Define%2A). For example, the sample app creates a field to describe a log message for the processing of work items: + +:::code language="csharp" source="../snippets/logging/worker-service-options/Extensions/LoggerExtensions.cs" id="FailedProcessingField"::: + +For the , specify: + +- The log level. +- A unique event identifier () with the name of the static extension method. +- The message template (named format string). + +As work items are dequeued for processing, the worker service app sets the: + +- Log level to . +- Event ID to `13` with the name of the `FailedToProcessWorkItem` method. +- Message template (named format string) to a string. + +:::code language="csharp" source="../snippets/logging/worker-service-options/Extensions/LoggerExtensions.cs" id="FailedProcessingAssignment"::: + +The method is used to configure and define an delegate, which represents a log message. + +Structured logging stores can use the event name when it's supplied with the event ID to enrich logging. For example, [Serilog](https://github.com/serilog/serilog-extensions-logging) uses the event name. + +The is invoked through a strongly typed extension method. The `PriorityItemProcessed` method logs a message every time a work item is processed. `FailedToProcessWorkItem` is called if and when an exception occurs: + +:::code language="csharp" source="../snippets/logging/worker-service-options/Worker.cs" range="9-33" highlight="17-20"::: + +Inspect the app's console output: + +```console +crit: WorkerServiceOptions.Example.Worker[13] + Epic failure processing item! + System.Exception: Failed to verify communications. + at WorkerServiceOptions.Example.Worker.ExecuteAsync(CancellationToken stoppingToken) in + ..\Worker.cs:line 27 +``` + +To pass parameters to a log message, define up to six types when creating the static field. The sample app logs the work item details when processing items by defining a `WorkItem` type for the field: + +:::code language="csharp" source="../snippets/logging/worker-service-options/Extensions/LoggerExtensions.cs" id="ProcessingItemField"::: + +The delegate's log message template receives its placeholder values from the types provided. The sample app defines a delegate for adding a work item where the item parameter is a `WorkItem`: + +:::code language="csharp" source="../snippets/logging/worker-service-options/Extensions/LoggerExtensions.cs" id="ProcessingItemAssignment"::: + +The static extension method for logging that a work item is being processed, `PriorityItemProcessed`, receives the work item argument value and passes it to the delegate: + +:::code language="csharp" source="../snippets/logging/worker-service-options/Extensions/LoggerExtensions.cs" id="ProcessingItemMethod"::: + +In the worker service's `ExecuteAsync` method, `PriorityItemProcessed` is called to log the message: + +:::code language="csharp" source="../snippets/logging/worker-service-options/Worker.cs" range="9-33" highlight="14"::: + +Inspect the app's console output: + +```console +info: WorkerServiceOptions.Example.Worker[1] + Processing priority item: Priority-Extreme (50db062a-9732-4418-936d-110549ad79e4): 'Verify communications' +``` + +## Log-level guarded optimizations + +You can optimize performance by checking the with before invoking the corresponding `Log*` method. When logging isn't configured for the given `LogLevel`, isn't called. In addition, value-type boxing and an allocation of `object[]` (to represent the parameters) are avoided. + +For more information, see: + +- [Micro benchmarks in the .NET runtime](https://github.com/dotnet/runtime/issues/51927#issuecomment-842993859) +- [Background and motivation for log-level checks](https://github.com/dotnet/runtime/issues/45290#issue-752502603) + +## See also + +- [Logging in .NET](overview.md) +- [Compile-time logging source generation](source-generation.md) diff --git a/docs/core/extensions/includes/logging-samples-browser.md b/docs/core/extensions/logging/includes/logging-samples-browser.md similarity index 100% rename from docs/core/extensions/includes/logging-samples-browser.md rename to docs/core/extensions/logging/includes/logging-samples-browser.md diff --git a/docs/core/extensions/logging-library-authors.md b/docs/core/extensions/logging/library-guidance.md similarity index 71% rename from docs/core/extensions/logging-library-authors.md rename to docs/core/extensions/logging/library-guidance.md index 1ccfe2e7b2140..81df005f51dab 100644 --- a/docs/core/extensions/logging-library-authors.md +++ b/docs/core/extensions/logging/library-guidance.md @@ -6,25 +6,24 @@ ms.date: 03/15/2024 # Logging guidance for .NET library authors -As a library author, exposing logging is a great way to provide consumers with insight into the inner workings of your library. This guidance helps you expose logging in a way that is consistent with other .NET libraries and frameworks. It also helps you avoid common performance bottlenecks that may not be otherwise obvious. +As a library author, exposing logging is a great way to provide consumers with insight into the inner workings of your library. This guidance helps you expose logging in a way that's consistent with other .NET libraries and frameworks. It also helps you avoid common performance bottlenecks. ## When to use the `ILoggerFactory` interface When writing a library that emits logs, you need an object to record the logs. To get that object, your API can either accept an parameter, or it can accept an after which you call . Which approach should be preferred? - When you need a logging object that can be passed along to multiple classes so that all of them can emit logs, use `ILoggerFactory`. It's recommended that each class creates logs with a separate category, named the same as the class. To do this, you need the factory to create unique `ILogger` objects for each class that emits logs. Common examples include public entry point APIs for a library or public constructors of types that might create helper classes internally. - - When you need a logging object that's only used inside one class and never shared, use `ILogger`, where `TCategoryName` is the type that produces the logs. A common example of this is a constructor for a class created by dependency injection. If you're designing a public API that must remain stable over time, keep in mind that you might desire to refactor your internal implementation in the future. Even if a class doesn't create any internal helper types initially, that might change as the code evolves. Using `ILoggerFactory` accommodates creating new `ILogger` objects for any new classes without changing the public API. -For more information, see [How filtering rules are applied](logging.md#how-filtering-rules-are-applied). +For more information, see [How filtering rules are applied](overview.md#how-filtering-rules-are-applied). ## Prefer source-generated logging -The `ILogger` API supports two approaches to using the API. You can either call methods such as and , or you can use the logging source generator to define strongly typed logging methods. For most situations, the source generator is recommended because it offers superior performance and stronger typing. It also isolates logging-specific concerns such as message templates, IDs, and log levels from the calling code. The non-source-generated approach is primarily useful for scenarios where you are willing to give up those advantages to make the code more concise. +The `ILogger` API supports two approaches to using the API. You can either call methods such as and , or you can use the logging source generator to define strongly typed logging methods. For most situations, the source generator is recommended because it offers superior performance and stronger typing. It also isolates logging-specific concerns such as message templates, IDs, and log levels from the calling code. The non-source-generated approach is primarily useful for scenarios where you're willing to give up those advantages to make the code more concise. -:::code source="snippets/logging/library-authors/LogMessages.cs"::: +:::code source="../snippets/logging/library-authors/LogMessages.cs"::: The preceding code: @@ -37,7 +36,7 @@ The preceding code: ### Use `IsEnabled` to avoid expensive parameter evaluation -There may be situations where evaluating parameters is expensive. Expanding upon the previous example, imagine the `description` parameter is a `string` that is expensive to compute. Perhaps the product being sold gets a friendly product description and relies on a database query, or reading from a file. In these situations, you can instruct the source generator to skip the `IsEnabled` guard and manually add the `IsEnabled` guard at the call site. This allows the user to determine where the guard is called and ensures that parameters that might be expensive to compute are only evaluated when truly needed. Consider the following code: +There might be situations where evaluating parameters is expensive. Expanding upon the previous example, imagine the `description` parameter is a `string` that is expensive to compute. Perhaps the product being sold gets a friendly product description and relies on a database query, or reading from a file. In these situations, you can instruct the source generator to skip the `IsEnabled` guard and manually add the `IsEnabled` guard at the call site. This allows the user to determine where the guard is called and ensures that parameters that might be expensive to compute are only evaluated when truly needed. Consider the following code: ```csharp using Microsoft.Extensions.Logging; @@ -71,15 +70,15 @@ if (_logger.IsEnabled(LogLevel.Information)) } ``` -For more information, see [Compile-time logging source generation](logger-message-generator.md) and [High-performance logging in .NET](high-performance-logging.md). +For more information, see [Compile-time logging source generation](source-generation.md) and [High-performance logging in .NET](high-performance-logging.md). ## Avoid string interpolation in logging -A common mistake is to use [string interpolation](../../csharp/tutorials/string-interpolation.md) to build log messages. String interpolation in logging is problematic for performance, as the string is evaluated even if the corresponding `LogLevel` isn't enabled. Instead of string interpolation, use the log message template, formatting, and argument list. For more information, see [Logging in .NET: Log message template](logging.md#log-message-template). +A common mistake is to use [string interpolation](../../../csharp/tutorials/string-interpolation.md) to build log messages. String interpolation in logging is problematic for performance, as the string is evaluated even if the corresponding `LogLevel` isn't enabled. Instead of string interpolation, use the log message template, formatting, and argument list. For more information, see [Logging in .NET: Log message template](overview.md#log-message-template). ## Use no-op logging defaults -There may be times, when consuming a library that exposes logging APIs that expect either an `ILogger` or `ILoggerFactory`, that you don't want to provide a logger. In these cases, the [Microsoft.Extensions.Logging.Abstractions](https://www.nuget.org/packages/Microsoft.Extensions.Logging.Abstractions) NuGet package provides no-op logging defaults. +When you consume a library that exposes logging APIs that expect either an `ILogger` or `ILoggerFactory`, there might be times that you don't want to provide a logger. In these cases, the [Microsoft.Extensions.Logging.Abstractions](https://www.nuget.org/packages/Microsoft.Extensions.Logging.Abstractions) NuGet package provides no-op logging defaults. Library consumers can default to _null logging_ if no `ILoggerFactory` is provided. The use of _null logging_ differs from defining types as nullable (`ILoggerFactory?`), as the types are non-null. These convenience-based types don't log anything and are essentially no-ops. Consider using any of the available abstraction types where applicable: diff --git a/docs/core/extensions/log-buffering.md b/docs/core/extensions/logging/log-buffering.md similarity index 82% rename from docs/core/extensions/log-buffering.md rename to docs/core/extensions/logging/log-buffering.md index 73db6079c24dc..fdde1bbae230b 100644 --- a/docs/core/extensions/log-buffering.md +++ b/docs/core/extensions/logging/log-buffering.md @@ -28,7 +28,7 @@ There are two buffering strategies available: Log buffering works with all logging providers. If a logging provider you use does not implement the interface, log buffering will call log methods directly on each buffered log record when flushing the buffer. -Log buffering extends [filtering capabilities](logging.md#configure-logging-with-code) by allowing you to capture and store logs temporarily. Rather than making an immediate emit-or-discard decision, buffering lets you hold logs in memory and decide later whether to emit them. +Log buffering extends [filtering capabilities](overview.md#configure-logging-with-code) by allowing you to capture and store logs temporarily. Rather than making an immediate emit-or-discard decision, buffering lets you hold logs in memory and decide later whether to emit them. ## Get started @@ -55,7 +55,7 @@ dotnet add package Microsoft.AspNetCore.Diagnostics.Middleware --- -For more information about adding packages, see [dotnet add package](../tools/dotnet-package-add.md) or [Manage package dependencies in .NET applications](../tools/dependencies.md). +For more information about adding packages, see [dotnet add package](../../tools/dotnet-package-add.md) or [Manage package dependencies in .NET applications](../../tools/dependencies.md). ## Global buffering @@ -65,7 +65,7 @@ Global buffering allows you to buffer logs across your entire application. You c To enable global buffering at or below a specific log level, specify that level: -:::code language="csharp" source="snippets/logging/log-buffering/global/basic/Program.cs" range="18-19"::: +:::code language="csharp" source="../snippets/logging/log-buffering/global/basic/Program.cs" range="18-19"::: The preceding configuration enables buffering logs with level and below. @@ -73,7 +73,7 @@ The preceding configuration enables buffering logs with level [!NOTE] > Flushing the per-request buffer also flushes the global buffer. @@ -171,15 +171,15 @@ For each log record, the algorithm checks: ### Change buffer filtering rules in a running app -Both [global buffering](#global-buffering) and [per-request buffering](#per-request-buffering) support runtime configuration updates via the interface. If you're using a configuration provider that supports reloads—such as the [File Configuration Provider](configuration-providers.md#file-configuration-provider)—you can update filtering rules at runtime without restarting the application. +Both [global buffering](#global-buffering) and [per-request buffering](#per-request-buffering) support runtime configuration updates via the interface. If you're using a configuration provider that supports reloads—such as the [File Configuration Provider](../configuration-providers.md#file-configuration-provider)—you can update filtering rules at runtime without restarting the application. For example, you can start your application with the following _appsettings.json_, which enables log buffering for logs with the level and category starting with `PerRequestLogBufferingFileBased.`: -:::code language="json" source="snippets/logging/log-buffering/per-request/file-based/appsettings.json" range="1-19" ::: +:::code language="json" source="../snippets/logging/log-buffering/per-request/file-based/appsettings.json" range="1-19" ::: While the app is running, you can update the _appsettings.json_ with the following configuration: -:::code language="json" source="snippets/logging/log-buffering/per-request/file-based/appsettingsUpdated.json" range="1-17" highlight="9-13" ::: +:::code language="json" source="../snippets/logging/log-buffering/per-request/file-based/appsettingsUpdated.json" range="1-17" highlight="9-13" ::: The new rules are applied automatically. For example, with the preceding configuration, all logs with the level will be buffered. @@ -215,5 +215,5 @@ However, be mindful of the memory consumption, especially in high-throughput app ## See also - [Log sampling](log-sampling.md) -- [Logging in .NET](logging.md) +- [Logging in .NET](overview.md) - [High-performance logging in .NET](high-performance-logging.md) diff --git a/docs/core/extensions/log-sampling.md b/docs/core/extensions/logging/log-sampling.md similarity index 84% rename from docs/core/extensions/log-sampling.md rename to docs/core/extensions/logging/log-sampling.md index 341c2a23e2016..c8e225219c4e8 100644 --- a/docs/core/extensions/log-sampling.md +++ b/docs/core/extensions/logging/log-sampling.md @@ -15,7 +15,7 @@ ms.date: 04/29/2025 > [!NOTE] > Only one sampler can be used at a time. If you register multiple samplers, the last one is used. -Log sampling extends [filtering capabilities](logging.md#configure-logging-with-code) by giving you more fine-grained control over which logs are emitted by your application. Instead of simply enabling or disabling logs, you can configure sampling to emit only a fraction of them. +Log sampling extends [filtering capabilities](overview.md#configure-logging-with-code) by giving you more fine-grained control over which logs are emitted by your application. Instead of simply enabling or disabling logs, you can configure sampling to emit only a fraction of them. For example, while filtering typically uses probabilities like `0` (emit no logs) or `1` (emit all logs), sampling lets you choose any value in between—such as `0.1` to emit 10% of logs, or `0.25` to emit 25%. @@ -40,13 +40,13 @@ dotnet add package Microsoft.Extensions.Telemetry --- -For more information, see [dotnet add package](../tools/dotnet-package-add.md) or [Manage package dependencies in .NET applications](../tools/dependencies.md). +For more information, see [dotnet add package](../../tools/dotnet-package-add.md) or [Manage package dependencies in .NET applications](../../tools/dependencies.md). ## Configure trace-based sampling -Trace-based sampling ensures that logs are sampled consistently with the underlying . This is useful when you want to maintain correlation between traces and logs. You can enable trace sampling (as described in the [guide](../diagnostics/distributed-tracing-concepts.md#sampling)), and then configure trace-based log sampling accordingly: +Trace-based sampling ensures that logs are sampled consistently with the underlying . This is useful when you want to maintain correlation between traces and logs. You can enable trace sampling (as described in the [guide](../../diagnostics/distributed-tracing-concepts.md#sampling)), and then configure trace-based log sampling accordingly: -:::code language="csharp" source="snippets/logging/log-sampling/trace-based/Program.cs" range="20"::: +:::code language="csharp" source="../snippets/logging/log-sampling/trace-based/Program.cs" range="20"::: When trace-based sampling is enabled, logs will only be emitted if the underlying is sampled. The sampling decision comes from the current value. @@ -64,7 +64,7 @@ There are several ways to configure random probabilistic sampling with its rules Create a configuration section in your _appsettings.json_, for example: -:::code language="json" source="snippets/logging/log-sampling/file-config/appsettings.json" ::: +:::code language="json" source="../snippets/logging/log-sampling/file-config/appsettings.json" ::: The preceding configuration: @@ -78,25 +78,25 @@ The preceding configuration: To register the sampler with the configuration, consider the following code: -:::code language="csharp" source="snippets/logging/log-sampling/file-config/Program.cs" range="16"::: +:::code language="csharp" source="../snippets/logging/log-sampling/file-config/Program.cs" range="16"::: #### Change sampling rules in a running app -Random probabilistic sampling supports runtime configuration updates via the interface. If you're using a configuration provider that supports reloads—such as the [File Configuration Provider](configuration-providers.md#file-configuration-provider)—you can update sampling rules at runtime without restarting the application. +Random probabilistic sampling supports runtime configuration updates via the interface. If you're using a configuration provider that supports reloads—such as the [File Configuration Provider](../configuration-providers.md#file-configuration-provider)—you can update sampling rules at runtime without restarting the application. For example, you can start your application with the following _appsettings.json_, which effectively acts as a no-op: -:::code language="json" source="snippets/logging/log-sampling/appsettings.noop.json" ::: +:::code language="json" source="../snippets/logging/log-sampling/appsettings.noop.json" ::: While the app is running, you can update the _appsettings.json_ with the following configuration: -:::code language="json" source="snippets/logging/log-sampling/appsettings.updated.json" ::: +:::code language="json" source="../snippets/logging/log-sampling/appsettings.updated.json" ::: The new rules will be applied automatically, for instance, with the preceding configuration, 1% of logs with the are sampled. #### How sampling rules are applied -The algorithm is very similar to [log filtering](logging.md#how-filtering-rules-are-applied), yet there are some differences. +The algorithm is very similar to [log filtering](overview.md#how-filtering-rules-are-applied), yet there are some differences. Log sampling rules evaluation is performed on each log record, however, there are performance optimizations in place, such as caching. The following algorithm is used for each log record for a given category: @@ -108,7 +108,7 @@ Log sampling rules evaluation is performed on each log record, however, there ar ### Inline code configuration -:::code language="csharp" source="snippets/logging/log-sampling/code-config/Program.cs" range="16-22"::: +:::code language="csharp" source="../snippets/logging/log-sampling/code-config/Program.cs" range="16-22"::: The preceding configuration: @@ -119,7 +119,7 @@ The preceding configuration: For basic scenarios, you can configure a single probability value that applies to all logs at or below a specified level: -:::code language="csharp" source="snippets/logging/log-sampling/Program.cs" range="14-15"::: +:::code language="csharp" source="../snippets/logging/log-sampling/Program.cs" range="14-15"::: The code above registers the sampler which would sample 10% of logs and 1% of (and below) logs. If the configuration did not have the rule for , it would have sampled 10% of logs and all levels below, including . @@ -166,6 +166,6 @@ For the built-in sampling, see [Benchmarks](https://github.com/dotnet/extensions ## See also -- [Logging in .NET](logging.md) +- [Logging in .NET](overview.md) - [High-performance logging in .NET](high-performance-logging.md) - [OpenTelemetry Tracing Sampling](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#sampling) diff --git a/docs/core/extensions/media/color-console-logger.png b/docs/core/extensions/logging/media/color-console-logger.png similarity index 100% rename from docs/core/extensions/media/color-console-logger.png rename to docs/core/extensions/logging/media/color-console-logger.png diff --git a/docs/core/extensions/media/console-logs-format-simple.png b/docs/core/extensions/logging/media/console-logs-format-simple.png similarity index 100% rename from docs/core/extensions/media/console-logs-format-simple.png rename to docs/core/extensions/logging/media/console-logs-format-simple.png diff --git a/docs/core/extensions/media/console-logs-format-systemd.png b/docs/core/extensions/logging/media/console-logs-format-systemd.png similarity index 100% rename from docs/core/extensions/media/console-logs-format-systemd.png rename to docs/core/extensions/logging/media/console-logs-format-systemd.png diff --git a/docs/core/extensions/logging.md b/docs/core/extensions/logging/overview.md similarity index 83% rename from docs/core/extensions/logging.md rename to docs/core/extensions/logging/overview.md index c5bc10ebb86a6..8f7cf090db475 100644 --- a/docs/core/extensions/logging.md +++ b/docs/core/extensions/logging/overview.md @@ -7,7 +7,7 @@ ai-usage: ai-assisted # Logging in C# and .NET -.NET supports high performance, structured logging via the API to help monitor application behavior and diagnose issues. Configure different [logging providers](logging-providers.md) to write logs to different destinations. Basic logging providers are built-in, and many third-party providers are available. +.NET supports high performance, structured logging via the API to help monitor application behavior and diagnose issues. Configure different [logging providers](providers.md) to write logs to different destinations. Basic logging providers are built-in, and many third-party providers are available. ## Get started @@ -18,17 +18,17 @@ This first example shows the basics, but it's only suitable for a trivial consol In the next section you see how to improve the code considering scale, performance, configuration, and typical programming patterns. -:::code language="csharp" source="snippets/logging/getting-started/Program.cs"::: +:::code language="csharp" source="../snippets/logging/getting-started/Program.cs"::: The preceding example: -- Creates an . The `ILoggerFactory` stores all the configuration that determines where log messages are sent. In this case, configure the console [logging provider](logging-providers.md) so that log messages are written to the console. +- Creates an . The `ILoggerFactory` stores all the configuration that determines where log messages are sent. In this case, configure the console [logging provider](providers.md) so that log messages are written to the console. - Creates an with a category named "Program". The [category](#log-category) is a `string` that's associated with each message logged by the `ILogger` object. It groups log messages from the same class (or category) together when searching or filtering logs. - Calls to log a message at the `Information` level. The [log level](#log-level) indicates the severity of the logged event and filters out less important log messages. The log entry also includes a [message template](#log-message-template) `"Hello World! Logging is {Description}."` and a key-value pair `Description = 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: -:::code language="xml" source="snippets/logging/getting-started/getting-started.csproj"::: +:::code language="xml" source="../snippets/logging/getting-started/getting-started.csproj"::: [!INCLUDE [logging-samples-browser](includes/logging-samples-browser.md)] @@ -36,50 +36,50 @@ This project file for this example includes two NuGet packages: Consider making these changes to the previous example when logging in a less trivial scenario: -- If your application uses [Dependency Injection (DI)](dependency-injection/overview.md) or a host such as ASP.NET's [WebApplication](/aspnet/core/fundamentals/minimal-apis/webapplication) or [Generic Host](generic-host.md), use `ILoggerFactory` and `ILogger` objects from their respective DI containers rather than creating them directly. For more information, see [Integration with DI and Hosts](#integration-with-hosts-and-dependency-injection). +- If your application uses [Dependency Injection (DI)](../dependency-injection/overview.md) or a host such as ASP.NET's [WebApplication](/aspnet/core/fundamentals/minimal-apis/webapplication) or [Generic Host](../generic-host.md), use `ILoggerFactory` and `ILogger` objects from their respective DI containers rather than creating them directly. For more information, see [Integration with DI and Hosts](#integration-with-hosts-and-dependency-injection). -- Logging [compile-time source generation](logger-message-generator.md) is usually a better alternative to `ILogger` extension methods like `LogInformation`. Logging source generation offers better performance, stronger typing, and avoids spreading `string` constants throughout your methods. The tradeoff is that using this technique requires a bit more code. +- [Compile-time source generation](source-generation.md) for logging is usually a better alternative to `ILogger` extension methods like `LogInformation`. Source-generated logging offers better performance and stronger typing, and avoids spreading `string` constants throughout your methods. The tradeoff is that using this technique requires a bit more code. -:::code language="csharp" source="snippets/logging/getting-started-logger-message/Program.cs" highlight="9,12-13"::: + :::code language="csharp" source="../snippets/logging/getting-started-logger-message/Program.cs" highlight="9,12-13"::: -- 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. accepts a `Type` to make this naming easy to do. +- The recommended practice for choosing a log category name 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. Specify the class type in the type parameter of the method. -:::code language="csharp" source="snippets/logging/getting-started-type-category-name/Program.cs" highlight="8"::: + :::code language="csharp" source="../snippets/logging/getting-started-type-category-name/Program.cs" highlight="8"::: -- If you don't use console logs as your sole production monitoring solution, add the [logging providers](logging-providers.md) you plan to use. For example, use [OpenTelemetry](https://github.com/open-telemetry/opentelemetry-dotnet#getting-started) to send logs over [OTLP (OpenTelemetry protocol)](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md#enable-log-exporter): +- If you don't use console logs as your sole production monitoring solution, add the [logging providers](providers.md) you plan to use. For example, use [OpenTelemetry](https://github.com/open-telemetry/opentelemetry-dotnet#getting-started) to send logs over [OTLP (OpenTelemetry protocol)](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md#enable-log-exporter): -:::code language="csharp" source="snippets/logging/getting-started-open-telemetry/Program.cs" highlight="6-9"::: + :::code language="csharp" source="../snippets/logging/getting-started-open-telemetry/Program.cs" highlight="6-9"::: ## Integration with hosts and dependency injection -If your application uses [Dependency Injection (DI)](dependency-injection/overview.md) or a host such as ASP.NET's [WebApplication](/aspnet/core/fundamentals/minimal-apis/webapplication) or [Generic Host](generic-host.md), use `ILoggerFactory` and `ILogger` objects from the DI container rather than creating them directly. +If your application uses [Dependency Injection (DI)](../dependency-injection/overview.md) or a host such as ASP.NET's [WebApplication](/aspnet/core/fundamentals/minimal-apis/webapplication) or [Generic Host](../generic-host.md), use `ILoggerFactory` and `ILogger` 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 using [ASP.NET Minimal APIs](/aspnet/core/fundamentals/minimal-apis/overview): -:::code language="csharp" source="snippets/logging/minimal-web/Program.cs" highlight="12"::: +:::code language="csharp" source="../snippets/logging/minimal-web/Program.cs" highlight="12"::: The preceding example: - Created a singleton service called `ExampleHandler` and mapped incoming web requests to run the `ExampleHandler.HandleRequest` function. -- Line 12 defines a [primary constructor](../../csharp/whats-new/tutorials/primary-constructors.md) for the ExampleHandler, a feature added in C# 12. Using the older style C# constructor works equally well but is a little more verbose. +- Line 12 defines a [primary constructor](../../../csharp/whats-new/tutorials/primary-constructors.md) 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 type `ILogger`. derives from and indicates which category the `ILogger` object has. The DI container locates an `ILogger` with the correct category and supplies it as the constructor argument. If no `ILogger` with that category exists yet, the DI container automatically creates it from the `ILoggerFactory` in the service provider. - The `logger` parameter received in the constructor is used for logging in the `HandleRequest` function. ### Host-provided ILoggerFactory -Host builders initialize [default configuration](generic-host.md#host-builder-settings), then add a configured `ILoggerFactory` object to the host's DI container when the host is built. Before the host is built, adjust the logging configuration via , , or similar APIs on other hosts. Hosts also apply logging configuration from default configuration sources like _appsettings.json_ and environment variables. For more information, see [Configuration in .NET](configuration.md). +Host builders initialize [default configuration](../generic-host.md#host-builder-settings), then add a configured `ILoggerFactory` object to the host's DI container when the host is built. Before the host is built, adjust the logging configuration via , , or similar APIs on other hosts. Hosts also apply logging configuration from default configuration sources like _appsettings.json_ and environment variables. For more information, see [Configuration in .NET](../configuration.md). This example expands on the previous one to customize the `ILoggerFactory` provided by `WebApplicationBuilder`. It adds [OpenTelemetry](https://github.com/open-telemetry/opentelemetry-dotnet#getting-started) as a logging provider transmitting the logs over [OTLP (OpenTelemetry protocol)](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md#enable-log-exporter): -:::code language="csharp" source="snippets/logging/minimal-web-open-telemetry/Program.cs" range="3-6" highlight="2"::: +:::code language="csharp" source="../snippets/logging/minimal-web-open-telemetry/Program.cs" range="3-6" highlight="2"::: ### Create an ILoggerFactory with DI If you're using a DI container without a host, use to configure and add `ILoggerFactory` to the container. -:::code language="csharp" source="snippets/logging/di-without-host/Program.cs" highlight="6"::: +:::code language="csharp" source="../snippets/logging/di-without-host/Program.cs" highlight="6"::: The preceding example: @@ -94,11 +94,11 @@ Set logging configuration in code or via external sources, such as config files ### Configure logging without code -For apps that [use a host](#integration-with-hosts-and-dependency-injection), the `"Logging"` section of _appsettings_`.{Environment}`_.json_ files commonly provides logging configuration. For apps that don't use a host, [set up external configuration sources explicitly](configuration.md) or [configure them in code](#configure-logging-with-code) instead. +For apps that [use a host](#integration-with-hosts-and-dependency-injection), the `"Logging"` section of _appsettings_`.{Environment}`_.json_ files commonly provides logging configuration. For apps that don't use a host, [set up external configuration sources explicitly](../configuration.md) or [configure them in code](#configure-logging-with-code) instead. The following _appsettings.Development.json_ file is generated by the .NET Worker service templates: -:::code language="json" source="snippets/configuration/worker-service/appsettings.Development.json"::: +:::code language="json" source="../snippets/configuration/worker-service/appsettings.Development.json"::: In the preceding JSON: @@ -107,7 +107,7 @@ In the preceding JSON: - The `"Microsoft"` category applies to all categories that start with `"Microsoft"`. - The `"Microsoft"` category logs at a log level of `Warning` 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, so `LogLevel` applies to all the enabled logging providers except for the [Windows EventLog](logging-providers.md#windows-eventlog). +- A specific log provider isn't specified, so `LogLevel` applies to all the enabled logging providers except for the [Windows EventLog](providers.md#windows-eventlog). The `Logging` property can have and log provider properties. The `LogLevel` specifies the minimum [level](#log-level) to log for selected categories. In the preceding JSON, `Information` and `Warning` log levels are specified. `LogLevel` indicates the severity of the log and ranges from 0 to 6: @@ -117,7 +117,7 @@ When a `LogLevel` is specified, logging is enabled for messages at the specified A provider property can specify a `LogLevel` property. `LogLevel` under a provider specifies levels to log for that provider, and overrides the non-provider log settings. Consider the following *appsettings.json* file: -:::code language="json" source="snippets/configuration/worker-service/appsettings.Staging.json"::: +:::code language="json" source="../snippets/configuration/worker-service/appsettings.Staging.json"::: Settings in `Logging.{ProviderName}.LogLevel` override settings in `Logging.LogLevel`. In the preceding JSON, the `Debug` provider's default log level is set to `Information`: @@ -142,7 +142,7 @@ If a provider supports [log scopes](#log-scopes), `IncludeScopes` indicates whet The following *appsettings.json* file contains settings for all of the built-in providers: -:::code language="json" source="snippets/configuration/worker-service/appsettings.Production.json"::: +:::code language="json" source="../snippets/configuration/worker-service/appsettings.Production.json"::: In the preceding sample: @@ -159,7 +159,7 @@ In the preceding sample: ### Set log level by command line, environment variables, and other configuration -Set the log level using any of the [configuration providers](configuration-providers.md). For example, create a persisted environment variable named `Logging:LogLevel:Microsoft` with a value of `Information`. +Set the log level using any of the [configuration providers](../configuration-providers.md). For example, create a persisted environment variable named `Logging:LogLevel:Microsoft` with a value of `Information`. ## [Command Line](#tab/command-line) @@ -233,7 +233,7 @@ On [Azure App Service](https://azure.microsoft.com/services/app-service/), selec - Encrypted at rest and transmitted over an encrypted channel. - Exposed as environment variables. -For more information on setting .NET configuration values using environment variables, see [environment variables](configuration-providers.md#environment-variable-configuration-provider). +For more information on setting .NET configuration values using environment variables, see [environment variables](../configuration-providers.md#environment-variable-configuration-provider). ### Configure logging with code @@ -243,7 +243,7 @@ To configure logging in code, use the . - When using a host, configure with , or other host specific APIs. -This example shows setting the console [logging provider](logging-providers.md) and several [filters](#how-filtering-rules-are-applied). +This example shows setting the console [logging provider](providers.md) and several [filters](#how-filtering-rules-are-applied). ```csharp using Microsoft.Extensions.Logging; @@ -376,7 +376,7 @@ Configure the appropriate log level and call the correct `Log{LogLevel}` methods The following JSON sets `Logging:Console:LogLevel:Microsoft:Information`: -:::code language="json" source="snippets/configuration/worker-service/appsettings.MSFT.json"::: +:::code language="json" source="../snippets/configuration/worker-service/appsettings.MSFT.json"::: ## Log event ID @@ -452,7 +452,7 @@ For example, when logging to Azure Table Storage: ### Log message template formatting -Log message templates support placeholder formatting. Templates can specify [any valid format](../../standard/base-types/formatting-types.md) for the given type argument. For example, consider the following `Information` logger message template: +Log message templates support placeholder formatting. Templates can specify [any valid format](../../../standard/base-types/formatting-types.md) for the given type argument. For example, consider the following `Information` logger message template: ```csharp _logger.LogInformation("Logged on {PlaceHolderName:MMMM dd, yyyy}", DateTimeOffset.UtcNow); @@ -461,7 +461,7 @@ _logger.LogInformation("Logged on {PlaceHolderName:MMMM dd, yyyy}", DateTimeOffs In the preceding example, the `DateTimeOffset` instance is the type that corresponds to the `PlaceHolderName` in the logger message template. This name can be anything as the values are ordinal-based. The `MMMM dd, yyyy` format is valid for the `DateTimeOffset` type. -For more information on `DateTime` and `DateTimeOffset` formatting, see [Custom date and time format strings](../../standard/base-types/custom-date-and-time-format-strings.md). +For more information on `DateTime` and `DateTimeOffset` formatting, see [Custom date and time format strings](../../../standard/base-types/custom-date-and-time-format-strings.md). #### Examples @@ -476,7 +476,7 @@ logger.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 rule [CA2254: Template should be a static expression](../../fundamentals/code-analysis/quality-rules/ca2254.md) helps alert you to places where your log messages don't use proper formatting. +> - Code analysis rule [CA2254: Template should be a static expression](../../../fundamentals/code-analysis/quality-rules/ca2254.md) helps alert you to places where your log messages don't use proper formatting. ## Log exceptions @@ -592,7 +592,7 @@ public async Task GetAsync(string id) The following JSON enables scopes for the console provider: -:::code language="json" source="snippets/configuration/worker-service/appsettings.IncludeScopes.json" highlight="9"::: +:::code language="json" source="../snippets/configuration/worker-service/appsettings.IncludeScopes.json" highlight="9"::: The following code enables scopes for the console provider: @@ -655,7 +655,7 @@ Logging should be so fast that it isn't worth the performance cost of asynchrono ## 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, the [File Configuration Provider](configuration-providers.md#file-configuration-provider) reloads logging configuration by default. If you change the configuration in code while an app is running, the app can call [IConfigurationRoot.Reload](xref:Microsoft.Extensions.Configuration.IConfigurationRoot.Reload%2A) to update the app's logging configuration. +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, the [File Configuration Provider](../configuration-providers.md#file-configuration-provider) reloads logging configuration by default. If you change the configuration in code while an app is running, the app can call [IConfigurationRoot.Reload](xref:Microsoft.Extensions.Configuration.IConfigurationRoot.Reload%2A) to update the app's logging configuration. ## NuGet packages @@ -664,13 +664,13 @@ The and , which adds the following logging providers: - [Console](#console) - [Debug](#debug) - [EventSource](#event-source) - [EventLog](#windows-eventlog) (Windows only) -:::code language="csharp" source="snippets/configuration/console/Program.cs" highlight="17"::: +:::code language="csharp" source="../snippets/configuration/console/Program.cs" highlight="17"::: The preceding code shows the `Program` class created with the .NET Worker app templates. The next several sections provide samples based on the .NET Worker app templates, which use the Generic Host. @@ -83,9 +83,9 @@ The `EventSource` provider writes to a cross-platform event source with the name #### dotnet trace tooling -The [dotnet-trace](../diagnostics/dotnet-trace.md) tool is a cross-platform CLI global tool that enables the collection of .NET Core traces of a running process. The tool collects provider data using a . +The [dotnet-trace](../../diagnostics/dotnet-trace.md) tool is a cross-platform CLI global tool that enables the collection of .NET Core traces of a running process. The tool collects provider data using a . -See [dotnet-trace](../diagnostics/dotnet-trace.md) for installation instructions. For a diagnostic tutorial using `dotnet-trace`, see [Debug high CPU usage in .NET Core](../diagnostics/debug-highcpu.md). +See [dotnet-trace](../../diagnostics/dotnet-trace.md) for installation instructions. For a diagnostic tutorial using `dotnet-trace`, see [Debug high CPU usage in .NET Core](../../diagnostics/debug-highcpu.md). ### Windows EventLog @@ -199,7 +199,7 @@ If you plan to develop your own implementation of the method. If your implementation strives to queue logging messages in a non-blocking manner, the messages should first be materialized or the object state that's used to materialize a log entry should be serialized. Doing so avoids potential exceptions from disposed objects. -For more information, see [Implement a custom logging provider in .NET](custom-logging-provider.md). +For more information, see [Implement a custom logging provider in .NET](custom-provider.md). ## Third-party logging providers @@ -228,6 +228,6 @@ For more information, see each provider's documentation. Third-party logging pro ## See also -- [Logging in .NET](logging.md). -- [Implement a custom logging provider in .NET](custom-logging-provider.md). +- [Logging in .NET](overview.md). +- [Implement a custom logging provider in .NET](custom-provider.md). - [High-performance logging in .NET](high-performance-logging.md). diff --git a/docs/core/extensions/logger-message-generator.md b/docs/core/extensions/logging/source-generation.md similarity index 89% rename from docs/core/extensions/logger-message-generator.md rename to docs/core/extensions/logging/source-generation.md index b87034f8342e6..e626d01df6f47 100644 --- a/docs/core/extensions/logger-message-generator.md +++ b/docs/core/extensions/logging/source-generation.md @@ -7,9 +7,9 @@ ai-usage: ai-assisted # Compile-time logging source generation -.NET 6 introduces the `LoggerMessageAttribute` type. This attribute is part of the `Microsoft.Extensions.Logging` namespace, and when used, it source-generates performant logging APIs. The source-generation logging support is designed to deliver a highly usable and highly performant logging solution for modern .NET applications. The auto-generated source code relies on the interface in conjunction with functionality. +Source-generated logging is designed to deliver a highly usable and highly performant logging solution for modern .NET apps. The auto-generated source code relies on the interface in conjunction with functionality. -The source generator is triggered when `LoggerMessageAttribute` is used on `partial` logging methods. When triggered, it's either able to autogenerate the implementation of the `partial` methods it's decorating, or produce compile-time diagnostics with hints about proper usage. The compile-time logging solution is considerably faster at runtime than existing logging approaches. It achieves this by eliminating boxing, temporary allocations, and copies to the maximum extent possible. +The source generator is triggered when is used on `partial` logging methods. When triggered, it autogenerates the implementation of the `partial` methods it's decorating. If there's a problem, it produces compile-time diagnostics with hints about proper usage. This compile-time logging solution is considerably faster at runtime than previously available logging approaches. It eliminates boxing, temporary allocations, and copies to the maximum extent possible. ## Basic usage @@ -93,7 +93,7 @@ public static partial class Log You can omit the logging message and is provided for the message. The state contains the arguments, formatted as key-value pairs. -:::code source="snippets/logging/logger-message-generator/Program.cs"::: +:::code source="../snippets/logging/logger-message-generator/Program.cs"::: Consider the example logging output when using the `JsonConsole` formatter. @@ -114,7 +114,7 @@ Consider the example logging output when using the `JsonConsole` formatter. ## Log method constraints -When using the `LoggerMessageAttribute` on logging methods, some constraints must be followed: +Logging methods that are decorated with `LoggerMessageAttribute` must meet the following requirements: - Logging methods must be `partial` and return `void`. - Logging method names must *not* start with an underscore. @@ -122,15 +122,7 @@ When using the `LoggerMessageAttribute` on logging methods, some constraints mus - Logging methods *can't* be generic. - If a logging method is `static`, the `ILogger` instance is required as a parameter. -The code-generation model depends on code being compiled with a modern C# compiler, version 9 or later. The C# 9.0 compiler became available with .NET 5. To upgrade to a modern C# compiler, edit your project file to target C# 9.0. - -```xml - - 9.0 - -``` - -For more information, see [C# language versioning](../../csharp/language-reference/configure-language-version.md). +The code-generation model depends on code being compiled with a modern C# compiler, that is, version 9 or later. For information about changing the language version, see [C# language versioning](../../../csharp/language-reference/configure-language-version.md). ## Log method anatomy @@ -423,8 +415,8 @@ The output should be like this: This approach ensures that only redacted data is logged, even when using compile-time generated logging APIs. You can use different redactors for different data types or classifications, and update your redaction logic centrally. -For more information about how to classify your data, see [Data classification in .NET](data-classification.md). -For more information about redaction and redactors, see [Data redaction in .NET](data-redaction.md). +For more information about how to classify your data, see [Data classification in .NET](../data-classification.md). +For more information about redaction and redactors, see [Data redaction in .NET](../data-redaction.md). ## Summary @@ -433,7 +425,7 @@ With the advent of C# source generators, writing highly performant logging APIs - Allows the logging structure to be preserved and enables the exact format syntax required by [Message Templates](https://messagetemplates.org). - Allows supplying alternative names for the template placeholders and using format specifiers. - Allows the passing of all original data as-is, without any complication around how it's stored before something is done with it (other than creating a `string`). -- Provides logging-specific diagnostics, and emits warnings for duplicate event IDs. +- Provides logging-specific diagnostics and emits warnings for duplicate event IDs. Additionally, there are benefits over manually using : @@ -444,9 +436,9 @@ Additionally, there are benefits over manually using Demonstrates how to use log buffering feature. Exe $(NoWarn);EXTEXP0003 - $(LatestTargetFramework) + net10.0 GlobalLogBufferingBasic diff --git a/docs/core/extensions/snippets/logging/log-sampling/code-config/LogSamplingCodeConfig.csproj b/docs/core/extensions/snippets/logging/log-sampling/code-config/LogSamplingCodeConfig.csproj index 6dc59747c56e4..195089b610aeb 100644 --- a/docs/core/extensions/snippets/logging/log-sampling/code-config/LogSamplingCodeConfig.csproj +++ b/docs/core/extensions/snippets/logging/log-sampling/code-config/LogSamplingCodeConfig.csproj @@ -3,6 +3,7 @@ Demonstrates how to use log sampling feature. Exe + net10.0 $(NoWarn);EXTEXP0003 diff --git a/docs/core/extensions/snippets/logging/log-sampling/file-config/LogSamplingFileConfig.csproj b/docs/core/extensions/snippets/logging/log-sampling/file-config/LogSamplingFileConfig.csproj index de183e9b44ec8..ea912002c8298 100644 --- a/docs/core/extensions/snippets/logging/log-sampling/file-config/LogSamplingFileConfig.csproj +++ b/docs/core/extensions/snippets/logging/log-sampling/file-config/LogSamplingFileConfig.csproj @@ -3,6 +3,7 @@ Demonstrates how to use log sampling feature. Exe + net10.0 $(NoWarn);EXTEXP0003 diff --git a/docs/core/extensions/snippets/logging/log-sampling/trace-based/LogSamplingTraceBased.csproj b/docs/core/extensions/snippets/logging/log-sampling/trace-based/LogSamplingTraceBased.csproj index 444864117d5bb..796e639843262 100644 --- a/docs/core/extensions/snippets/logging/log-sampling/trace-based/LogSamplingTraceBased.csproj +++ b/docs/core/extensions/snippets/logging/log-sampling/trace-based/LogSamplingTraceBased.csproj @@ -3,6 +3,7 @@ Demonstrates how to use log sampling feature. Exe + net10.0 $(NoWarn);EXTEXP0003 diff --git a/docs/core/extensions/snippets/logging/logging.sln b/docs/core/extensions/snippets/logging/logging.sln deleted file mode 100644 index 99c7ea57b6205..0000000000000 --- a/docs/core/extensions/snippets/logging/logging.sln +++ /dev/null @@ -1,103 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.2.32616.157 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "console-formatter-custom", "console-formatter-custom\console-formatter-custom.csproj", "{88C85579-02B5-4390-8D46-C8DE357ED069}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "console-formatter-custom-with-config", "console-formatter-custom-with-config\console-formatter-custom-with-config.csproj", "{84CA23D9-26F3-4092-89C4-E190CBDAA73B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "console-formatter-json", "console-formatter-json\console-formatter-json.csproj", "{6AB3E830-961E-432C-ABBA-9A4A413F1E0B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "console-formatter-simple", "console-formatter-simple\console-formatter-simple.csproj", "{083C961C-A45B-4721-A24A-7857592FF730}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "console-formatter-systemd", "console-formatter-systemd\console-formatter-systemd.csproj", "{55B4967D-4E68-4E6F-BEB4-0C61E676E683}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "worker-service-options", "worker-service-options\worker-service-options.csproj", "{2D23DB42-7FAF-452E-9AD2-36E925065270}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "logger-message-generator", "logger-message-generator\logger-message-generator.csproj", "{93C2255D-2CED-4C0A-8B2A-3191B0B85C7B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "library-authors", "library-authors\library-authors.csproj", "{C0C79D16-5ECB-4B52-9303-15DCF6B0B639}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "getting-started", "getting-started\getting-started.csproj", "{AA405DF9-EA0A-4130-BD42-F662CFFFA0B1}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "getting-started-logger-message", "getting-started-logger-message\getting-started-logger-message.csproj", "{1179C5BB-3C2F-4253-9FCC-528DACF1D0D6}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "getting-started-type-category-name", "getting-started-type-category-name\getting-started-type-category-name.csproj", "{8CE47011-B4BB-4054-A48F-30CCF5AE5671}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "getting-started-open-telemetry", "getting-started-open-telemetry\getting-started-open-telemetry.csproj", "{D711C802-982D-4712-B70D-A3179C4313CC}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "di-without-host", "di-without-host\di-without-host.csproj", "{5191561E-658B-485D-B006-760C65218FA5}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "minimal-web", "minimal-web\minimal-web.csproj", "{631A9547-C326-4BE6-A8C1-AB070AB0025D}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {88C85579-02B5-4390-8D46-C8DE357ED069}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {88C85579-02B5-4390-8D46-C8DE357ED069}.Debug|Any CPU.Build.0 = Debug|Any CPU - {88C85579-02B5-4390-8D46-C8DE357ED069}.Release|Any CPU.ActiveCfg = Release|Any CPU - {88C85579-02B5-4390-8D46-C8DE357ED069}.Release|Any CPU.Build.0 = Release|Any CPU - {84CA23D9-26F3-4092-89C4-E190CBDAA73B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {84CA23D9-26F3-4092-89C4-E190CBDAA73B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {84CA23D9-26F3-4092-89C4-E190CBDAA73B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {84CA23D9-26F3-4092-89C4-E190CBDAA73B}.Release|Any CPU.Build.0 = Release|Any CPU - {6AB3E830-961E-432C-ABBA-9A4A413F1E0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6AB3E830-961E-432C-ABBA-9A4A413F1E0B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6AB3E830-961E-432C-ABBA-9A4A413F1E0B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6AB3E830-961E-432C-ABBA-9A4A413F1E0B}.Release|Any CPU.Build.0 = Release|Any CPU - {083C961C-A45B-4721-A24A-7857592FF730}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {083C961C-A45B-4721-A24A-7857592FF730}.Debug|Any CPU.Build.0 = Debug|Any CPU - {083C961C-A45B-4721-A24A-7857592FF730}.Release|Any CPU.ActiveCfg = Release|Any CPU - {083C961C-A45B-4721-A24A-7857592FF730}.Release|Any CPU.Build.0 = Release|Any CPU - {55B4967D-4E68-4E6F-BEB4-0C61E676E683}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {55B4967D-4E68-4E6F-BEB4-0C61E676E683}.Debug|Any CPU.Build.0 = Debug|Any CPU - {55B4967D-4E68-4E6F-BEB4-0C61E676E683}.Release|Any CPU.ActiveCfg = Release|Any CPU - {55B4967D-4E68-4E6F-BEB4-0C61E676E683}.Release|Any CPU.Build.0 = Release|Any CPU - {2D23DB42-7FAF-452E-9AD2-36E925065270}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2D23DB42-7FAF-452E-9AD2-36E925065270}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2D23DB42-7FAF-452E-9AD2-36E925065270}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2D23DB42-7FAF-452E-9AD2-36E925065270}.Release|Any CPU.Build.0 = Release|Any CPU - {93C2255D-2CED-4C0A-8B2A-3191B0B85C7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {93C2255D-2CED-4C0A-8B2A-3191B0B85C7B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {93C2255D-2CED-4C0A-8B2A-3191B0B85C7B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {93C2255D-2CED-4C0A-8B2A-3191B0B85C7B}.Release|Any CPU.Build.0 = Release|Any CPU - {C0C79D16-5ECB-4B52-9303-15DCF6B0B639}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C0C79D16-5ECB-4B52-9303-15DCF6B0B639}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C0C79D16-5ECB-4B52-9303-15DCF6B0B639}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C0C79D16-5ECB-4B52-9303-15DCF6B0B639}.Release|Any CPU.Build.0 = Release|Any CPU - {AA405DF9-EA0A-4130-BD42-F662CFFFA0B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AA405DF9-EA0A-4130-BD42-F662CFFFA0B1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AA405DF9-EA0A-4130-BD42-F662CFFFA0B1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AA405DF9-EA0A-4130-BD42-F662CFFFA0B1}.Release|Any CPU.Build.0 = Release|Any CPU - {1179C5BB-3C2F-4253-9FCC-528DACF1D0D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1179C5BB-3C2F-4253-9FCC-528DACF1D0D6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1179C5BB-3C2F-4253-9FCC-528DACF1D0D6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1179C5BB-3C2F-4253-9FCC-528DACF1D0D6}.Release|Any CPU.Build.0 = Release|Any CPU - {8CE47011-B4BB-4054-A48F-30CCF5AE5671}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8CE47011-B4BB-4054-A48F-30CCF5AE5671}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8CE47011-B4BB-4054-A48F-30CCF5AE5671}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8CE47011-B4BB-4054-A48F-30CCF5AE5671}.Release|Any CPU.Build.0 = Release|Any CPU - {D711C802-982D-4712-B70D-A3179C4313CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D711C802-982D-4712-B70D-A3179C4313CC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D711C802-982D-4712-B70D-A3179C4313CC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D711C802-982D-4712-B70D-A3179C4313CC}.Release|Any CPU.Build.0 = Release|Any CPU - {5191561E-658B-485D-B006-760C65218FA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5191561E-658B-485D-B006-760C65218FA5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5191561E-658B-485D-B006-760C65218FA5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5191561E-658B-485D-B006-760C65218FA5}.Release|Any CPU.Build.0 = Release|Any CPU - {631A9547-C326-4BE6-A8C1-AB070AB0025D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {631A9547-C326-4BE6-A8C1-AB070AB0025D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {631A9547-C326-4BE6-A8C1-AB070AB0025D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {631A9547-C326-4BE6-A8C1-AB070AB0025D}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {9F9DEFD0-1FD9-461E-9409-D4A6B653139E} - EndGlobalSection -EndGlobal diff --git a/docs/core/extensions/snippets/logging/minimal-web-open-telemetry/Program.cs b/docs/core/extensions/snippets/logging/minimal-web-open-telemetry/Program.cs index cc0c1c09101d2..d9f869e961786 100644 --- a/docs/core/extensions/snippets/logging/minimal-web-open-telemetry/Program.cs +++ b/docs/core/extensions/snippets/logging/minimal-web-open-telemetry/Program.cs @@ -1,10 +1,10 @@ using OpenTelemetry.Logs; -var builder = WebApplication.CreateBuilder(args); +WebApplicationBuilder builder = WebApplication.CreateBuilder(args); builder.Logging.AddOpenTelemetry(logging => logging.AddOtlpExporter()); builder.Services.AddSingleton(); -var app = builder.Build(); -var handler = app.Services.GetRequiredService(); +WebApplication app = builder.Build(); +ExampleHandler handler = app.Services.GetRequiredService(); app.MapGet("/", handler.HandleRequest); app.Run(); diff --git a/docs/core/extensions/snippets/logging/minimal-web-open-telemetry/minimal-web-open-telemetry.csproj b/docs/core/extensions/snippets/logging/minimal-web-open-telemetry/minimal-web-open-telemetry.csproj index 962f8f2ccdf2c..ad8cc06d11d5c 100644 --- a/docs/core/extensions/snippets/logging/minimal-web-open-telemetry/minimal-web-open-telemetry.csproj +++ b/docs/core/extensions/snippets/logging/minimal-web-open-telemetry/minimal-web-open-telemetry.csproj @@ -7,4 +7,9 @@ minimal_web_open_telemetry + + + + + diff --git a/docs/core/extensions/windows-service.md b/docs/core/extensions/windows-service.md index a0754d8e81895..7745a06ea2b93 100644 --- a/docs/core/extensions/windows-service.md +++ b/docs/core/extensions/windows-service.md @@ -96,7 +96,7 @@ In the preceding code, the `JokeService` is injected along with an `ILogger`. Bo > } > ``` > -> For more information on configuring log levels, see [Logging providers in .NET: Configure Windows EventLog](logging-providers.md#windows-eventlog). +> For more information on configuring log levels, see [Logging providers in .NET: Configure Windows EventLog](logging/providers.md#windows-eventlog). ## Rewrite the `Program` class diff --git a/docs/core/whats-new/dotnet-6.md b/docs/core/whats-new/dotnet-6.md index cf4a69b21689a..c85d93590a74a 100644 --- a/docs/core/whats-new/dotnet-6.md +++ b/docs/core/whats-new/dotnet-6.md @@ -239,7 +239,7 @@ Several extensions namespaces have improvements in .NET 6, as the following tabl | - | - | | | lets you safely use a `using` statement for a service provider that registers an service. | | | New methods simplify application setup. | -| | has a new source generator for performant logging APIs. The source generator is triggered if you add the new to a `partial` logging method. At compile time, the generator generates the implementation of the `partial` method, which is typically faster at runtime than existing logging solutions. For more information, see [Compile-time logging source generation](../extensions/logger-message-generator.md). | +| | has a new source generator for performant logging APIs. The source generator is triggered if you add the new to a `partial` logging method. At compile time, the generator generates the implementation of the `partial` method, which is typically faster at runtime than existing logging solutions. For more information, see [Compile-time logging source generation](../extensions/logging/source-generation.md). | ## New LINQ APIs diff --git a/docs/fundamentals/code-analysis/quality-rules/ca1848.md b/docs/fundamentals/code-analysis/quality-rules/ca1848.md index e43d6d1c1b525..8da42e23d6e0b 100644 --- a/docs/fundamentals/code-analysis/quality-rules/ca1848.md +++ b/docs/fundamentals/code-analysis/quality-rules/ca1848.md @@ -26,7 +26,7 @@ Use of [logger extension methods](xref:Microsoft.Extensions.Logging.LoggerExtens ## Rule description -For high-performance logging scenarios, use the [LoggerMessage](../../../core/extensions/logger-message-generator.md) pattern instead of extension methods. +For high-performance logging scenarios, use the [LoggerMessage](../../../core/extensions/logging/source-generation.md) pattern instead of extension methods. ## How to fix violations @@ -81,6 +81,6 @@ Do not suppress a warning from this rule. ## See also -- [Compile-time logging source generation](../../../core/extensions/logger-message-generator.md) -- [High-performance logging in .NET](../../../core/extensions/high-performance-logging.md) +- [Compile-time logging source generation](../../../core/extensions/logging/source-generation.md) +- [High-performance logging in .NET](../../../core/extensions/logging/high-performance-logging.md) - [Performance rules](performance-warnings.md) diff --git a/docs/fundamentals/code-analysis/quality-rules/ca1873.md b/docs/fundamentals/code-analysis/quality-rules/ca1873.md index 5ee75f27938d7..9979975fe6c62 100644 --- a/docs/fundamentals/code-analysis/quality-rules/ca1873.md +++ b/docs/fundamentals/code-analysis/quality-rules/ca1873.md @@ -78,5 +78,5 @@ For more information, see [How to suppress code analysis warnings](../suppress-w ## See also - [Performance rules](performance-warnings.md) -- [High-performance logging in .NET](../../../core/extensions/high-performance-logging.md) -- [Compile-time logging source generation](../../../core/extensions/logger-message-generator.md) +- [High-performance logging in .NET](../../../core/extensions/logging/high-performance-logging.md) +- [Compile-time logging source generation](../../../core/extensions/logging/source-generation.md) diff --git a/docs/fundamentals/code-analysis/quality-rules/ca2023.md b/docs/fundamentals/code-analysis/quality-rules/ca2023.md index fa8a1f8d11838..86c3c92d1f8ac 100644 --- a/docs/fundamentals/code-analysis/quality-rules/ca2023.md +++ b/docs/fundamentals/code-analysis/quality-rules/ca2023.md @@ -162,5 +162,5 @@ For more information, see [How to suppress code analysis warnings](../suppress-w ## See also - [Reliability rules](reliability-warnings.md) -- [High-performance logging in .NET](../../../core/extensions/high-performance-logging.md) -- [Logging in .NET](../../../core/extensions/logging.md) +- [High-performance logging in .NET](../../../core/extensions/logging/high-performance-logging.md) +- [Logging in .NET](../../../core/extensions/logging/overview.md) diff --git a/docs/fundamentals/code-analysis/quality-rules/ca2254.md b/docs/fundamentals/code-analysis/quality-rules/ca2254.md index d5c7aa2127129..10a6711e629ea 100644 --- a/docs/fundamentals/code-analysis/quality-rules/ca2254.md +++ b/docs/fundamentals/code-analysis/quality-rules/ca2254.md @@ -22,7 +22,7 @@ author: Youssef1313 ## Cause -A message template passed to a logger API is not constant. This occurs when the template passed uses either string concatenation or interpolation. Instead, the template should be a constant value that represents the log message in _message template format_. For example: `"User {User} logged in from {Address}"`. For more information, see [Log message template formatting](../../../core/extensions/logging.md#log-message-template-formatting). +A message template passed to a logger API is not constant. This occurs when the template passed uses either string concatenation or interpolation. Instead, the template should be a constant value that represents the log message in _message template format_. For example: `"User {User} logged in from {Address}"`. For more information, see [Log message template formatting](../../../core/extensions/logging/overview.md#log-message-template-formatting). ## Rule description @@ -73,4 +73,4 @@ It's safe to suppress a warning from this rule if your use case doesn't require ## See also - [Usage warnings](usage-warnings.md) -- [Logging in C# and .NET](../../../core/extensions/logging.md) +- [Logging in C# and .NET](../../../core/extensions/logging/overview.md) diff --git a/docs/fundamentals/syslib-diagnostics/syslib1027.md b/docs/fundamentals/syslib-diagnostics/syslib1027.md index bc9b616382676..3ca0c9b222071 100644 --- a/docs/fundamentals/syslib-diagnostics/syslib1027.md +++ b/docs/fundamentals/syslib-diagnostics/syslib1027.md @@ -24,10 +24,10 @@ partial class C(ILogger logger) ## Workarounds -Either remove the field or the primary constructor. For more information, see [Basic usage](../../core/extensions/logger-message-generator.md#basic-usage). +Either remove the field or the primary constructor. For more information, see [Basic usage](../../core/extensions/logging/source-generation.md#basic-usage). [!INCLUDE [suppress-syslib-warning](includes/suppress-source-generator-diagnostics.md)] ## See also -- [Compile-time logging source generation](../../core/extensions/logger-message-generator.md) +- [Compile-time logging source generation](../../core/extensions/logging/source-generation.md) diff --git a/docs/fundamentals/toc.yml b/docs/fundamentals/toc.yml index 73202d2e14101..972710a954a28 100644 --- a/docs/fundamentals/toc.yml +++ b/docs/fundamentals/toc.yml @@ -1083,29 +1083,29 @@ items: - name: Logging items: - name: Overview - href: ../core/extensions/logging.md + href: ../core/extensions/logging/overview.md displayName: logging,logger,log,loggers - name: Logging providers - href: ../core/extensions/logging-providers.md + href: ../core/extensions/logging/providers.md displayName: logging providers,log providers - name: Compile-time logging source generation - href: ../core/extensions/logger-message-generator.md + href: ../core/extensions/logging/source-generation.md displayName: LoggerMessage,LoggerMessageAttribute,source generator,compile-time generation - name: Logging guidance for library authors - href: ../core/extensions/logging-library-authors.md + href: ../core/extensions/logging/library-guidance.md displayName: logging guidance,logger guidance,log guidance - name: Implement a custom logging provider - href: ../core/extensions/custom-logging-provider.md + href: ../core/extensions/logging/custom-provider.md displayName: custom logging,custom log,custom logging provider,custom log provider - name: High-performance logging - href: ../core/extensions/high-performance-logging.md + href: ../core/extensions/logging/high-performance-logging.md displayName: high-performance logging,high-performance log,high-performance logging provider,high-performance log provider - name: Log Sampling - href: ../core/extensions/log-sampling.md + href: ../core/extensions/logging/log-sampling.md - name: Log Buffering - href: ../core/extensions/log-buffering.md + href: ../core/extensions/logging/log-buffering.md - name: Console log formatting - href: ../core/extensions/console-log-formatter.md + href: ../core/extensions/logging/console-log-formatter.md displayName: console log formatting,console log formatter,console log formatting provider,console log formatter provider - name: HostBuilder (generic host) href: ../core/extensions/generic-host.md diff --git a/docs/orleans/host/monitoring/index.md b/docs/orleans/host/monitoring/index.md index 8653fabb47e2d..247e6cc7320ad 100644 --- a/docs/orleans/host/monitoring/index.md +++ b/docs/orleans/host/monitoring/index.md @@ -13,7 +13,7 @@ Observability is one of the most important aspects of a distributed system. It's ## Logging -Orleans uses [Microsoft.Extensions.Logging](https://www.nuget.org/packages/Microsoft.Extensions.Logging) for all silo and client logs. You can use any logging provider compatible with `Microsoft.Extensions.Logging`. Your app code relies on [dependency injection](../../../core/extensions/dependency-injection/overview.md) to get an instance of and uses it to log messages. For more information, see [Logging in .NET](../../../core/extensions/logging.md). +Orleans uses [Microsoft.Extensions.Logging](https://www.nuget.org/packages/Microsoft.Extensions.Logging) for all silo and client logs. You can use any logging provider compatible with `Microsoft.Extensions.Logging`. Your app code relies on [dependency injection](../../../core/extensions/dependency-injection/overview.md) to get an instance of and uses it to log messages. For more information, see [Logging in .NET](../../../core/extensions/logging/overview.md). :::zone target="docs" pivot="orleans-10-0,orleans-9-0,orleans-8-0,orleans-7-0" @@ -440,7 +440,7 @@ clientBuilder.AddApplicationInsightsTelemetryConsumer(telemetryConfiguration); ## See also -- [Logging in .NET](../../../core/extensions/logging.md) +- [Logging in .NET](../../../core/extensions/logging/overview.md) - [.NET metrics](../../../core/diagnostics/metrics.md) - [Investigate performance counters (dotnet-counters)](../../../core/diagnostics/dotnet-counters.md) - [.NET distributed tracing](../../../core/diagnostics/distributed-tracing.md) diff --git a/docs/standard/runtime-libraries-overview.md b/docs/standard/runtime-libraries-overview.md index e820db6f0d3c3..5c9a054df1dd4 100644 --- a/docs/standard/runtime-libraries-overview.md +++ b/docs/standard/runtime-libraries-overview.md @@ -28,7 +28,7 @@ The following table shows some examples of package-provided libraries. | [`Microsoft.Extensions.Hosting`][host] | [Generic Host](../core/extensions/generic-host.md) | | [`Microsoft.Extensions.Http`][http] | [HTTP](../core/extensions/httpclient-factory.md) | | [`Microsoft.Extensions.Localization`][loc] | [Localization](../core/extensions/localization.md) | -| [`Microsoft.Extensions.Logging`][log] | [Logging](../core/extensions/logging.md) | +| [`Microsoft.Extensions.Logging`][log] | [Logging](../core/extensions/logging/overview.md) | [ai]: https://www.nuget.org/packages/Microsoft.Extensions.AI [configuration]: https://www.nuget.org/packages/Microsoft.Extensions.Configuration