ASP.NET Core - 日志记录系统(二)

news/2025/1/12 11:51:49/文章来源:https://www.cnblogs.com/wewant/p/17489884.html

本篇接着上一篇 [ASP.NET Core - 日志记录系统(一)] 往下讲,所以目录不是从 1 开始的。

2.4 日志提供程序

2.4.1 内置日志提供程序

ASP.NET Core 包括以下日志记录提供程序作为共享框架的一部分:

  • Console
  • Debug
  • EventSource
  • EventLog

除此之外,还有一些微软官方提供的,但是没有和 .NET Core 框架集成的提供程序,如 ApplicationInsights 、AzureAppServicesFile 和 AzureAppServicesBlob ,这些在日常开发中使用的比较少,大家有兴趣的话可以自行了解一下。

  • 控制台

    Console 提供程序将输出记录到控制台。

    通用主机启动时就包含了控制台日志提供程序,使用它之后,我们记录的日志在调试过程中,可以在 VS 的 “调试输出” 窗口和 “ASP.NET Core Web 服务器” 窗口(非 IIS Press 启动) 看到。使用 dotnet run 运行应用时,可以在控制台窗口中看到。以 “Microsoft” 类别开头的日志来自 ASP.NET Core 框架代码。 ASP.NET Core 和应用程序代码使用相同的日志记录 API 和提供程序。

    控制台提供程序提供了多个 API,允许根据需要多输出格式、文字颜色等进行调整。

  • 调试

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

    在 Linux 上,Debug 提供程序日志位置取决于分发,并且可以是以下位置之一:

    • /var/log/message
    • /var/log/syslog

  • 事件来源

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

    EventSource 日志提供程序记录的日志可以使用跨平台的 dotnet 追踪工具 dotnet-trace 来收集和跟踪。dotnet-trace 的按照和使用请参阅 dotnet-trace 诊断工具 - .NET CLI | Microsoft Learn 。

  • 事件日志

    仅在 Windows 系统下生效,可通过“事件查看器”进行日志查看。

    EventLog 提供程序将日志输出发送到 Windows 事件日志。 与其他提供程序不同,EventLog 提供程序不继承默认的非提供程序设置。 如果未指定 EventLog 日志设置,则它们默认为 LogLevel.Warning。若要记录低于 LogLevel.Warning 的事件,请显式设置日志级别。

    默认情况下,记录下来的事件日志一些基本参数如下:

    • LogName:“Application”
    • SourceName:“.NET Runtime”
    • MachineName:使用本地计算机名称。

    我们可以通过 AddEventLog 重载可以传入 EventLogSettings 来修改:

    var builder = WebApplication.CreateBuilder();
    builder.Logging.AddEventLog(eventLogSettings =>
    {eventLogSettings.SourceName = "MyLogs";
    });
    

上面已经讲到,在通过通用主机启动一个 .NET Core 应用时,会默认添加了 Console、Debug、EventSource 日志提供程序,如果运行平台是 Windows,还会添加 EventLog 日志提供程序。通过 ILoggingBuilder 我们可以重置并自定义日志提供程序的类型,这使得我们可以根据需要使用任何符合标准的日志提供程序。

如果是没有使用通用主机的非托管控制台应用,可以通过以下方式添加控制台日志提供程序:

using var loggerFactory = LoggerFactory.Create(builder =>
{builder.AddConsole();
});
ILogger logger = loggerFactory.CreateLogger<Program>();
logger.LogInformation("Example log message");

不止控制台日志提供程序,其他各种日志提供程序都是按照日志记录系统框架进行开发和集成。显然,仅这些内置日志提供程序并不能满足我们生产开发中的适应,例如缺少最基础且常用的文件日志提供程序,还有在分布式应用已经非常普遍的业界现状下,时常需要将日志写分布式日志系统中进行统一的管理和分析,这些是微软没有提供的,但是第三方都有成熟的按照 .NET Core 日志记录系统体系架构开发的实现,这些将在下面细讲。

2.4.2 源码解析

.NET Core 日志记录系统的使用非常简单方便,其扩展性非常强,上面的章节已经讲解了基本的配置和使用,最核心的实现在于 LogeerFactoryILogger, LogeerFactory 用于日志系统的配置,ILogger 用于日志记录。下面从框架源码的角度,解析一下日志记录系统的实现。

阅读一个框架源码,我们可以从其开放出来的 API 作为入口,这样能较容易地梳理出其设计思路和实现脉络。首先是日志配置这一块,我们在应用集成的时候,对日志系统的配置都是基于 ILoggingBuilder 的,当然通过上面章节的内容,大家都已经知道在我们 ILoggingBuilder 进行配置之前,通用主机已经进行了一些配置。

ILoggingBuilder 的实现类其实就只是保存了容器,其他各种可用的方法都是扩展方法,都是往容器之中添加配置。

image

在添加日志系统默认配置的时候,可以看到显示调用了 AddLogging() 方法,之后就是像我们自己在实际应用中对日志系统进行配置一样帮我们添加了一些默认配置。

image

AddLogging() 方法是扩展方法,在 LoggingServiceCollectionExtensions 类中,在这个方法中往容器注入了三个日志记录系统最关键的东西,分别是 LoggerFactoryLogger<> 和日志配置。

image

当我们从使用日志记录器的时候,要么就是从容器中解析,要么就是通过 LoggerFactory.CreateLogger() 方法创建,查看 Logger<> 类的实现,其内部其实也是通过 LoggerFactory 创建了 ILogger 实例,注意这里的 ILogger 是没有泛型的,最终我们使用的其实都是这一个没有泛型的。

image

LoggerFactory 在其初始化的时候,会从容器中解析出我们添加的日志记录提供程序以及和日记记录系统相关的配置信息,并将日志记录提供程序保存到集合中。

image

当调用 CreateLogger 方法时,会创建 Logger 实例,为其配置并应用过滤规则,并将其保存起来。

image

image

这里就引出了三个重要的内部实现 LoggerLoggerInformationMessageLoggerLogger 是上面讲到的我们最终实际使用的 ILogger 的实现类,它的构造函数中需要传入 LoggerInformation 数组,LoggerInformation 数组与与日志提供程序的数量对应。LoggerInformation 是一个结构体,是针对特定日志记录提供程序和日志类别的封装,在内部创建了特定于具体日志提供程序的日志记录器。

image

MessageLogger 是最终的日志信息书写的地方,它也是一个结构体,包含了规则过滤等内容,可以看到它的构造函数中传入了 LoggerInformationLogger 属性,也就是说最终也是使用特定于日志提供程序的日志记录器的。

image

最终返回的 MessageLogger 数组赋值给了 LoggerMessageLogger 数组不一定与日志记录提供程序的数量一样,应该有些日志记录提供程序在规则配置检查中可能跳过了。

Logger 类应用了装饰器模式,对多种日志记录提供程序的记录器进行了包装,提供了统一的日志记录 API,使得我们在使用时可以通过统一的入口将日志同时书写到不同的地方。当我们调用 Logger 实例的 Log 方法时,实际上是遍历了 MessageLogger 数组,通过具体的日志提供程序对应的日志记录器对当前日志级别进行检查,并进行最终的日志记录。

最终返回的 MessageLogger 数组赋值给了 LoggerMessageLogger 数组不一定与日志记录提供程序的数量一样,应该有些日志记录提供程序在规则配置检查中可能跳过了。

Logger 类应用了装饰器模式,对多种日志记录提供程序的记录器进行了包装,提供了统一的日志记录 API,使得我们在使用时可以通过统一的入口将日志同时书写到不同的地方。当我们调用 Logger 实例的 Log 方法时,实际上是遍历了 MessageLogger 数组,通过具体的日志提供程序对应的日志记录器对当前日志级别进行检查,并进行最终的日志记录。

image

以控制台提供程序为例,这里中间有很多代码,其实只是为了实现更好的扩展性和性能,可以先忽略不看,最终也只是返回了特定 ConsoleLogger

image

ConsoleLogger 中的 Log 方法最终是将日志信息放到队列中,再由队列处理器写到控制台中。

image

2.4.3 自定义日志提供程序

了解完 .NET Core 日志记录系统的整体实现逻辑之后,我们想实现一个自己的日志提供程序其实还是比较简单的,当然如果要像微软内置的日志记录提供程序,或者第三方成熟的日志框架那样,各种细节处理得很好,就稍微有些难度了。以下是一个简单的示例,模仿默认日志记录提供程序的的实现方式,将日志记录到文件中:

(1) 创建一个类库项目,并引入以下依赖包

Install-Package Microsoft.Extensions.Logging.Abstractions
Install-Package Microsoft.Extensions.Logging

(2) 首先是实现 ILogger 接口,提供我们的日志记录器

internal sealed class WeWantFileLogger : ILogger
{private readonly object _sync = new object();/// <summary>/// 创建日志记录域/// </summary>/// <typeparam name="TState"></typeparam>/// <param name="state"></param>/// <returns></returns>/// <exception cref="NotImplementedException"></exception>public IDisposable? BeginScope<TState>(TState state) where TState : notnull{// 由于不准备支持日志记录域功能,这里返回一个空实现return NullScope.Instance;}/// <summary>/// 判断是否记录日志/// </summary>/// <param name="logLevel"></param>/// <returns></returns>public bool IsEnabled(LogLevel logLevel){return logLevel != LogLevel.None;}/// <summary>/// 记录日志,这里简单的演示例子/// 一个可用于正式环境的文件记录器还需考虑很多可扩展性、性能等因素/// </summary>/// <typeparam name="TState"></typeparam>/// <param name="logLevel"></param>/// <param name="eventId"></param>/// <param name="state"></param>/// <param name="exception"></param>/// <param name="formatter"></param>public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter){if (!IsEnabled(logLevel)){return;}ThrowHelper.ThrowIfNull(formatter);string message = formatter(state, exception);if(string.IsNullOrEmpty(message)){return;}message = $"{logLevel}: {message} { Environment.NewLine }";if(exception != null){message += Environment.NewLine + Environment.NewLine + exception;}var filePath = Path.Combine(Directory.GetCurrentDirectory(), "log.txt");lock (_sync){System.IO.File.AppendAllText(filePath, message);}}
}

其他相关的类如下:

internal sealed class NullScope : IDisposable
{public static NullScope Instance = new NullScope();private NullScope() { }public void Dispose(){}
}internal static partial class ThrowHelper
{/// <summary>Throws an <see cref="ArgumentNullException"/> if <paramref name="argument"/> is null.</summary>/// <param name="argument">The reference type argument to validate as non-null.</param>/// <param name="paramName">The name of the parameter with which <paramref name="argument"/> corresponds.</param>internal static void ThrowIfNull(
#if NETCOREAPP3_0_OR_GREATER[NotNull]
#endifobject? argument,[CallerArgumentExpression("argument")] string? paramName = null){if (argument is null){Throw(paramName);}}#if NETCOREAPP3_0_OR_GREATER[DoesNotReturn]
#endifprivate static void Throw(string? paramName) => throw new ArgumentNullException(paramName);
}[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
internal sealed class CallerArgumentExpressionAttribute : Attribute
{public CallerArgumentExpressionAttribute(string parameterName){ParameterName = parameterName;}public string ParameterName { get; }
}

(3) 然后是实现 ILoggerProvider 接口,提供日志记录提供程序

[ProviderAlias("WeWantFile")]
public class WeWantFileLoggerProvider : ILoggerProvider
{public ILogger CreateLogger(string categoryName){return new WeWantFileLogger();}public void Dispose(){}
}

(4) 提供相应的扩展方法

public static class WeWantFileLoggerFactoryExtensions
{public static ILoggingBuilder AddWeWantFile(this ILoggingBuilder builder){builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, WeWantFileLoggerProvider>());return builder;}
}

(5) 在之前的项目中引用,并进行以下配置

// 清除默认的日志记录提供程序,添加自定义的日志记录提供程序
builder.Logging.ClearProviders();
builder.Logging.AddWeWantFile();

(6) 测试日志记录

调用之前测试用的 Web API 接口,代码如下:

// 各种日志API对应各种日志级别
// 断点
_logger.LogTrace("这是一个断点日志");
//调试
_logger.LogDebug("this is a debug.");
//信息
_logger.LogInformation("this is an info.");
//警告
_logger.LogWarning("this is a warning.");
//错误
_logger.LogError("this is an error.");
//当机
_logger.LogCritical("this is Critical");

可以看到项目文件夹中多了 log.txt文件,内容如下:

image

image

.NET Core 下的日志记录系统大概就介绍到这里,后面再继续介绍一下一些第三方日志框架,怎么将其集成到 .NET Core 框架中进行正式生产环境下的应用。



参考文章:

.NET Core 和 ASP.NET Core 中的日志记录 | Microsoft Learn
理解ASP.NET Core - 日志(Logging) - xiaoxiaotank - 博客园 (cnblogs.com)



ASP.NET Core 系列:

目录:ASP.NET Core 系列总结
上一篇:ASP.NET Core - 日志记录系统(一)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/868122.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

bullyBox pg walkthrough Intermediate

nmap 发现80 和 22端口 访问80 端口发现 跳转 http://bullybox.local/ 在/etc/hosts 里面加上这个域名dirsearch 扫描的时候发现了.git泄露 用dunpall工具 获取.git泄露的源码查看源码 我们发现了数据库的密码 name => boxbilling, user => admin, password => Playin…

苹果系统下无痕检测是否开启iMessage服务,iMessages数据筛选,iMessage蓝号检测协议版

一、实现iMessage数据检测的两种方式:1.人工筛选,将要验证的号码输出到文件中,以逗号分隔。再将文件中的号码粘贴到iMessage客户端的地址栏,iMessage客户端会自动逐个检验该号码是否为iMessage账号,检验速度视网速而定。红色表示不是iMessage账号,蓝色表示iMessage账号。2…

数据分析之年度总结分享

背景:我们是一家国内的服装公司,在全国拥有几十家服装门店,从事18个服装品类的销售,市场覆盖国内上海、华北、华中、西南、东北、中南、西北七个区域,年销售额达数千万元。财年结束了,老板希望我们(数据分析师)能对公司的销售团队的数据进行分析,并得出结论作为下年度…

国家数据如何统一目录标识、统一身份登记和统一接口

日前,《国家数据基础设施建设指引》发布。最大的看点之一,是全国数据统一大市场:统一目录标识、统一身份登记和统一接口。那么,如何实现数据的全国统一目录标识、统一身份登记和统一接口? 一、全国统一目录标识 建立数据分类标准 顶层设计规划:由国家相关部门牵头,联合各…

信创环境下国产系统不同版本的依赖库都从哪里下载

在Linux系统中安装软件时,可能会遇到各种依赖库问题,以下是一些常见的依赖库问题及其解决方法,以及获取软件依赖包的不同途径。 1、依赖库问题 依赖库版本不兼容:安装软件时,系统提示缺少特定版本的依赖库。 依赖库缺失:软件安装需要某些库文件,但系统中未安装。 依赖冲…

1. 结构光系统标定原理

什么时逆向机法,与双目模型区别?

读量子霸权01硅时代的终结

硅时代的终结1. 量子计算机 1.1. 一种全新型计算机,在处理特定任务时能明显超越普通数字超级计算机1.1.1. 谷歌宣称自己研发的量子计算机Sycamore可以在200秒以内解决世界上最快的数字超级计算机花1万年才能完成的数学问题1.1.1.1. 谷歌的Sycamore量子计算机就是全球第一台实现…

合成橡胶 2025

1月12日: C浪反弹进行中 目前在走C-3

转:celery 常用执行命令

转自:https://blog.csdn.net/weixin_44649870/article/details/105844668celery 常用执行命令详解执行命令celery -A test-1.celery worker -n name-1 --loglevel=info --max-tasks-per-child 500 --autoscale=4,1 -Q q-1常用参数参数 说明-A / --app 要使用的应用程序实例-n …

VMware ESXi 8.0U3c macOS Unlocker OEM BIOS 集成驱动版,新增 12 款 I219 网卡驱动

VMware ESXi 8.0U3c macOS Unlocker & OEM BIOS 集成驱动版,新增 12 款 I219 网卡驱动VMware ESXi 8.0U3c macOS Unlocker & OEM BIOS 集成驱动版,新增 12 款 I219 网卡驱动 VMware ESXi 8.0U3c macOS Unlocker & OEM BIOS 集成网卡驱动和 NVMe 驱动 (集成驱动版…