J4JLogger: 高级日志记录解决方案

在编写和调试代码时,通常希望能够直接定位到出现问题的地方。由于几乎总是包含日志记录,查看日志事件会是一个很好的起点。但是,Serilog默认并不提供包含源代码信息(如源文件、调用方法和行号)的方式。J4JLogger作为一个Serilog的包装器,提供了这样的功能,并且可以通过短信发送日志事件,这对于真正严重的问题非常有用。虽然目前只包含了Twilio提供商,但添加其他SMS库的提供商也很简单。

J4JLogger还提供了一个缓存日志器,适合在“真正的”日志系统建立之前作为日志目标使用(例如,在构建IHost时)。缓存的条目可以在日志系统建立后转储到日志系统中,提供在调试启动问题时有用的信息。

在编写代码时,通常喜欢能够直接定位到造成问题的地方。由于几乎总是包含日志记录,查看日志事件会是一个很好的起点。但是,Serilog默认并不提供包含源代码信息(如源文件、调用方法和行号)的方式。

一种可能的解决方案是编写一个丰富器(enricher),在Serilog中,它允许将额外的信息插入到日志记录过程中。但真正的挑战在于获取这些信息。如果需要在所有的日志调用中指定方法调用名称、源代码文件名称和行号,那将是非常繁琐的。而且这样做也很容易出错,因为这些名称和数字在开发过程中会经常变化。

有一个更好的方法:C#编译器允许在任何方法调用中自动包含这些信息,只要在参数列表中包含某些带有特定属性和分配特定默认值的参数。例如: public void Write( LogEventLevel level, string template, [CallerMemberName] string memberName = "", [CallerFilePath] string srcPath = "", [CallerLineNumber] int srcLine = 0); 当调用这个方法时,关于方法被调用的上下文信息——调用成员的名称、源代码文件的路径和调用的行号——在Write()方法中是可用的。这就是J4JLogger包含在日志事件中的信息。

使用代码

有多种方式可以设置J4JLogger(请查看Github页面上的详细信息)。这里是一个使用Serilog的IConfiguration-based插件的例子: using System; using System.IO; using System.Linq; using System.Runtime.CompilerServices; using J4JSoftware.Logging; using Microsoft.Extensions.Configuration; using Serilog; namespace ConfigurationBasedExample { class Program { static void Main(string[] args) { var loggerConfig = new J4JLoggerConfiguration(); var configRoot = new ConfigurationBuilder() .AddJsonFile(Path.Combine(Environment.CurrentDirectory, "appConfig.json"), true) .Build(); loggerConfig.SerilogConfiguration.ReadFrom.Configuration(configRoot); var logger = loggerConfig.CreateLogger(); logger.SetLoggedType(typeof(Program)); logger.Information("This is an Informational logging message"); logger.Fatal("This is a Fatal logging message"); } } }

附加功能

有时,需要立即通知某些日志事件(例如,如果依赖的服务运行出现问题)。为了适应这种情况,增加了将日志事件作为短信发送的功能。

要做到这一点,需要向日志器添加一个Serilog接收器,它在Serilog和短信服务之间进行接口。该库包括一个与Twilio一起工作的接收器。但可以添加其他的,这并不难(请查看Github文档了解详细信息)。

SMS功能是通过调整日志器的SmsHandling属性来触发的。这可以通过设置或通过以下便捷方法来完成: public void SendNextEventToSms() => SmsHandling = SmsHandling.SendNextMessage; public void SendAllEventsToSms() => SmsHandling = SmsHandling.SendUntilReset; public void StopSendingEventsToSms() => SmsHandling = SmsHandling.DoNotSend;

非常喜欢Microsoft的IHostBuilder/IHost API。它允许在启动时以开发者定义的方式配置应用程序,然后将执行交给声明的运行时代理方法。它支持使用IConfigurationBuilder/IConfiguration API和依赖注入。在项目中,经常使用它来设置J4JLogging子系统。

鉴于大多数启动程序的复杂性,如果在初始化期间记录事件以便于研究问题将会很方便。不幸的是,尝试简单地通过J4JLogger(或任何其他日志器,怀疑)来做这件事会产生一个鸡和蛋的问题:不能记录到一个尚未配置和构建的日志器。

解决这个问题的方法是定义了一个特殊的J4JLogger版本,J4JCachedLogger,它不包装Serilog日志器。实际上,它根本不发出任何日志事件。相反,它将它们存储在内存中,直到“真正的”日志器建立起来。在这一点上,可以通过调用以下方法将所有缓存的日志事件转储到J4JLogger: public abstract bool OutputCache(J4JCachedLogger cachedLogger);

有时需要在UI中显示日志消息,或者其中的子集。为了简化这一点,在IJ4JLogger中添加了一个C#事件,可以监听它: event EventHandler<NetEventArgs>? LogEvent; NetEventArgs是一个简单的类,它只是回显一个记录的事件: public class NetEventArgs { public NetEventArgs(LogEventLevel level, string mesg) { Level = level; LogMessage = mesg; } public LogEventLevel Level { get; } public string LogMessage { get; } }

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485