本文介绍了在.NET Core中如何在组件设计中使用Trace和TraceSource。
在以下方面会提供一些帮助:
1.你已经为.NET Framework和.NET Core / .NET Standard构建了组件,而且你更喜欢保留Trace和TraceSource。
2.你有使用跟踪和TraceSource的第三方组件。
3.你正在将一个复杂的.NET Framework应用程序迁移到.NET Core,并且目前还不想更改跟踪和日志记录设计。
4.你将保持跟踪和日志记录的分离和易用。
5.可部署的程序不会托管在Linux中。
目标读者是那些在.NET Framework编程方面有丰富经验的程序员,这里讨论的知识是 .NET Core和.NET Framework 。
在.NET生态系统中使用特定的技术堆栈会产生一些困惑,因为有很多选择,比如应该使用哪种类型的运行时?在这篇文章中,我们将试图把这些要点都说清楚。
在.NET Core中,默认的跟踪和日志被升级为 ILogger<T>,相应的日志记录器对象被通过 .NET Core的依赖注入实例化。ILogger<T> 可以与System.Diagnostics.TraceSource比较。ILoggerProvider对象可以与System.Diagnostics.TraceListener比较。
在.NET Core上为一个复杂的应用程序编程期间,我发现关于在.NET Core中使用Trace和TraceSource的文章很少,而几乎所有的文章和示例都是关于 ILogger<T>的。我可以通过谷歌找到如何使用ILogger并立即注入Program,Startup和控制器,而我一直在寻找例子使ILogger组件远离项目。
Logger
接下来的代码示例包含多个项目,每个项目代表一个简单的场景和一个技术解决方案。
日志记录不包含在.NET Core运行时和启动逻辑中,也不包含在控制台应用程序的脚手架代码中。为了使用日志,Microsoft.Extensions.Logging是必不可少的。
但是,仅此包不足以将日志记录到控制台。相反,使用Microsoft.Extensions.Logging.Console:
这个package包括Microsoft.Extensions.Logging。此外,通常你不会在代码中切换编码,而是在配置文件中,通常在.NET Core中,使用的是JSON配置文件,因此你需要Microsoft.Extensions.Configuration.Json。
LoggerFactory
代码示例:ConsoleAppLoggerFactory
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; namespace ConsoleAppLoggerDemo { class Program { static void Main(string[] args) { var configuration = new ConfigurationBuilder() .AddJsonFile("appsettings.json", false, true) .Build(); using var loggerFactory = LoggerFactory.Create( builder => { builder.AddConfiguration(configuration.GetSection("Logging")); builder.AddConsole(); } ); var logger = loggerFactory.CreateLogger<Program>(); logger.LogInformation("1111logger information"); //settings in appsettings.json filters this out logger.LogWarning("2222logger warning"); var fooLogger = loggerFactory.CreateLogger<FooService>(); IFooService fooService = new FooService(fooLogger); fooService.DoWork(); } } public interface IFooService { void DoWork(); } public class FooService : IFooService { private readonly ILogger logger; public FooService(ILogger<FooService> logger) { this.logger = logger; } public void DoWork() { logger.LogInformation("3333Doing work."); logger.LogWarning("4444Something warning"); logger.LogCritical("5555Something critical"); } } }
appsettings.json
{ "Logging": { "Console": { "disableColors": false }, "LogLevel": { "Default": "Information", "Microsoft": "Information", "ConsoleAppLoggerDemo.FooService": "Warning", "ConsoleAppLoggerDemo.Program": "warning" } } }
这对于非常简单的场景来说已经足够好了,但是,在复杂的应用程序中,你可能想要利用.net Core中内置的依赖注入,如下所述。
向ServiceCollection注入Logger
代码示例:ConsoleAppAddLogging
在ServiceCollection中构建并注册了ILoggerFactory的一个实例,因此该工厂随后通过以下两种方式创建 ILogger<Program>:
serviceProvider.GetService<ILoggerFactory>().CreateLogger<Program>();
或者
serviceProvider.GetService<ILogger<Program>>();
当FooService通过依赖注入实例化时,定义的ILogger<FooService>被实例化和注入。
using Microsoft.Extensions.Logging; using System; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; namespace ConsoleAppLoggerDemo { class Program { static void Main(string[] args) { Console.WriteLine("Hello World! from console"); var configuration = new ConfigurationBuilder() .AddJsonFile("appsettings.json", false, true) .Build(); using var serviceProvider = new ServiceCollection() .AddSingleton<IFooService, FooService>() .AddLogging(builder => { builder.AddConfiguration(configuration.GetSection("Logging")); builder.AddConsole(); }) .BuildServiceProvider(); ILogger<Program> logger = serviceProvider.GetService<ILogger<Program>>(); //logger = serviceProvider.GetService<ILoggerFactory>().CreateLogger<Program>(); // Factory first. This works too. IFooService fooService = serviceProvider.GetService<IFooService>(); logger.LogInformation("1111logger information"); logger.LogWarning("2222logger warning"); fooService.DoWork(); } } public interface IFooService ... }
Trace 和 TraceSource
System.Diagnostics.Trace 和 System.Diagnostics.TraceSource是为分离跟踪和日志而设计的,通过附加的跟踪监听器实现日志记录。
代码示例:ConsoleAppTraceListener
. net Framework中许多TraceListener派生类在. net Core上都是可用的,但是像IisTraceListener这样的东西在. net Core上是不可用的。
在. net Framework中,应用程序可以初始化Trace和TraceSource,并在执行应用程序代码的第一行之前,通过app.config实例化并加载跟踪侦听器。
在.net Core中,你仍然可以使用各种跟踪监听器,比如ConsoleTraceListener,但是,因为. net Core默认情况下不会加载配置文件,而且内置配置不会关心跟踪监听器。
1
2
3
4
5
6
|
using ( var listener = new TextWriterTraceListener( "c:\temp\mylog.txt" )) using ( var consoleListener = new ConsoleTraceListener()) { Trace.Listeners.Add(listener); Trace.Listeners.Add(consoleListener); } |
因此,你必须在应用程序启动代码中实例化跟踪侦听器并初始化Trace和TraceSources对象。还不算太坏,不过事情会继续发展,越来越多的第三方组件可能会使用ILogger<T>接口用于跟踪和日志记录。考虑到各种因素和权衡,最好在TraceSource和ILogger<T>之间建立一座桥梁,这样使用Trace和TraceSource的遗留组件可以向ILogger<T>发送跟踪消息。
LoggerTraceListener
这是一个辅助TraceListener,可以将Trace和TraceSource连接到ILogger。
代码示例:ConsoleAppTrace
由于Trace和TraceSource只有侦听器与日志记录接口,因此这里有LoggerTraceListener来侦听跟踪并写入ILogger<T>,它最终将跟踪发送给记录器提供程序。
public class LoggerTraceListener : TraceListener { private readonly ILogger logger; public LoggerTraceListener(ILogger logger) { this.logger = logger; } public override void Write(string message) { logger.LogInformation(message); } public override void WriteLine(string message) { logger.LogInformation(message); } public override void WriteLine(string message, string category) { logger.LogInformation(category + ": " + message); } public override void TraceEvent (TraceEventCache eventCache, string source, TraceEventType eventType, int id) { switch (eventType) { case TraceEventType.Critical: logger.LogCritical(id, source); break; case TraceEventType.Error: logger.LogError(id, source); break; case TraceEventType.Warning: logger.LogWarning(id, source); break; case TraceEventType.Information: logger.LogInformation(id, source); break; case TraceEventType.Verbose: logger.LogTrace(id, source); break; case TraceEventType.Start: logger.LogInformation(id, "Start: " + source); break; case TraceEventType.Stop: logger.LogInformation(id, "Stop: " + source); break; case TraceEventType.Suspend: logger.LogInformation(id, "Suspend: " + source); break; case TraceEventType.Resume: logger.LogInformation(id, "Resume: " + source); break; case TraceEventType.Transfer: logger.LogInformation(id, "Transfer: " + source); break; default: throw new InvalidOperationException("Impossible"); } }
Startup:
using var serviceProvider = new ServiceCollection() .AddSingleton<IFooService, FooService>() .AddLogging(builder => { builder.AddConfiguration(configuration.GetSection("Logging")); builder.AddConsole(); }) .BuildServiceProvider(); ILogger<Program> logger = serviceProvider.GetService<ILogger<Program>>(); IFooService fooService = serviceProvider.GetService<IFooService>(); logger.LogInformation("1111logger information"); logger.LogWarning("2222logger warning"); fooService.DoWork(); using (var listener = new LoggerTraceListener(logger)) { System.Diagnostics.Trace.Listeners.Add(listener); TraceSources.Instance.InitLoggerTraceListener(listener); TraceLover.DoSomething(); TraceSourceLover.DoSomething(); }
现在,Trace和TraceSource可以使用什么日志媒体是由连接到ILogger的日志程序提供程序决定的。
代码示例:ConsoleappSeriLog
微软已经在.net Core中开发了一些具体的日志提供程序,这可能是基于业务愿景和设计。
有相当多的第三方日志提供商:
· NLog
· Log4net
· Serilog
我认为Serilog 是最好的。
var configuration = new ConfigurationBuilder() .AddJsonFile("appsettings.json", false, true) .Build(); Serilog.Log.Logger = new Serilog.LoggerConfiguration() .Enrich.FromLogContext() .ReadFrom.Configuration(configuration) .CreateLogger(); using var serviceProvider = new ServiceCollection() .AddLogging(builder => builder.AddSerilog()) .AddSingleton<IFooService, FooService>() .BuildServiceProvider(); var logger = serviceProvider.GetService<ILogger<Program>>(); var fooService = serviceProvider.GetService<IFooService>(); try { Log.Information("Starting up"); logger.LogInformation("1111logger information"); logger.LogWarning("2222logger warning"); fooService.DoWork(); using (var listener = new LoggerTraceListener(logger)) { System.Diagnostics.Trace.Listeners.Add(listener); TraceSources.Instance.InitLoggerTraceListener(listener); TraceLover.DoSomething(); TraceSourceLover.DoSomething(); } } catch (Exception ex) { Log.Fatal(ex, "Application start-up failed"); } finally { Log.CloseAndFlush(); }
appsettings.json:
{ "TraceSource": { "WebApi": { "SourceLevels": "Information" }, "HouseKeeping": { "SourceLevels": "Warning" }, "DbAudit": { "SourceLevels": "Warning" } }, "Serilog": { "MinimumLevel": { "Default": "Debug", "Override": { "Microsoft": "Information", "System": "Warning", "ConsoleAppLoggerDemo.FooService": "Warning", "ConsoleAppLoggerDemo.Program": "Warning" } }, "WriteTo": [ { "Name": "Console" }, { "Name": "File", "Args": { "path": "%PROGRAMDATA%/my/logs/CloudPosApi_Test.log", "outputTemplate": "{Timestamp:MM-dd HH:mm:ss.fff zzz} [{Level}] {ThreadId} {Message}{NewLine}{Exception}", "rollingInterval": "Day" } } ] } }
在.NET Framework中,运行时将加载app.config并在执行应用程序代码的第一行之前将设置应用于一些内置组件。一些其他组件,如SMTPClient和System.Diagnostics组件默认情况下将读取app.config。
在.NET Core上,在代码中或通过加载配置文件进行配置是应用程序程序员的职责。
欢迎关注我的公众号——码农译站,如果你有喜欢的外文技术文章,可以通过公众号留言推荐给我。
原文链接:https://www.codeproject.com/Articles/5255953/Use-Trace-and-TraceSource-in-NET-Core-Logging