控制台日志格式设置 您所在的位置:网站首页 vs控制台程序怎么改颜色 控制台日志格式设置

控制台日志格式设置

#控制台日志格式设置| 来源: 网络整理| 查看: 265

控制台日志格式设置 项目 06/23/2023

在 .NET 5 中,已向 Microsoft.Extensions.Logging.Console 命名空间中的控制台日志添加了对自定义格式设置的支持。 有三种预定义的格式设置选项可供选择:Simple、Systemd 和 Json。

重要

以前,ConsoleLoggerFormat 枚举允许选择所需的日志格式,可以是人工可读取的 (Default),也可以是单行(也称为 Systemd)。 不过,这些都是不能进行自定义的,现已弃用。

本文介绍了控制台日志格式化程序。 示例源代码演示了如何执行以下操作:

注册新的格式化程序 选择要使用的已注册格式化程序 通过代码或配置 实现自定义格式化程序 通过 IOptionsMonitor 更新配置 启用自定义颜色格式设置

提示

所有日志记录示例源代码都可以在示例浏览器中下载。 有关详细信息,请参阅浏览代码示例:.NET 中的日志记录。

注册格式化程序

Console 日志记录提供程序有几个预定义的格式化程序,并公开了可供你编写自己的自定义格式化程序的功能。 要注册任何可用的格式化程序,请使用相应的 Add{Type}Console 扩展方法:

可用类型 注册类型的方法 ConsoleFormatterNames.Json ConsoleLoggerExtensions.AddJsonConsole ConsoleFormatterNames.Simple ConsoleLoggerExtensions.AddSimpleConsole ConsoleFormatterNames.Systemd ConsoleLoggerExtensions.AddSystemdConsole 简单

要使用 Simple 控制台格式化程序,请将其注册到 AddSimpleConsole:

using Microsoft.Extensions.Logging; using ILoggerFactory loggerFactory = LoggerFactory.Create(builder => builder.AddSimpleConsole(options => { options.IncludeScopes = true; options.SingleLine = true; options.TimestampFormat = "HH:mm:ss "; })); ILogger logger = loggerFactory.CreateLogger(); using (logger.BeginScope("[scope is enabled]")) { logger.LogInformation("Hello World!"); logger.LogInformation("Logs contain timestamp and log level."); logger.LogInformation("Each log message is fit in a single line."); }

在前面的示例源代码中,已经注册了 ConsoleFormatterNames.Simple 格式化程序。 它不仅为日志提供了在每条日志消息中包装信息(如时间和日志级别)的功能,而且还允许 ANSI 颜色嵌入和消息缩进。

Systemd

ConsoleFormatterNames.Systemd 控制台记录器:

使用“Syslog”日志级别格式和严重性 不为消息设置颜色格式 始终将消息记录在单行中

这对于容器来说通常很有用,因为容器经常使用 Systemd 控制台日志记录。 在 .NET 5 中,Simple 控制台记录器还可以实现以单行方式进行记录的紧凑版本,并且还允许禁用颜色,如前面的示例所示。

using Microsoft.Extensions.Logging; using ILoggerFactory loggerFactory = LoggerFactory.Create(builder => builder.AddSystemdConsole(options => { options.IncludeScopes = true; options.TimestampFormat = "HH:mm:ss "; })); ILogger logger = loggerFactory.CreateLogger(); using (logger.BeginScope("[scope is enabled]")) { logger.LogInformation("Hello World!"); logger.LogInformation("Logs contain timestamp and log level."); logger.LogInformation("Systemd console logs never provide color options."); logger.LogInformation("Systemd console logs always appear in a single line."); } Json

要以 JSON 格式编写日志,需要使用 Json 控制台格式化程序。 示例源代码展示了 ASP.NET Core 应用如何注册格式化程序。 使用 webapp 模板,用 dotnet new 命令创建一个新的 ASP.NET Core 应用:

dotnet new webapp -o Console.ExampleFormatters.Json

运行此应用时,使用模板代码会获得以下默认日志格式:

info: Console.ExampleFormatters.Json.Startup[0] Hello .NET friends! info: Microsoft.Hosting.Lifetime[14] Now listening on: https://localhost:5001 info: Microsoft.Hosting.Lifetime[14] Now listening on: http://localhost:5000 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: .\snippets\logging\console-formatter-json

默认情况下,默认配置中会选择 Simple 控制台日志格式化程序。 可以通过在 Program.cs 中调用 AddJsonConsole 来更改此设置:

using System.Text.Json; HostApplicationBuilder builder = Host.CreateApplicationBuilder(args); builder.Logging.AddJsonConsole(options => { options.IncludeScopes = false; options.TimestampFormat = "HH:mm:ss "; options.JsonWriterOptions = new JsonWriterOptions { Indented = true }; }); using IHost host = builder.Build(); var logger = host.Services .GetRequiredService() .CreateLogger(); logger.LogInformation("Hello .NET friends!"); await host.RunAsync();

或者,也可以使用日志记录配置来配置此设置,例如位于 appsettings.json 文件中的配置:

{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" }, "Console": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" }, "FormatterName": "json", "FormatterOptions": { "SingleLine": true, "IncludeScopes": true, "TimestampFormat": "HH:mm:ss ", "UseUtcTimestamp": true, "JsonWriterOptions": { "Indented": true } } } }, "AllowedHosts": "*" }

再次运行此应用,进行上述更改后,现在日志消息的格式为 JSON:

{ "Timestamp": "02:28:19 ", "EventId": 0, "LogLevel": "Information", "Category": "Console.ExampleFormatters.Json.Startup", "Message": "Hello .NET friends!", "State": { "Message": "Hello .NET friends!", "{OriginalFormat}": "Hello .NET friends!" } } { "Timestamp": "02:28:21 ", "EventId": 14, "LogLevel": "Information", "Category": "Microsoft.Hosting.Lifetime", "Message": "Now listening on: https://localhost:5001", "State": { "Message": "Now listening on: https://localhost:5001", "address": "https://localhost:5001", "{OriginalFormat}": "Now listening on: {address}" } } { "Timestamp": "02:28:21 ", "EventId": 14, "LogLevel": "Information", "Category": "Microsoft.Hosting.Lifetime", "Message": "Now listening on: http://localhost:5000", "State": { "Message": "Now listening on: http://localhost:5000", "address": "http://localhost:5000", "{OriginalFormat}": "Now listening on: {address}" } } { "Timestamp": "02:28:21 ", "EventId": 0, "LogLevel": "Information", "Category": "Microsoft.Hosting.Lifetime", "Message": "Application started. Press Ctrl\u002BC to shut down.", "State": { "Message": "Application started. Press Ctrl\u002BC to shut down.", "{OriginalFormat}": "Application started. Press Ctrl\u002BC to shut down." } } { "Timestamp": "02:28:21 ", "EventId": 0, "LogLevel": "Information", "Category": "Microsoft.Hosting.Lifetime", "Message": "Hosting environment: Development", "State": { "Message": "Hosting environment: Development", "envName": "Development", "{OriginalFormat}": "Hosting environment: {envName}" } } { "Timestamp": "02:28:21 ", "EventId": 0, "LogLevel": "Information", "Category": "Microsoft.Hosting.Lifetime", "Message": "Content root path: .\\snippets\\logging\\console-formatter-json", "State": { "Message": "Content root path: .\\snippets\\logging\\console-formatter-json", "contentRoot": ".\\snippets\\logging\\console-formatter-json", "{OriginalFormat}": "Content root path: {contentRoot}" } }

提示

默认情况下,Json 控制台格式化程序将每条消息记录在单行中。 为了在配置格式化程序时使其更具可读性,请将 JsonWriterOptions.Indented 设置为 true。

注意

使用 JSON 控制台格式化程序时,不要传入已经序列化为 JSON 的日志消息。 日志记录基础结构本身已管理日志消息的序列化,因此,如果你传入已经序列化的日志消息,它将双重序列化,从而导致输出格式不正确。

通过配置设置格式化程序

前面的示例展示了如何以编程方式注册格式化程序。 另外,也可以通过配置来完成。 考虑到之前的 Web 应用示例源代码,如果更新 appsettings.json 文件,而不是调用 Program.cs 文件中的 ConfigureLogging,可以得到相同的结果。 更新后的 appsettings.json 文件将对格式化程序进行如下配置:

{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" }, "Console": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" }, "FormatterName": "json", "FormatterOptions": { "SingleLine": true, "IncludeScopes": true, "TimestampFormat": "HH:mm:ss ", "UseUtcTimestamp": true, "JsonWriterOptions": { "Indented": true } } } }, "AllowedHosts": "*" }

需要设置的两个键值为 "FormatterName" 和 "FormatterOptions"。 如果已经注册了值设置为 "FormatterName" 的格式化程序,则会选择此格式化程序,并且只要在 "FormatterOptions" 节点中将其属性作为键提供,就可以配置属性。 预定义的格式化程序名称保留在 ConsoleFormatterNames 下:

ConsoleFormatterNames.Json ConsoleFormatterNames.Simple ConsoleFormatterNames.Systemd 实现自定义格式化程序

要实现自定义格式化程序,需要执行以下操作:

创建一个 ConsoleFormatter 的子类,这代表你的自定义格式化程序 注册以下自定义格式化程序 ConsoleLoggerExtensions.AddConsole ConsoleLoggerExtensions.AddConsoleFormatter(ILoggingBuilder, Action)

创建一个扩展方法来为你进行处理:

using Microsoft.Extensions.Logging; namespace Console.ExampleFormatters.Custom; public static class ConsoleLoggerExtensions { public static ILoggingBuilder AddCustomFormatter( this ILoggingBuilder builder, Action configure) => builder.AddConsole(options => options.FormatterName = "customName") .AddConsoleFormatter(configure); }

CustomOptions 的定义如下:

using Microsoft.Extensions.Logging.Console; namespace Console.ExampleFormatters.Custom; public sealed class CustomOptions : ConsoleFormatterOptions { public string? CustomPrefix { get; set; } }

在前面的代码中,选项是 ConsoleFormatterOptions 的子类。

AddConsoleFormatter API 会执行以下操作:

注册 ConsoleFormatter 的子类 处理配置: 基于选项模式和 IOptionsMonitor 接口,使用更改令牌同步更新 using Console.ExampleFormatters.Custom; using Microsoft.Extensions.Logging; using ILoggerFactory loggerFactory = LoggerFactory.Create(builder => builder.AddCustomFormatter(options => options.CustomPrefix = " ~~~~~ ")); ILogger logger = loggerFactory.CreateLogger(); using (logger.BeginScope("TODO: Add logic to enable scopes")) { logger.LogInformation("Hello World!"); logger.LogInformation("TODO: Add logic to enable timestamp and log level info."); }

定义 ConsoleFormatter 的 CustomFormatter 子类:

using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Console; using Microsoft.Extensions.Options; namespace Console.ExampleFormatters.Custom; public sealed class CustomFormatter : ConsoleFormatter, IDisposable { private readonly IDisposable? _optionsReloadToken; private CustomOptions _formatterOptions; public CustomFormatter(IOptionsMonitor options) // Case insensitive : base("customName") => (_optionsReloadToken, _formatterOptions) = (options.OnChange(ReloadLoggerOptions), options.CurrentValue); private void ReloadLoggerOptions(CustomOptions options) => _formatterOptions = options; public override void Write( in LogEntry logEntry, IExternalScopeProvider? scopeProvider, TextWriter textWriter) { string? message = logEntry.Formatter?.Invoke( logEntry.State, logEntry.Exception); if (message is null) { return; } CustomLogicGoesHere(textWriter); textWriter.WriteLine(message); } private void CustomLogicGoesHere(TextWriter textWriter) { textWriter.Write(_formatterOptions.CustomPrefix); } public void Dispose() => _optionsReloadToken?.Dispose(); }

前面的 CustomFormatter.Write API 指明了每个日志消息包装的文本类型。 一个标准的 ConsoleFormatter 应至少能包装日志的范围、时间戳和严重性级别。 此外,你还可以对日志消息中的 ANSI 颜色进行编码,并提供所需的缩进。 CustomFormatter.Write 的实现缺少这些功能。

有关进一步自定义格式设置的灵感,请参阅 Microsoft.Extensions.Logging.Console 命名空间中的现有实现:

SimpleConsoleFormatter。 SystemdConsoleFormatter JsonConsoleFormatter 自定义配置选项

若要进一步自定义日志记录可扩展性,可从任何配置提供程序配置派生的 ConsoleFormatterOptions 类。 例如,可以使用 JSON 配置提供程序来定义自定义选项。 首先定义 ConsoleFormatterOptions 子类。

using Microsoft.Extensions.Logging.Console; namespace Console.ExampleFormatters.CustomWithConfig; public sealed class CustomWrappingConsoleFormatterOptions : ConsoleFormatterOptions { public string? CustomPrefix { get; set; } public string? CustomSuffix { get; set; } }

前述控制台格式化程序选项类定义了两个自定义属性,表示前缀和后缀。 接下来,定义将配置控制台格式化程序选项的 appsettings.json 文件。

{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" }, "Console": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" }, "FormatterName": "CustomTimePrefixingFormatter", "FormatterOptions": { "CustomPrefix": "|--|", "SingleLine": true, "IncludeScopes": true, "TimestampFormat": "HH:mm:ss.ffff ", "UseUtcTimestamp": true, "JsonWriterOptions": { "Indented": true } } } }, "AllowedHosts": "*" }

在前述 JSON 配置文件中:

"Logging" 节点定义 "Console"。 "Console" 节点指定 "CustomTimePrefixingFormatter" 的 "FormatterName",它映射到自定义格式化程序。 "FormatterOptions" 节点定义 "CustomPrefix" 和 "CustomSuffix",以及其他一些派生的选项。

提示

$.Logging.Console.FormatterOptions JSON 路径已保留,使用 AddConsoleFormatter 扩展方法添加时,它将映射到自定义 ConsoleFormatterOptions。 除了可用属性之外,这还能定义自定义属性。

假设为以下 CustomDatePrefixingFormatter:

using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Console; using Microsoft.Extensions.Options; namespace Console.ExampleFormatters.CustomWithConfig; public sealed class CustomTimePrefixingFormatter : ConsoleFormatter, IDisposable { private readonly IDisposable? _optionsReloadToken; private CustomWrappingConsoleFormatterOptions _formatterOptions; public CustomTimePrefixingFormatter( IOptionsMonitor options) // Case insensitive : base(nameof(CustomTimePrefixingFormatter)) { _optionsReloadToken = options.OnChange(ReloadLoggerOptions); _formatterOptions = options.CurrentValue; } private void ReloadLoggerOptions(CustomWrappingConsoleFormatterOptions options) => _formatterOptions = options; public override void Write( in LogEntry logEntry, IExternalScopeProvider? scopeProvider, TextWriter textWriter) { string message = logEntry.Formatter( logEntry.State, logEntry.Exception); if (message == null) { return; } WritePrefix(textWriter); textWriter.Write(message); WriteSuffix(textWriter); } private void WritePrefix(TextWriter textWriter) { DateTime now = _formatterOptions.UseUtcTimestamp ? DateTime.UtcNow : DateTime.Now; textWriter.Write($""" {_formatterOptions.CustomPrefix} {now.ToString(_formatterOptions.TimestampFormat)} """); } private void WriteSuffix(TextWriter textWriter) => textWriter.WriteLine($" {_formatterOptions.CustomSuffix}"); public void Dispose() => _optionsReloadToken?.Dispose(); }

在前述格式化程序实现中:

监视 CustomWrappingConsoleFormatterOptions 是否有所更改,并相应地进行更新。 写入的消息将用配置的前缀和后缀进行包装。 使用配置的 ConsoleFormatterOptions.UseUtcTimestamp 和 ConsoleFormatterOptions.TimestampFormat 值在前缀后面、消息之前添加时间戳。

若要在自定义格式化程序实现中使用自定义配置选项,请在调用 ConfigureLogging(IHostBuilder, Action) 时添加。

using Console.ExampleFormatters.CustomWithConfig; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; HostApplicationBuilder builder = Host.CreateApplicationBuilder(args); builder.Logging.AddConsole() .AddConsoleFormatter< CustomTimePrefixingFormatter, CustomWrappingConsoleFormatterOptions>(); using IHost host = builder.Build(); ILoggerFactory loggerFactory = host.Services.GetRequiredService(); ILogger logger = loggerFactory.CreateLogger(); using (logger.BeginScope("Logging scope")) { logger.LogInformation("Hello World!"); logger.LogInformation("The .NET developer community happily welcomes you."); }

以下控制台输出类似于你使用此 CustomTimePrefixingFormatter 时可能想要看到的内容。

|--| |--| 实现自定义颜色格式设置

为了在自定义日志记录格式化程序中正确地启用颜色功能,可以扩展 SimpleConsoleFormatterOptions,因为它具有 SimpleConsoleFormatterOptions.ColorBehavior 属性,这个属性对于在日志中启用颜色非常有用。

创建一个从 SimpleConsoleFormatterOptions 派生的 CustomColorOptions:

using Microsoft.Extensions.Logging.Console; namespace Console.ExampleFormatters.Custom; public class CustomColorOptions : SimpleConsoleFormatterOptions { public string? CustomPrefix { get; set; } }

接下来,在 TextWriterExtensions 类中编写一些扩展方法,以便在经过格式设置的日志消息中方便地嵌入 ANSI 编码的颜色:

namespace Console.ExampleFormatters.Custom; public static class TextWriterExtensions { const string DefaultForegroundColor = "\x1B[39m\x1B[22m"; const string DefaultBackgroundColor = "\x1B[49m"; public static void WriteWithColor( this TextWriter textWriter, string message, ConsoleColor? background, ConsoleColor? foreground) { // Order: // 1. background color // 2. foreground color // 3. message // 4. reset foreground color // 5. reset background color var backgroundColor = background.HasValue ? GetBackgroundColorEscapeCode(background.Value) : null; var foregroundColor = foreground.HasValue ? GetForegroundColorEscapeCode(foreground.Value) : null; if (backgroundColor != null) { textWriter.Write(backgroundColor); } if (foregroundColor != null) { textWriter.Write(foregroundColor); } textWriter.WriteLine(message); if (foregroundColor != null) { textWriter.Write(DefaultForegroundColor); } if (backgroundColor != null) { textWriter.Write(DefaultBackgroundColor); } } static string GetForegroundColorEscapeCode(ConsoleColor color) => color switch { ConsoleColor.Black => "\x1B[30m", ConsoleColor.DarkRed => "\x1B[31m", ConsoleColor.DarkGreen => "\x1B[32m", ConsoleColor.DarkYellow => "\x1B[33m", ConsoleColor.DarkBlue => "\x1B[34m", ConsoleColor.DarkMagenta => "\x1B[35m", ConsoleColor.DarkCyan => "\x1B[36m", ConsoleColor.Gray => "\x1B[37m", ConsoleColor.Red => "\x1B[1m\x1B[31m", ConsoleColor.Green => "\x1B[1m\x1B[32m", ConsoleColor.Yellow => "\x1B[1m\x1B[33m", ConsoleColor.Blue => "\x1B[1m\x1B[34m", ConsoleColor.Magenta => "\x1B[1m\x1B[35m", ConsoleColor.Cyan => "\x1B[1m\x1B[36m", ConsoleColor.White => "\x1B[1m\x1B[37m", _ => DefaultForegroundColor }; static string GetBackgroundColorEscapeCode(ConsoleColor color) => color switch { ConsoleColor.Black => "\x1B[40m", ConsoleColor.DarkRed => "\x1B[41m", ConsoleColor.DarkGreen => "\x1B[42m", ConsoleColor.DarkYellow => "\x1B[43m", ConsoleColor.DarkBlue => "\x1B[44m", ConsoleColor.DarkMagenta => "\x1B[45m", ConsoleColor.DarkCyan => "\x1B[46m", ConsoleColor.Gray => "\x1B[47m", _ => DefaultBackgroundColor }; }

可以定义一个处理应用自定义颜色的自定义颜色格式化程序,如下所示:

using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Console; using Microsoft.Extensions.Options; namespace Console.ExampleFormatters.Custom; public sealed class CustomColorFormatter : ConsoleFormatter, IDisposable { private readonly IDisposable? _optionsReloadToken; private CustomColorOptions _formatterOptions; private bool ConsoleColorFormattingEnabled => _formatterOptions.ColorBehavior == LoggerColorBehavior.Enabled || _formatterOptions.ColorBehavior == LoggerColorBehavior.Default && System.Console.IsOutputRedirected == false; public CustomColorFormatter(IOptionsMonitor options) // Case insensitive : base("customName") => (_optionsReloadToken, _formatterOptions) = (options.OnChange(ReloadLoggerOptions), options.CurrentValue); private void ReloadLoggerOptions(CustomColorOptions options) => _formatterOptions = options; public override void Write( in LogEntry logEntry, IExternalScopeProvider? scopeProvider, TextWriter textWriter) { if (logEntry.Exception is null) { return; } string? message = logEntry.Formatter?.Invoke( logEntry.State, logEntry.Exception); if (message is null) { return; } CustomLogicGoesHere(textWriter); textWriter.WriteLine(message); } private void CustomLogicGoesHere(TextWriter textWriter) { if (ConsoleColorFormattingEnabled) { textWriter.WriteWithColor( _formatterOptions.CustomPrefix ?? string.Empty, ConsoleColor.Black, ConsoleColor.Green); } else { textWriter.Write(_formatterOptions.CustomPrefix); } } public void Dispose() => _optionsReloadToken?.Dispose(); }

当你运行应用程序时,日志会在 FormatterOptions.ColorBehavior 为 Enabled 时用绿色显示 CustomPrefix 消息。

注意

当 LoggerColorBehavior 为 Disabled 时,日志消息不会解释日志消息中嵌入的 ANSI 颜色代码。 相反,它们会输出原始消息。 例如,请考虑如下事项:

logger.LogInformation("Random log \x1B[42mwith green background\x1B[49m message");

这会输出逐字字符串,且不会着色。

Random log \x1B[42mwith green background\x1B[49m message 另请参阅 .NET 中的日志记录 在 .NET 中实现自定义日志记录提供程序 .NET 中的高性能日志记录


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有