From f5a6b5d9180aabd68deb48cfd8445dee2e07e1b1 Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Wed, 4 Feb 2026 18:28:18 -0800 Subject: [PATCH 1/6] fix up code snippets and descriptions --- .../extensions/logging/custom-provider.md | 54 ++++++++++--------- .../ColorConsoleLogger.cs | 2 + 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/docs/core/extensions/logging/custom-provider.md b/docs/core/extensions/logging/custom-provider.md index ab770f44b7be3..94f1e82d3acd5 100644 --- a/docs/core/extensions/logging/custom-provider.md +++ b/docs/core/extensions/logging/custom-provider.md @@ -1,18 +1,18 @@ --- title: Implement a custom logging provider description: Discover how to implement a custom logging provider with colorized logs, writing custom C# ILogger and ILoggerProvider implementations. -ms.date: 10/20/2025 +ms.date: 02/04/2026 ms.topic: how-to --- # Implement a custom logging provider in .NET -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. +There are many [logging providers](providers.md) available for common logging needs. But 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). +> The custom logging provider example source code is available in the [docs GitHub repo](https://github.com/dotnet/docs/tree/main/docs/core/extensions/snippets/configuration/console-custom-logging). -### Sample custom logger configuration +## Sample custom logger configuration The sample creates different color console entries per log level and event ID using the following configuration type: @@ -20,7 +20,7 @@ The sample creates different color console entries per log level and event ID us The preceding code sets the default level to `Information`, the color to `Green`, and the `EventId` is implicitly `0`. -### Create the custom logger +## Create the custom logger The `ILogger` implementation category name is typically the logging source. For example, the type where the logger is created: @@ -28,17 +28,17 @@ The `ILogger` implementation category name is typically the logging source. For The preceding code: -- Creates a logger instance per category name. +- Creates one logger instance per category name. - Checks `_getCurrentConfig().LogLevelToColorMap.ContainsKey(logLevel)` in `IsEnabled`, so each `logLevel` has a unique logger. In this implementation, each log level requires an explicit configuration entry to log. -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. +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" id="IsEnabledCheck"::: -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. +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. > [!IMPORTANT] -> The implementation checks if the `config.EventId` value is set. When `config.EventId` is not set or when it matches the exact `logEntry.EventId`, the logger logs in color. +> The implementation checks if the `config.EventId` value is set. When `config.EventId` is not set or when it matches the exact `logEntry.EventId`, the logger logs in color. ## Custom logger provider @@ -46,11 +46,11 @@ The `ILoggerProvider` object is responsible for creating logger instances. It's :::code language="csharp" source="../snippets/configuration/console-custom-logging/ColorConsoleLoggerProvider.cs"::: -In the preceding code, 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. +In the preceding code, 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="7"::: The `ColorConsoleLoggerProvider` class defines two class-scoped attributes: @@ -61,34 +61,38 @@ The configuration can be specified with any valid [configuration provider](../co :::code language="json" source="../snippets/configuration/console-custom-logging/appsettings.json"::: -This configures the log levels to the following values: +These settings configure the log levels to the following colors: -- : -- : -- : +| | | +|----------------------------------------------------------|--------------------------------------| +| | | +| | | +| | | The log level is set to , which overrides the default value set in the `ColorConsoleLoggerConfiguration` object. ## Usage and registration of the custom logger -By convention, registering services for dependency injection happens as part of the startup routine of an application. The registration occurs in the `Program` class, or could be delegated to a `Startup` class. In this example, you'll register directly from the _Program.cs_. +By convention, registering services for dependency injection happens as part of the startup routine of an application. The registration occurs in the `Program` class or could also be delegated to a `Startup` class. In this example, it's registered directly from the _Program.cs_ file. -To add the custom logging provider and corresponding logger, add an with from the : +To add the custom logging provider and corresponding logger, add an by calling a custom extension method, `AddColorConsoleLogger`, on the from the property: :::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. +By convention, extension methods on `ILoggingBuilder` are used to register the custom provider: -The configuration from the _appsettings.json_ file overrides the following values: +:::code language="csharp" source="../snippets/configuration/console-custom-logging/Extensions/ColorConsoleLoggerExtensions.cs"::: -- : -- : +The `ILoggingBuilder` creates one or more `ILogger` instances. The `ILogger` instances are used by the framework to log the information. -By convention, extension methods on `ILoggingBuilder` are used to register the custom provider: +The configuration from the _appsettings.json_ file overrides the following values: -:::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: +When you run this simple app, it renders color output to the console window similar to the following image: :::image type="content" source="media/color-console-logger.png" alt-text="Color console logger sample output"::: diff --git a/docs/core/extensions/snippets/configuration/console-custom-logging/ColorConsoleLogger.cs b/docs/core/extensions/snippets/configuration/console-custom-logging/ColorConsoleLogger.cs index a7884c99d7530..03e750e7b2652 100644 --- a/docs/core/extensions/snippets/configuration/console-custom-logging/ColorConsoleLogger.cs +++ b/docs/core/extensions/snippets/configuration/console-custom-logging/ColorConsoleLogger.cs @@ -16,10 +16,12 @@ public void Log( Exception? exception, Func formatter) { + // if (!IsEnabled(logLevel)) { return; } + // ColorConsoleLoggerConfiguration config = getCurrentConfig(); if (config.EventId == 0 || config.EventId == eventId.Id) From 78eae124a5221be6a7c0e657e1572479d2b03592 Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Wed, 4 Feb 2026 19:41:53 -0800 Subject: [PATCH 2/6] more fixes --- .../extensions/logging/custom-provider.md | 34 +++++++------------ .../ColorConsoleLogger.cs | 5 ++- .../console-custom-logging/Program.cs | 6 ++-- 3 files changed, 17 insertions(+), 28 deletions(-) diff --git a/docs/core/extensions/logging/custom-provider.md b/docs/core/extensions/logging/custom-provider.md index 94f1e82d3acd5..f3a04ee1bf533 100644 --- a/docs/core/extensions/logging/custom-provider.md +++ b/docs/core/extensions/logging/custom-provider.md @@ -14,26 +14,23 @@ There are many [logging providers](providers.md) available for common logging ne ## Sample custom logger configuration -The sample creates different color console entries per log level and event ID using the following configuration type: +The sample logger 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"::: -The preceding code sets the default level to `Information`, the color to `Green`, and the `EventId` is implicitly `0`. +The preceding code sets the default color for the `Information` level to `Green`. The `EventId` is implicitly 0. ## Create the custom logger -The `ILogger` implementation category name is typically the logging source. For example, the type where the logger is created: +The following code snippet shows the `ILogger` implementation: :::code language="csharp" source="../snippets/configuration/console-custom-logging/ColorConsoleLogger.cs"::: -The preceding code: - -- Creates one logger instance per category name. -- Checks `_getCurrentConfig().LogLevelToColorMap.ContainsKey(logLevel)` in `IsEnabled`, so each `logLevel` has a unique logger. In this implementation, each log level requires an explicit configuration entry to log. +Each logger instance is instantiated by passing a category name, which is typically the type where the logger is created. The `IsEnabled` method checks `_getCurrentConfig().LogLevelToColorMap.ContainsKey(logLevel)` to see if the requested log level is enabled (that is, in the configuration's dictionary of log levels). 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" id="IsEnabledCheck"::: +:::code language="csharp" source="../snippets/configuration/console-custom-logging/ColorConsoleLogger.cs" range="19-22"::: 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. @@ -46,13 +43,11 @@ The `ILoggerProvider` object is responsible for creating logger instances. It's :::code language="csharp" source="../snippets/configuration/console-custom-logging/ColorConsoleLoggerProvider.cs"::: -In the preceding code, 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: +In the preceding code, creates a single instance of the `ColorConsoleLogger` per category name and stores it in the [`ConcurrentDictionary`](/dotnet/api/system.collections.concurrent.concurrentdictionary-2). -:::code language="csharp" source="../snippets/configuration/console-custom-logging/ColorConsoleLoggerProvider.cs" range="6-8" highlight="7"::: +The `ColorConsoleLoggerProvider` class is decorated with two attributes: -The `ColorConsoleLoggerProvider` class defines two class-scoped attributes: +:::code language="csharp" source="../snippets/configuration/console-custom-logging/ColorConsoleLoggerProvider.cs" range="6-8"::: - : The `ColorConsoleLogger` type is _not supported_ in the `"browser"`. - : Configuration sections can define options using the `"ColorConsole"` key. @@ -69,15 +64,15 @@ These settings configure the log levels to the following colors: | | | | | | -The log level is set to , which overrides the default value set in the `ColorConsoleLoggerConfiguration` object. +The _appsettings.json_ file specifies that the color for the log level is , which overrides the default value set in the `ColorConsoleLoggerConfiguration` object. ## Usage and registration of the custom logger -By convention, registering services for dependency injection happens as part of the startup routine of an application. The registration occurs in the `Program` class or could also be delegated to a `Startup` class. In this example, it's registered directly from the _Program.cs_ file. +By convention, registering services for dependency injection happens as part of the startup routine of an application. The registration occurs in the `Program` class or in a `Startup` class. In this example, it's registered directly from the _Program.cs_ file. To add the custom logging provider and corresponding logger, add an by calling a custom extension method, `AddColorConsoleLogger`, on the from the property: -:::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="8-14"::: By convention, extension methods on `ILoggingBuilder` are used to register the custom provider: @@ -85,12 +80,7 @@ By convention, extension methods on `ILoggingBuilder` are used to register the c The `ILoggingBuilder` creates one or more `ILogger` instances. The `ILogger` instances are used by the framework to log the information. -The configuration from the _appsettings.json_ file overrides the following values: - -| | | -|------------------------------------------------------|-------------------------------------| -| | | -| | | +The instantiation code overrides the color values from the _appsettings.json_ file for and . When you run this simple app, it renders color output to the console window similar to the following image: diff --git a/docs/core/extensions/snippets/configuration/console-custom-logging/ColorConsoleLogger.cs b/docs/core/extensions/snippets/configuration/console-custom-logging/ColorConsoleLogger.cs index 03e750e7b2652..df51ad49e026d 100644 --- a/docs/core/extensions/snippets/configuration/console-custom-logging/ColorConsoleLogger.cs +++ b/docs/core/extensions/snippets/configuration/console-custom-logging/ColorConsoleLogger.cs @@ -4,7 +4,8 @@ public sealed class ColorConsoleLogger( string name, Func getCurrentConfig) : ILogger { - public IDisposable? BeginScope(TState state) where TState : notnull => default!; + public IDisposable? BeginScope(TState state) + where TState : notnull => default!; public bool IsEnabled(LogLevel logLevel) => getCurrentConfig().LogLevelToColorMap.ContainsKey(logLevel); @@ -16,12 +17,10 @@ public void Log( Exception? exception, Func formatter) { - // if (!IsEnabled(logLevel)) { return; } - // ColorConsoleLoggerConfiguration config = getCurrentConfig(); if (config.EventId == 0 || config.EventId == eventId.Id) diff --git a/docs/core/extensions/snippets/configuration/console-custom-logging/Program.cs b/docs/core/extensions/snippets/configuration/console-custom-logging/Program.cs index 6f79ee3f22a62..f0c80342715dd 100644 --- a/docs/core/extensions/snippets/configuration/console-custom-logging/Program.cs +++ b/docs/core/extensions/snippets/configuration/console-custom-logging/Program.cs @@ -7,15 +7,15 @@ builder.Logging.ClearProviders(); builder.Logging.AddColorConsoleLogger(configuration => { - // Replace warning value from appsettings.json of "Cyan" + // Replace warning value from appsettings.json of "Cyan". configuration.LogLevelToColorMap[LogLevel.Warning] = ConsoleColor.DarkCyan; - // Replace warning value from appsettings.json of "Red" + // Replace warning value from appsettings.json of "Red". configuration.LogLevelToColorMap[LogLevel.Error] = ConsoleColor.DarkRed; }); using IHost host = builder.Build(); -var logger = host.Services.GetRequiredService>(); +ILogger logger = host.Services.GetRequiredService>(); logger.LogDebug(1, "Does this line get hit?"); // Not logged logger.LogInformation(3, "Nothing to see here."); // Logs in ConsoleColor.DarkGreen From 8605f764bb076eed0e4150e25cded16dfc5cdee4 Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Wed, 4 Feb 2026 19:42:21 -0800 Subject: [PATCH 3/6] and update code files --- .../configuration/console-custom-logging/Program.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/core/extensions/snippets/configuration/console-custom-logging/Program.cs b/docs/core/extensions/snippets/configuration/console-custom-logging/Program.cs index f0c80342715dd..e2d74fa7eb2a8 100644 --- a/docs/core/extensions/snippets/configuration/console-custom-logging/Program.cs +++ b/docs/core/extensions/snippets/configuration/console-custom-logging/Program.cs @@ -7,10 +7,12 @@ builder.Logging.ClearProviders(); builder.Logging.AddColorConsoleLogger(configuration => { - // Replace warning value from appsettings.json of "Cyan". - configuration.LogLevelToColorMap[LogLevel.Warning] = ConsoleColor.DarkCyan; - // Replace warning value from appsettings.json of "Red". - configuration.LogLevelToColorMap[LogLevel.Error] = ConsoleColor.DarkRed; + // Replace value of "Cyan" from appsettings.json. + configuration.LogLevelToColorMap[LogLevel.Warning] + = ConsoleColor.DarkCyan; + // Replace value of "Red" from appsettings.json. + configuration.LogLevelToColorMap[LogLevel.Error] + = ConsoleColor.DarkRed; }); using IHost host = builder.Build(); From a74f1d5f798951c1bfb93c44345c8af73e05ffb6 Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Wed, 4 Feb 2026 19:51:25 -0800 Subject: [PATCH 4/6] fix line numbers --- docs/core/extensions/logging/custom-provider.md | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/docs/core/extensions/logging/custom-provider.md b/docs/core/extensions/logging/custom-provider.md index f3a04ee1bf533..ac93b9ad0c927 100644 --- a/docs/core/extensions/logging/custom-provider.md +++ b/docs/core/extensions/logging/custom-provider.md @@ -30,9 +30,9 @@ Each logger instance is instantiated by passing a category name, which is typica 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="19-22"::: +:::code language="csharp" source="../snippets/configuration/console-custom-logging/ColorConsoleLogger.cs" range="20-23"::: -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. +The logger is instantiated with the `name` and a `Func` that returns the current configuration. > [!IMPORTANT] > The implementation checks if the `config.EventId` value is set. When `config.EventId` is not set or when it matches the exact `logEntry.EventId`, the logger logs in color. @@ -56,19 +56,11 @@ The configuration can be specified with any valid [configuration provider](../co :::code language="json" source="../snippets/configuration/console-custom-logging/appsettings.json"::: -These settings configure the log levels to the following colors: - -| | | -|----------------------------------------------------------|--------------------------------------| -| | | -| | | -| | | - The _appsettings.json_ file specifies that the color for the log level is , which overrides the default value set in the `ColorConsoleLoggerConfiguration` object. ## Usage and registration of the custom logger -By convention, registering services for dependency injection happens as part of the startup routine of an application. The registration occurs in the `Program` class or in a `Startup` class. In this example, it's registered directly from the _Program.cs_ file. +By convention, services are registered for dependency injection as part of the startup routine of an application. In this example, the logging service is registered directly from the _Program.cs_ file. To add the custom logging provider and corresponding logger, add an by calling a custom extension method, `AddColorConsoleLogger`, on the from the property: From 6a1c257ecdb1b74a061addb4369d622348614900 Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Wed, 4 Feb 2026 19:55:56 -0800 Subject: [PATCH 5/6] ccr feedback --- docs/core/extensions/logging/custom-provider.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/core/extensions/logging/custom-provider.md b/docs/core/extensions/logging/custom-provider.md index ac93b9ad0c927..67088e7e00416 100644 --- a/docs/core/extensions/logging/custom-provider.md +++ b/docs/core/extensions/logging/custom-provider.md @@ -26,7 +26,7 @@ The following code snippet shows the `ILogger` implementation: :::code language="csharp" source="../snippets/configuration/console-custom-logging/ColorConsoleLogger.cs"::: -Each logger instance is instantiated by passing a category name, which is typically the type where the logger is created. The `IsEnabled` method checks `_getCurrentConfig().LogLevelToColorMap.ContainsKey(logLevel)` to see if the requested log level is enabled (that is, in the configuration's dictionary of log levels). +Each logger instance is instantiated by passing a category name, which is typically the type where the logger is created. The `IsEnabled` method checks `getCurrentConfig().LogLevelToColorMap.ContainsKey(logLevel)` to see if the requested log level is enabled (that is, in the configuration's dictionary of log levels). 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. @@ -43,7 +43,7 @@ The `ILoggerProvider` object is responsible for creating logger instances. It's :::code language="csharp" source="../snippets/configuration/console-custom-logging/ColorConsoleLoggerProvider.cs"::: -In the preceding code, creates a single instance of the `ColorConsoleLogger` per category name and stores it in the [`ConcurrentDictionary`](/dotnet/api/system.collections.concurrent.concurrentdictionary-2). +In the preceding code, creates a single instance of the `ColorConsoleLogger` per category name and stores it in the [`ConcurrentDictionary`](/dotnet/api/system.collections.concurrent.concurrentdictionary-2). The `ColorConsoleLoggerProvider` class is decorated with two attributes: From a3195845c4811363245cbfca65c6f1ac57e4cda5 Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Thu, 5 Feb 2026 08:18:03 -0800 Subject: [PATCH 6/6] Update docs/core/extensions/logging/custom-provider.md --- docs/core/extensions/logging/custom-provider.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/extensions/logging/custom-provider.md b/docs/core/extensions/logging/custom-provider.md index 67088e7e00416..0aeb14fbf06fb 100644 --- a/docs/core/extensions/logging/custom-provider.md +++ b/docs/core/extensions/logging/custom-provider.md @@ -64,7 +64,7 @@ By convention, services are registered for dependency injection as part of the s To add the custom logging provider and corresponding logger, add an by calling a custom extension method, `AddColorConsoleLogger`, on the from the property: -:::code language="csharp" source="../snippets/configuration/console-custom-logging/Program.cs" highlight="8-14"::: +:::code language="csharp" source="../snippets/configuration/console-custom-logging/Program.cs" highlight="8-16"::: By convention, extension methods on `ILoggingBuilder` are used to register the custom provider: