当前位置: 首页 > news >正文

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录

ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。

ASP.NET Core 中的日志记录

.NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程序将日志写入不同的目标。 基本日志记录提供程序是内置的,并且还可以使用许多第三方提供程序。

文章目录

    • ASP.NET Core 中的日志记录
      • 配置依赖于 ILogger 的服务
      • 内置日志记录提供程序
        • 控制台
        • 调试
        • 事件来源
        • 自定义日志记录提供程序
          • 1. 创建自定义记录器
          • 2. 自定义记录器提供程序
          • 3. 服务实例注册及注入
    • 第三方日志记录提供程序
      • Log4Net日志
        • 注册及配置
        • 日志项配置
      • Serilog日志
        • JSON格式配置
        • 编程Code方式配置
        • LoggerConfiguration配置结构
          • 1. Sinks接收器
          • 2. MinimumLevel最小记录级别
          • 3. Enrichers丰富器
          • 4. Filters过滤器
          • 5. WriteTo输出
          • 6. Property附加属性

配置依赖于 ILogger 的服务

若要配置依赖于 ILogger的服务,请使用构造函数注入或提供工厂方法。 仅当没有其他选项时,才建议使用工厂方法方法。 例如,假设某个服务需要由 DI 提供的 ILogger 实例:

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);builder.Services.AddSingleton<IExampleService>(container => new DefaultExampleService{Logger = container.GetRequiredService<ILogger<IExampleService>>()});

内置日志记录提供程序

Microsoft扩展包括以下日志记录提供程序作为运行时库的一部分:

  • 控制台
  • 调试
  • EventSource
  • 事件日志

日志记录提供程序保留日志,Console 提供程序除外,该提供程序仅将日志显示为标准输出。 例如,Azure Application Insights 提供程序将日志存储在 Azure Application Insights 中。 可以启用多个提供程序。

appsettings.config配置Logging节点,进行指定类跟踪事件

"Logging": {// 所有提供者,LogLevel适用于所有启用的提供者"LogLevel": {"Default": "Information",// 常规ASP.NET Core诊断"Microsoft.AspNetCore": "Warning",//"Microsoft": "Warning","Microsoft.Hosting.Lifetime": "Information",// EFCore Sql执行跟踪"Microsoft.EntityFrameworkCore.Database.Command": "Information"},// 调试提供者"Debug": {"LogLevel": {"Default": "Information", // Overrides preceding LogLevel:Default setting."Microsoft.Hosting": "Trace" // Debug:Microsoft.Hosting category.}},// 事件来源提供者"EventSource": {"LogLevel": {"Default": "Warning" // All categories of EventSource provider.}}
}
控制台

Console 提供程序将输出记录到控制台。 如需详细了解如何在开发环境中查看 Console 日志,请参阅记录来自 dotnet run 和 Visual Studio 的输出。

// 从 builder 中删除所有记录器提供程序
builder.Logging.ClearProviders();// 控制台输出
builder.Logging.AddConsole();
调试

Debug 提供程序使用 System.Diagnostics.Debug 类写入日志输出。 对 System.Diagnostics.Debug.WriteLine 的调用写入到 Debug 提供程序。

// 调试输出
builder.Logging.AddDebug();
事件来源

EventSource 提供程序写入名称为 Microsoft.Extensions.Logging 的跨平台事件源。 在 Windows 上,提供程序使用的是 ETW。

// 事件来源输出
builder.Logging.AddEventSourceLogger();

日志记录不仅对于我们开发的应用,还是对于ASP.NET Core框架功能都是一项非常重要的功能特性。我们知道ASP.NET Core使用的是一个极具扩展性的日志系统,该系统由Logger、LoggerFactory和LoggerProvider这三个核心对象组成。我们可以通过简单的配置实现对LoggerFactory的定制,以及对LoggerProvider添加。

自定义日志记录提供程序

有许多 日志记录提供程序 可用于常见日志记录需求。 当某个可用提供程序不符合应用程序需求时,可能需要实现自定义 ILoggerProvider。 本节将实现一个自定义日志提供器,以便在控制台中对日志进行着色。

实现接口结构顺序
ILogger -> ILoggerProvider -> ILoggingBuilder(LoggerFactory)

1. 创建自定义记录器

ILogger接口
泛型接口用于记录从指定的 TCategoryName 类型名称派生类别名称的位置。

using Microsoft.Extensions.Logging;namespace ContosoUniversity.Extensions.Logger;
// 自定义记录器配置
public sealed class ColorConsoleLoggerConfiguration
{// 事件IDpublic int EventId { get; set; }// 日志字典:包括日志级别与内容描述呈现颜色风格等public Dictionary<LogLevel, ConsoleColor> LogLevelToColorMap { get; set; } = new(){[LogLevel.Information] = ConsoleColor.Green,};
}// ILogger 实现类别名称通常是日志记录源。例如,创建记录器的类型:
public sealed class ColorConsoleLogger(string name,Func<ColorConsoleLoggerConfiguration> getCurrentConfig) : ILogger
{public IDisposable? BeginScope<TState>(TState state) where TState : notnull => default!;// 检查 _getCurrentConfig().LogLevelToColorMap.ContainsKey(logLevel),因此每个 logLevel 都有一个唯一的记录器。// 在此实现中,每个日志级别都需要显式配置条目才能记录public bool IsEnabled(LogLevel logLevel) =>getCurrentConfig().LogLevelToColorMap.ContainsKey(logLevel);/* 实现[写入日志项]Log方法* LogLevel: 日志级别* EventId: 事件ID* TState: 要写入的项或对象* Exception?: 与此项相关的异常* Func<TState, Exception?, string>: 函数体,用于创建state和exception的String消息*/    public void Log<TState>(LogLevel logLevel, EventId eventId,TState state, Exception? exception, Func<TState, Exception?, string> formatter){if (!IsEnabled(logLevel)){return;}ColorConsoleLoggerConfiguration config = getCurrentConfig();if (config.EventId == 0 || config.EventId == eventId.Id){ConsoleColor originalColor = Console.ForegroundColor;Console.ForegroundColor = config.LogLevelToColorMap[logLevel];Console.Write($"{logLevel.ToString().ToLower()[..4]}: ");Console.ForegroundColor = originalColor;Console.WriteLine($"{name}[{eventId.Id}]");if (config.LogLevelToColorMap[logLevel] != ConsoleColor.DarkGreen)Console.ForegroundColor = config.LogLevelToColorMap[logLevel];Console.Write($"      {formatter(state, exception)}");Console.ForegroundColor = originalColor;Console.WriteLine();}}
}

前面的代码:

  • 为每个类别名称创建一个记录器实例。
  • IsEnabled 中检查 _getCurrentConfig().LogLevelToColorMap.ContainsKey(logLevel),因此每个 logLevel 都有一个唯一的记录器。 在此实现中,每个日志级别都需要显式配置条目才能记录。

最好在 ILogger.Log 的实现中调用 ILogger.IsEnabled,因为 Log 可以被任何使用者调用,无法保证它以前已被检查过。 在大多数实现中,IsEnabled 方法应该非常快。

2. 自定义记录器提供程序

ILoggerProvider 接口
负责创建记录器实例。 不需要为每个类别创建记录器实例,但对于某些记录器(例如 NLog 或 log4net)来说,这很有意义。 此策略允许你为每个类别选择不同的日志记录输出目标,如以下示例所示:

using Microsoft.Extensions.Options;
using System.Collections.Concurrent;
using System.Runtime.Versioning;namespace ContosoUniversity.Extensions.Logger;[UnsupportedOSPlatform("browser")]  //定义类范围属性,"browser" 中不支持ColorConsoleLogger类型
[ProviderAlias("ColorConsole")]     //在提供程序上定义别名,控制ColorConsoleLogger的配置
public sealed class ColorConsoleLoggerProvider : ILoggerProvider
{private readonly IDisposable? _onChangeToken;private ColorConsoleLoggerConfiguration _currentConfig;// 可多线程访问的键/值对的线程安全集合<日志类别名称, 日志实例ILogger>private readonly ConcurrentDictionary<string, ColorConsoleLogger> _loggers =new(StringComparer.OrdinalIgnoreCase);//通过IOptionsMonitor<TOptions>接口来更新对基础ColorConsoleLoggerConfiguration对象的更改public ColorConsoleLoggerProvider(IOptionsMonitor<ColorConsoleLoggerConfiguration> config){_currentConfig = config.CurrentValue;_onChangeToken = config.OnChange(updatedConfig => _currentConfig = updatedConfig);}// 为每个类别名称创建一个ColorConsoleLogger实例,并将其存储在 ConcurrentDictionary<TKey,TValue>中public ILogger CreateLogger(string categoryName) =>_loggers.GetOrAdd(categoryName, name => new ColorConsoleLogger(name, GetCurrentConfig));private ColorConsoleLoggerConfiguration GetCurrentConfig() => _currentConfig;public void Dispose(){_loggers.Clear();_onChangeToken?.Dispose();}
}

ColorConsoleLoggerProvider 类定义两个类范围属性:

  • UnsupportedOSPlatformAttribute:"browser"不支持 ColorConsoleLogger 类型。
  • ProviderAliasAttribute:配置节可以使用 "ColorConsole" 键定义选项。

可以使用任何有效的 配置提供程序指定配置。 请考虑以下 appsettings.json 文件:

{"Logging": {//在此处添加 ColorConsole子节点"ColorConsole": {"LogLevelToColorMap": {"Information": "DarkGreen","Warning": "Yellow","Error": "Red"}}}
}

这会将日志级别配置为以下值:

  • LogLevel.Information:ConsoleColor.DarkGreen
  • LogLevel.Warning:ConsoleColor.Cyan
  • LogLevel.Error:ConsoleColor.Red

Information 日志级别设置为 DarkGreen,这将替代 ColorConsoleLoggerConfiguration 对象中设置的默认值。

3. 服务实例注册及注入

实现ILoggingBuilder 接口
实现自定义日志记录提供程序扩展接口

using ContosoUniversity.Extensions.Logger;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging.Configuration;namespace ContosoUniversity.Extensions;public static class ColorConsoleLoggerExtensions
{public static ILoggingBuilder AddColorConsoleLogger(this ILoggingBuilder builder){// 添加使用ILoggerProviderConfiguration接口或所需的服务builder.AddConfiguration();// 尝试注册单例服务<服务类型, 服务描述及实现>builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, ColorConsoleLoggerProvider>());// 指示应将日志设置加载到ILogger实例的类型中LoggerProviderOptions.RegisterProviderOptions<ColorConsoleLoggerConfiguration, ColorConsoleLoggerProvider>(builder.Services);return builder;}public static ILoggingBuilder AddColorConsoleLogger(this ILoggingBuilder builder,Action<ColorConsoleLoggerConfiguration> configure){builder.AddColorConsoleLogger();builder.Services.Configure(configure);return builder;}
}

服务注入
按照约定,注册依赖项注入的服务作为应用程序的启动例程的一部分进行。 注册发生在 Program 类中,也可以委托给 Startup 类。 在此示例中,你将直接从 Program.cs注册。

var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Logging.ClearProviders();
builder.Services.AddLogging(logBuilder =>
{//logBuilder.AddConsole();    // 控制台日志logBuilder.AddColorConsoleLogger();/* 还可通过回调函数,继续对自定义记录器配置项进行添加或修改logBuilder.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;});*/
});var app = builder.Build();
using (var scope = app.Services.CreateScope())
{var services = scope.ServiceProvider;var logger = services.GetRequiredService<ILogger<Program>>();logger.LogError(7, "Oops, there was an error.");logger.LogTrace(5, "== 120.");	//没有配置Track类型日志,输出时则会自动过滤
}

运行此简单应用程序会将颜色输出呈现到控制台窗口,如下图所示:
在这里插入图片描述

第三方日志记录提供程序

下面是一些适用于各种 .NET 工作负荷的第三方日志记录框架:

  • EFLogger
  • JSNLog
  • Log4Net
  • Nlog
  • Serilog

某些第三方框架可以执行 语义日志记录,也称为结构化日志记录。
使用第三方框架类似于使用其中一个内置提供程序:

  1. 将 NuGet 包添加到项目。
  2. 调用日志记录框架提供的 ILoggerFactoryILoggingBuilder 扩展方法。

Log4Net日志

Log4net是从Java中的Log4j迁移过来的一个.Net版的开源日志框架,它的功能很强大,可以将日志分为不同的等级,以不同的格式输出到不同的存储介质中,比如:数据库、txt文件、内存缓冲区、邮件、控制台、ANSI终端、远程接收端等等。

注册及配置
# NuGet包
Install-package Microsoft.Extensions.Logging.Log4Net.AspNetCore 8.0

ILoggingBuilder服务注入

builder.Services.AddLogging(logBuilder =>
{logBuilder.ClearProviders();	//清空默认的日志提供程序[appsettings.json中Logging节点]logBuilder.AddConsole();    // 控制台日志builder.Logging.AddLog4Net();
});// 启用敏感数据以及详细错误跟踪
public partial class SchoolContext : DbContext
{//......protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder){optionsBuilder//.LogTo(Console.WriteLine)// 启用敏感数据.EnableSensitiveDataLogging()// 启用详细错误.EnableDetailedErrors();base.OnConfiguring(optionsBuilder);}    
}
日志项配置

日志配置文件log4net.config,默认配置可存放在项目根下

<?xml version="1.0" encoding="utf-8"?>
<log4net><!-- Define some output appenders --><appender name="FileAppenderDefault" type="log4net.Appender.RollingFileAppender"><!--日志输出到exe程序这个相对目录下--><file value= "..\logs\"/><!--防止多线程时不能写Log,官方说线程非安全--><!--实际使用时,本地测试正常,部署后没有不能写日志的情况--><lockingModel type="log4net.Appender.FileAppender+MinimalLock" /><!--追加日志内容,true后续输出的日志会追加到之前的日志文件--><appendToFile value="true" /><!--可以为:Once|Size|Date|Composite--><!--Composite为Size和Date的组合--><rollingStyle value="Composite" /><!--置为true,当前最新日志文件名永远为file节中的名字--><staticLogFileName value="false" /><!--当备份文件时,为文件名加的后缀--><datePattern value="SqlTrack_yyyy-MM-dd'.log'" /><!--日志最大个数,都是最新的--><!--rollingStyle节点为Size时,只能有value个日志--><!--rollingStyle节点为Composite时,每天有value个日志--><maxSizeRollBackups value="100" /><!--可用的单位:KB|MB|GB--><maximumFileSize value="10MB" /><!--输出级别在INFO和ERROR之间的日志--><filter type="log4net.Filter.LevelRangeFilter"><param name="LevelMin" value="ALL" /><param name="LevelMax" value="FATAL" /></filter><!--<layout type="log4net.Layout.PatternLayout"><conversionPattern value="%n==========%n【日志级别】%-5level%n【记录时间】%date%n【执行时间】[%r]毫秒%n【执行Log分类的名称】%logger%n【传入信息内容】%message%n=========="/></layout>--><layout type="log4net.Layout.PatternLayout"><conversionPattern value="[%p][%d{HH:mm:ss}]【%logger】 %message %n" /></layout></appender><root><!--(高) OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL (低) --><!--<priority value="ALL"/>--><level value="ALL"/><!-- 根据LOG4NET_CONFIG_FILE环境变量确定appender --><appender-ref ref="FileAppenderDefault" /></root>
</log4net>

注解
默认配置文档log4net.config也可以指定配置路径和配置文件名,比如
builder.Logging.AddLog4Net("Cfg\log4net_Development.config");
注意Log4Net需通过项目的appsettings.json中Logging节点配置项进行输出关键性日志。

项目运行所生成的日志内容
在这里插入图片描述

Serilog日志

Serilog 是一个功能强大的日志记录库,专为 .NET 平台设计。它提供了丰富的 API 和可插拔的输出器及格式化器,使得开发者能够轻松定制和扩展日志记录功能。

注意
Srilog.AspNetCore是集成 Serilog 到 ASP.NET Core项目中,其中包含了以下包而无须再手工引入
在这里插入图片描述

JSON格式配置
"Serilog": {//Sink接口(NuGet包引用,为ASPCore内置时可无免指定包引用)"Using": [ "Serilog.Enrichers.Thread", "Serilog.Sinks.Console", "Serilog.Sinks.File" ],//最小级别"MinimumLevel": {"Default": "Information","Override": {"Microsoft.AspNetCore": "Warning","Microsoft.Hosting.Lifetime": "Information","Microsoft.EntityFrameworkCore.Database.Command": "Information"}},//丰富器"Enrich": [{"Name": "FromLogContext"},{"Name": "host","Args": {"value": "Environment.MachineName"}},{"Name": "WithThreadId" //扩充当前管理的ThreadId属性}],//过滤器//"Filter": [//  {//    "Name": "ByExcluding",//    "Args": {//      //只包括//      "expression": "StartsWith(SourceContext, 'Microsoft.EntityFrameworkCore.')"//    }//  },//  {//    "Name": "ByIncludingOnly",//    "Args": {//      //不包括//      "expression": "StartsWith(SourceContext, 'Microsoft.Hosting.Lifetime.')"//    }//  }//],//输出器"WriteTo": [{"Name": "Console","Args": {"theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console","outputTemplate": "[{Level:u4}][{Timestamp:HH:mm:ss}][{SourceContext}]{Exception}{NewLine}{Message:lj}{NewLine}"}},{"Name": "File","Args": {"path": "logs/traceSql-.log","restrictedToMinimumlevel": "Information","fileSizeLimitBytes": 10485760,//"levelSwitch": "InitialLevel","rollingInterval": "Day","rollOnFileSizeLimit": true,"retainedFileCountLimit": 7,"formatter": "Serilog.Formatting.Compact.CompactJsonFormatter,Serilog.Formatting.Compact","outputTemplate": "[{Level:u4}][{Timestamp:HH:mm:ss}][{EventId.Id}]{SourceContext}{Exception}{NewLine}{Message:lj}{NewLine}"}}]
},

通过引用NuGet包Serilog.Settings.Configuration实现JSON配置注入该服务:

// 注册服务
Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(new ConfigurationBuilder().AddJsonFile(path: "appsettings.json", optional: false, reloadOnChange: true).Build()).CreateLogger();
//DI注入
builder.Host.UseSerilog();

这是最简单服务配置方式,下面以不同环境进行配置为例

  • 先定义两个json环境配置文件,如appsettings.Developmentappsettings.Production
    在这里插入图片描述
    两个Json配置内容可以先配置为一样,比如
{"Logging": {"LogLevel": {"Default": "Information","Microsoft.AspNetCore": "Warning"}},"Serilog": {//......省略},"AllowedHosts": "*"}
}

提示
两者最主要的区别,无非就是WriteTo输出,在appsettings.Production生产环境实际项目中可以不需要Console终端输出模式,包含输出方式可以是Sinks.MSSqlServer、Sinks.MySQL数据库或Sinks.Seq、Sinks.Elasticsearch日志服务器平台等等。

  • Json配置加载及服务注入
var builder = WebApplication.CreateBuilder(args);
var appEnvironment = $"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json";Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(new ConfigurationBuilder().AddJsonFile(appEnvironment, optional: true).Build()).CreateLogger();builder.Host.UseSerilog();
Log.Information($"当前项目环境Json配置为:【{appEnvironment}】");

重点就是通过appEnvironment变量动态获取ASPNETCORE_ENVIRONMENT环境变量,当在Debug调试模式下运行时,系统会动态加载appsettings.Development配置。反之,以Publish发布后则会调用appsettings.Production配置进行注入服务。

  • 当发布到生产环境运行时,比如发布到Publist目录直接执行主程序exe文件
    在这里插入图片描述

注意
日志文件存储路径是运行目录(编译后)的logs\xxx.log位置,而Debug调试模式时存放在项目根下。

编程Code方式配置
builder.Host.UseSerilog((context, loggerconfig) =>
{string _outputTemplate = "[{Level:u4}][{Timestamp:HH:mm:ss}][<{ThreadId}>{SourceContext}]{Exception}{NewLine}{Message:lj}{NewLine}";// formatProvider: 提供特定于区域性的格式化信息或为nullvar _formatter = new MessageTemplateTextFormatter(_outputTemplate, formatProvider: null);loggerconfig.MinimumLevel.Information().MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning).MinimumLevel.Override("Microsoft.Hosting.Lifetime", LogEventLevel.Information).MinimumLevel.Override("Microsoft.EntityFrameworkCore.Database.Command", LogEventLevel.Information)//.Filter.ByIncludingOnly(logEvent => logEvent.Level >= LogEventLevel.Error)//.Filter.ByExcluding(Matching.FromSource("Microsoft.EntityFrameworkCore")).Enrich.FromLogContext()    //扩充日志上下文,使用LogContext.PushProperty添加和移除属性.Enrich.WithProperty("host", Environment.MachineName).Enrich.WithThreadId().WriteTo.Console(outputTemplate: _outputTemplate, theme: AnsiConsoleTheme.Literate).WriteTo.Async(c => c.File(formatter: _formatter,path: Path.Combine("logs", @"traceSql-.log"),restrictedToMinimumLevel: LogEventLevel.Information,fileSizeLimitBytes: 10 * 1024 * 1024,      // Singlefile:10MlevelSwitch: null, //new Serilog.Core.LoggingLevelSwitch(LevelAlias.Minimum),//outputTemplate: _outputTemplate,//buffered: false,//shared: false,//flushToDiskInterval: null,rollingInterval: RollingInterval.Day,rollOnFileSizeLimit: true,retainedFileCountLimit: 7//encoding: null,//hooks: null,//retainedFileTimeLimit: null));});var app = builder.Build();
// 启用HttpRequestLogging
app.UseForwardedHeaders();
app.UseSerilogRequestLogging(options =>options.EnrichDiagnosticContext = RequestEnricher.LogAdditionalInfo);Log.Verbose("This is a verbose log message.");
Log.Warning("This is a warning log message.");
Log.Error("This is an error log message.");
//Log.CloseAndFlush();namespace ContosoUniversity.Extensions.Logger;public static class RequestEnricher
{//增加Client请求IPpublic static void LogAdditionalInfo(IDiagnosticContext diagnosticContext, HttpContext httpContext){diagnosticContext.Set("ClientIP",httpContext.Connection.RemoteIpAddress?.ToString());}
}

其中,.Enrich.WithThreadId()丰富器扩充当前管理的子线程信息,比如在输出模板中获取子线程ID{ThreadId}等,而.WriteTo.Async是以异步模型写入文件,需引用NuGet包Serilog.Sinks.Async

LoggerConfiguration配置结构
  • Sinks接收器
  • MinimumLevel最小级别
  • Enrich丰富器
  • Filter过滤(筛选)器
  • WriteTo输出器
  • Property扩展属性

Serilog配置分为Sinks接收器、WriteTo输出器以及Filter过滤器等部分组成,可以通过编程方式或XML、JSON编码方式进行配置。

1. Sinks接收器

提供给.WriteTo输出使用,需引用NeGet包(dotnet add package)支持

# 将日志输出到控制台[Serilog.AspNetCore内置]
Serilog.Sinks.Console# 将日志写入文件中,支持按时间滚动[Serilog.AspNetCore内置]
Serilog.Sinks.File# 将日志发送到 Seq 日志服务器,Seq 提供了强大的查询和可视化功能
Serilog.Sinks.Seq# 将日志发送到 Elasticsearch,配合 Kibana 使用可以进行复杂的日志分析和可视化
Serilog.Sinks.Elasticsearch# 将日志记录到 Microsoft SQL Server 数据库
Serilog.Sinks.MSSqlServer
# 将日志记录到 MySQL 数据库
Serilog.Sinks.MySQL# 通过 HTTP POST 请求发送日志到远程 API 或服务
Serilog.Sinks.Http# 通过电子邮件发送错误或其他关键日志信息
Serilog.Sinks.Email# 将日志发送到 Azure Application Insights,提供性能监控和诊断工具
Serilog.Sinks.ApplicationInsights
2. MinimumLevel最小记录级别

配置将事件传递到接收器的最低级别。如果未指定,则仅 LogEventlevel.lnformation 级别的事件及以上都将通过。

3. Enrichers丰富器

丰富器是一种扩展机制,可以将额外的上下文信息添加到日志事件中。Serilog提供了一些内置的丰富器,例如WithProperty和WithProperties,可以用于添加自定义属性到日志事件中。

除了内置的丰富器,Serilog还支持自定义丰富器,开发人员可以根据自己的需求实现自己的丰富器。自定义丰富器可以从各种来源获取上下文信息,例如从请求头、数据库、配置文件等。

常见的Enrichers

  • WithThreadId ‌:为日志事件添加线程ID属性,帮助追踪线程相关的日志。
  • WithEnvironmentUserName ‌:为日志事件添加环境用户名属性,适用于需要记录用户信息的场景。
  • Serilog.Enrichers.Sensitive ‌:自动屏蔽日志中的敏感信息,如电子邮件地址和IBAN账号,确保日志既详尽又安全‌。
  • Serilog.Enrichers.MassTransit ‌:集成 MassTransit消息传递框架 ,记录消息和事件,便于分析和跟踪应用程序行为‌。

参考配置文档:丰富配置

提供给.Enrich扩充使用,第三方丰富器需引用NeGet包(dotnet add package)支持

# 使用环境变量扩充 Serilog 事件。
Serilog.Enrichers.Context# 使用 System.Environment 中的属性扩充 Serilog 日志事件。
Serilog.Enrichers.Environment
# Serilog 的进程丰富器。
Serilog.Enrichers.Process
# 使用当前线程中的属性扩充 Serilog 事件。
Serilog.Enrichers.Thread# 使用客户端 IP、相关 ID 和 HTTP 请求标头丰富日志。
Serilog.Enrichers.ClientInfo
4. Filters过滤器

过滤器控制要处理的日志事件。该属性提供了用于配置过滤器的方法。

// Example
builder.Host.UseSerilog((context, loggerconfig) =>
{loggerconfig.MinimumLevel.Information()//ByIncludingOnly: 只包括与谓词匹配的事件.Filter.ByIncludingOnly(logEvent => logEvent.Level >= LogEventLevel.Error)//ByExcluding: 不包括匹配谓词的日志事件.Filter.ByExcluding(Matching.FromSource("Microsoft.EntityFrameworkCore"));//loggerconfig.CreateLogger();
});                            
5. WriteTo输出

以下以输出到文件.WriteTo.File参数配置Serilog.Sinks.File 5.0.0为例

/// <summary>
/// 将日志事件写入指定文件。
/// </summary>
/// <param name="sinkConfiguration">日志记录接收器配置</param>
/// <param name="path">文件路径</param>
/// <param name="restrictedToMinimumLevel">通过接收器的事件的最小级别,当指定levelSwitch时忽略
/// <param name="formatProvider">提供特定于区域性的格式化信息或为空</param>
/// <param name="outputTemplate">描述用于写入接收器的格式的消息模板,
/// 默认值为“{Timestamp:yyyy-MM-dd HH:mm:ss”。fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}"</param>
/// <param name="fileSizeLimitBytes">允许日志文件增长到的大致最大大小,以字节为单位
/// 对于不受限制的增长,请传递 null。默认值为 1GB。为避免写入部分事件,即使超出限制,也会完整写入限制内的最后一个事件
/// <param name="levelSwitch">允许在运行时更改最小直通级别的开关
/// <param name="buffered">是否使用缓冲来刷新输出文件,缺省为false</param>
/// <param name="shared">允许多个进程共享日志文件,缺省为false</param>
/// <param name="flushToDiskInterval">按指定的时间间隔定期执行完全磁盘刷新,缺省为null</param>
/// <param name="rollingInterval">日志记录将滚动到新文件的时间间隔</param>
/// <param name="rollOnFileSizeLimit">如果为 true,则在达到文件大小限制时将创建新文件,
/// 文件名将以 _NNN 格式附加一个数字,第一个文件名没有编号</param>
/// <param name="retainedFileCountLimit">保留的日志文件的最大数量,包括当前日志文件
/// 缺省为null,则是无限保留(默认值为31)</param>
/// <param name="encoding">写入文本文件的字符编码,默认值为不带BOM的UTF-8</param>
/// <param name="hooks">(可选)启用挂钩日志文件生命周期事件</param>
/// <param name="retainedFileTimeLimit">间隔结束后,滚动日志文件将保留的最长时间。
/// 必须大于或等于"TimeSpan.Zero"。如果"rollingInterval"为"RollingInterval.Infinite",则忽略默认值为无限期保留文件。
/// <returns>配置对象允许方法链接</returns>
public static LoggerConfiguration File(this LoggerSinkConfiguration sinkConfiguration,string path,LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,string outputTemplate = DefaultOutputTemplate,IFormatProvider? formatProvider = null,long? fileSizeLimitBytes = DefaultFileSizeLimitBytes,LoggingLevelSwitch? levelSwitch = null,bool buffered = false,bool shared = false,TimeSpan? flushToDiskInterval = null,RollingInterval rollingInterval = RollingInterval.Infinite,bool rollOnFileSizeLimit = false,int? retainedFileCountLimit = DefaultRetainedFileCountLimit,Encoding? encoding = null,FileLifecycleHooks? hooks = null,TimeSpan? retainedFileTimeLimit = null)/// <summary>
/// 将日志事件写入指定文件。
/// </summary>
/// <param name="sinkConfiguration">日志记录接收器配置</param>
/// <param name="formatter">格式化程序,例如“JsonFormatter”,用于将日志事件转换为文件的文本。
/// 如果需要控制常规文本格式,请使用"File(LoggerSinkConfiguration, string, LogEventLevel, string, IFormatProvider, long?, LoggingLevelSwitch, bool, bool, TimeSpan?, RollingInterval, bool, int?, Encoding, FileLifecycleHooks, TimeSpan?)"
/// 的另一个重载,并改为指定 outputTemplate 参数</param>
/// <param name="path">文件路径</param>
/// <param name="restrictedToMinimumLevel">通过接收器的事件的最小级别,当指定levelSwitch时忽略
/// <param name="levelSwitch">允许在运行时更改最小直通级别的开关
/// <param name="fileSizeLimitBytes">允许日志文件增长到的大致最大大小,以字节为单位
/// 对于不受限制的增长,请传递 null。默认值为 1GB。为避免写入部分事件,即使超出限制,也会完整写入限制内的最后一个事件
/// will be written in full even if it exceeds the limit.</param>
/// <param name="buffered">是否使用缓冲器来刷新输出文件</param>
/// <param name="shared">允许多个进程共享日志文件,默认值为false</param>
/// <param name="flushToDiskInterval">按指定的时间间隔定期执行完全磁盘刷新,缺省为null</param>
/// <param name="rollingInterval">日志记录将滚动到新文件的时间间隔</param>
/// <param name="rollOnFileSizeLimit">如果为 true,则在达到文件大小限制时将创建新文件,
/// 如果为 true,则在达到文件大小限制时将创建新文件。文件名将以 _NNN 格式附加一个数字,第一个文件名没有编号</param>
/// <param name="retainedFileCountLimit">保留的日志文件的最大数量,包括当前日志文件
/// 缺省为null,则是无限保留(默认值为31)</param>
/// <param name="encoding">写入文本文件的字符编码,默认值为不带BOM的UTF-8</param>
/// <param name="hooks">(可选)启用挂钩日志文件生命周期事件</param>
/// <param name="retainedFileTimeLimit">间隔结束后,滚动日志文件将保留的最长时间。
/// 必须大于或等于 “TimeSpan.Zero”。
public static LoggerConfiguration File(this LoggerSinkConfiguration sinkConfiguration,ITextFormatter formatter,string path,LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,long? fileSizeLimitBytes = DefaultFileSizeLimitBytes,LoggingLevelSwitch? levelSwitch = null,bool buffered = false,bool shared = false,TimeSpan? flushToDiskInterval = null,RollingInterval rollingInterval = RollingInterval.Infinite,bool rollOnFileSizeLimit = false,int? retainedFileCountLimit = DefaultRetainedFileCountLimit,Encoding? encoding = null,FileLifecycleHooks? hooks = null,TimeSpan? retainedFileTimeLimit = null)/// <summary>
/// 将审计日志事件写入指定文件
/// </summary>
/// <param name="sinkConfiguration">日志记录接收器配置</param>
/// <param name="path">文件路径</param>
/// <param name="restrictedToMinimumLevel">通过接收器的事件的最小级别,当指定levelSwitch时忽略
/// <param name="levelSwitch">允许在运行时更改最小直通级别的开关
/// <param name="formatProvider">提供特定于区域性的格式化信息或为空</param>
/// <param name="outputTemplate">描述用于写入接收器的格式的消息模板,
/// 默认值为“{Timestamp:yyyy-MM-dd HH:mm:ss”。fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}"</param>
/// <param name="encoding">写入文本文件的字符编码,默认值为不带BOM的UTF-8</param>
/// <param name="hooks">(可选)启用挂钩日志文件生命周期事件</param>
/// <returns>配置对象允许方法链接</returns>
public static LoggerConfiguration File(this LoggerAuditSinkConfiguration sinkConfiguration,string path,LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,string outputTemplate = DefaultOutputTemplate,IFormatProvider? formatProvider = null,LoggingLevelSwitch? levelSwitch = null,Encoding? encoding = null,FileLifecycleHooks? hooks = null)/// <summary>
/// 将审计日志事件写入指定文件
/// </summary>
/// <param name="sinkConfiguration">日志记录接收器配置</param>
/// <param name="formatter">格式化程序,例如"JsonFormatter",用于将日志事件转换为文件的文本。
/// 如果需要控制常规文本格式,请使用
/// "File(LoggerAuditSinkConfiguration, string, LogEventLevel, string, IFormatProvider, LoggingLevelSwitch, Encoding, FileLifecycleHooks)"的另一个重载,并改为指定 outputTemplate 参数。/>
/// </param>
/// <param name="path">文件路径</param>
/// <param name="restrictedToMinimumLevel">通过接收器的事件的最小级别,当指定levelSwitch时忽略
/// <param name="levelSwitch">允许在运行时更改最小直通级别的开关
/// <param name="encoding">写入文本文件的字符编码,默认值为不带BOM的UTF-8</param>
/// <param name="hooks">(可选)启用挂钩日志文件生命周期事件</param>
/// <returns>配置对象允许方法链接</returns>
public static LoggerConfiguration File(this LoggerAuditSinkConfiguration sinkConfiguration,ITextFormatter formatter,string path,LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,LoggingLevelSwitch? levelSwitch = null,Encoding? encoding = null,FileLifecycleHooks? hooks = null)

提示
上述方法体只提供几种通用最较强的几种,过时或废弃不再列出。

6. Property附加属性

静态附加

builder.Host.UseSerilog((context, loggerconfig) =>
{loggerconfig.Enrich.WithThreadId().Enrich.WithProperty("host", Environment.MachineName);
});

或者在Json中附加

"Serilog":{"Properties": {"Home": "testRoot"}    
}

动态附加
调用IDiagnosticContext接口,进行附加扩展属性:

var app = builder.Build();
// ......
app.UseStaticFiles();
// 添加中间件以简化请求日志记录
app.UseSerilogRequestLogging();public class HomeController : Controller
{readonly IDiagnosticContext _diagnosticContext;readonly ILogger<HomeController> _logger;readonly SchoolContext _context;public HomeController(IDiagnosticContext diagnosticContext,ILogger<HomeController> logger, SchoolContext context){_diagnosticContext = diagnosticContext;_logger = logger;_context = context;}public IActionResult Index(){// The request completion event will carry this property._diagnosticContext.Set("CatalogLoadTime", 1423);return View();}    
}

还可以通过RequestLoggingOptions设置所提供IDiagnosticContext实例的值,我们基本上使用完全相同的方法来定制中间件所使用的方法。下面的静态帮助器类从当前HttpContext上下文检索值,并在值可用时对其进行设置。
下面的静态helper类从当前HttpContext检索值,并在值可用时设置它们。

public static class LogHelper 
{public static void EnrichFromRequest(IDiagnosticContext diagnosticContext, HttpContext httpContext){var request = httpContext.Request;// Set all the common properties available for every requestdiagnosticContext.Set("Host", request.Host);diagnosticContext.Set("Protocol", request.Protocol);diagnosticContext.Set("Scheme", request.Scheme);// Only set it if available. You're not sending sensitive data in a querystring right?!if(request.QueryString.HasValue){diagnosticContext.Set("QueryString", request.QueryString.Value);}// Set the content-type of the Response at this pointdiagnosticContext.Set("ContentType", httpContext.Response.ContentType);// Retrieve the IEndpointFeature selected for the requestvar endpoint = httpContext.GetEndpoint();if (endpoint is object) // endpoint != null{diagnosticContext.Set("EndpointName", endpoint.DisplayName);}}
}

上面的帮助器函数从“Request”,“Response”以及其他中间件(端点名称)设置的功能中检索值。您可以扩展它,以根据需要在请求中添加其他值。
您可以通过调用UseSerilogRequestLoggingEnrichDiagnosticContext属性,来注册上面的帮助类:

var app = builder.Build();
// ... Other middleware
app.UseStaticFiles();app.UseSerilogRequestLogging(opts=> opts.EnrichDiagnosticContext = LogHelper.EnrichFromRequest);// ... Other middleware

现在,当您发出请求时,您将看到添加到Serilog结构化日志中的所有其他属性:
在这里插入图片描述
只要您具有通过当前HttpContext可供中间件管道使用的值,就可以使用此方法。但是MVC的相关属性是个例外,它们是MVC中间件“内部”的特性,例如action 名称或RazorPage处理程序名称。

-持续更新-

http://www.xdnf.cn/news/969139.html

相关文章:

  • cell properties修改参数
  • 突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
  • Vue 指令详解:概念与作用
  • 渲染学进阶内容——模型
  • ssc377d修改flash分区大小
  • 86壳温湿度传感器:高温下工业生产的安全防线
  • Elasticsearch增删改查语句
  • GAMES202-高质量实时渲染(Real-Time Ray-Tracing)
  • Minktec 柔性弯曲传感器应用:3D 脊柱姿势追踪与人体活动识别
  • 半加器和全加器
  • React19源码系列之 事件优先级
  • Netty从入门到进阶(三)
  • 淘宝SKU与视频详情API接口使用指南
  • 6月10日day50打卡
  • 鹰盾播放器禁止录屏操作的深度技术解析与全栈实现方案
  • AI写实数字人实时交互系统本地私有化部署方案
  • Java TCP网络编程核心指南
  • 服务器硬防的应用场景都有哪些?
  • V837s-sdk buildroot文件系统设置串口登录密码
  • Docker 创建及部署完整流程
  • spring jms使用
  • pnpm install 和 npm install 的区别
  • 力扣HOT100之堆:347. 前 K 个高频元素
  • 基于51单片机的三位电子密码锁
  • LDPC码的编码算法
  • 【2025CVPR】花粉识别新标杆:HieraEdgeNet多尺度边缘增强框架详解
  • C++中变量赋值有几种形式
  • [ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
  • Suna 开源 AI Agent 安装配置过程全解析(输出与交互详解)
  • 泊松圆盘采样进行随机选点