TagProvider
[LogProperties] 与 [LogPropertyIgnore] 如果用在DTO不存在任何问题,如果用在Domain实体上,可能有点混乱。
您可能不希望因日志记录问题而使您的域模型变得混乱。对于这种情况,可以使用[TagProvider]属性来丰富日志。
我们仍然使用前面用的Network实体,这次它不再使用[LogPropertyIgnore]属性:
- public class NetWorkInfo
- {
- public string IPAddress { get; set; }
- public int Port { get; set; }
- }
相反,我们定义了一个专用的“TagProvider”实现。
不需要实现接口或任何类,只需要正确的方法格式。
下面是我们给Network对象的标签提供程序,我们只记录字段IPAddres字段,如下所示:
- internal static class NetWorkInfoTagProvider
- {
- // ?? Has the required signature 'void RecordTags(ITagCollector, T)'
- public static void RecordTags(ITagCollector collector, NetWorkInfo network)
- {
- // You can add aribrtrary objects to be logged.
- // You provide a key (first arg) and a value.
- collector.Add(nameof(NetWorkInfo.IPAddress), network.IPAddress);
- }
- }
定义标签提供程序后,我们现在可以在日志记录方法中使用它。
将属性替换[LogProperties]为[TagProvider]如下所示的属性:
- public static partial class Log
- {
- [LoggerMessage(
- EventId = 0,
- Level = LogLevel.Error,
- Message = "Can not open SQL connection {err}")]
- public static partial void CouldNotOpenConnection(this ILogger logger, string err,
- [TagProvider(typeof(NetWorkInfoTagProvider), nameof(NetWorkInfoTagProvider.RecordTags))] NetWorkInfo netWork);
- }
按正常方式调用即可,可以看到Network.IPAddress已经记录到日志的State属性中。
- private static async Task Main(string[] args)
- {
- using ILoggerFactory loggerFactory = LoggerFactory.Create(
- builder =>
- builder.AddJsonConsole(
- options =>
- options.JsonWriterOptions = new JsonWriterOptions()
- {
- Indented = true
- }));
- ILogger logger = loggerFactory.CreateLogger("Program");
- logger.CouldNotOpenConnection("network err", new NetWorkInfo { IPAddress = "123.1.1", Port = 7777 });
- }

Enricher
Microsoft.Extensions.Telemetry包可以像Serilog一样丰富日志。首先添加Nuget包
- <PackageReference Include="Microsoft.Extensions.Telemetry" Version="8.3.0" />
首先使用方法ILoggingBuilder.EnableEnrichment()启用全局丰富,并通过AddProcessLogEnricher将进程的日志信息添加到日志中。
- builder.Logging.AddJsonConsole(options =>
- options.JsonWriterOptions = new JsonWriterOptions()
- {
- Indented = true
- }
- );
- builder.Logging.EnableEnrichment(); // Enable log enrichment
- builder.Services.AddProcessLogEnricher(x =>
- {
- x.ProcessId = true; // Add the process ID (true by default)
- x.ThreadId = true; // Add the managed thread ID (false by default)
- });
也可以通过metadata自定义使用的字段
- builder.Services.AddServiceLogEnricher(options =>
- {
- options.ApplicationName = true; // Choose which values to add to the logs
- options.BuildVersion = true;
- options.DeploymentRing = true;
- options.EnvironmentName = true;
- });
- builder.Services.AddApplicationMetadata(x =>
- {
- x.ApplicationName = "My App";
- x.BuildVersion = "1.2.3";
- x.EnvironmentName = "Development";
- x.DeploymentRing = "test";
- });

这些内置的丰富器很方便,但也可以创建自定义的实现。
自定义LogEnricher
您可以通过从或接口IStaticLogEnricher和ILogEnricher派生创建自己的丰富器
- IStaticLogEnricher: IStaticLogEnricher—是全局的enricher,如果日志在整个声明周期中不变则可将其标签添加到记录器中。
- ILogEnricher- 每次写入日志时都会调用丰富器,这对于可能更改的值非常有用。
我们将创建一个简单的IStaticLogEnricher,将当前计算机名称添加到日志中,另外创建一个ILogEnricher,将当前用户Id添加到日志中。
- internal class MachineNameEnricher : IStaticLogEnricher
- {
- public void Enrich(IEnrichmentTagCollector collector)
- {
- collector.Add("MachineName", Environment.MachineName);
- }
- }
- internal class UserIdEnricher : ILogEnricher
- {
- public void Enrich(IEnrichmentTagCollector collector)
- {
- collector.Add("UserId", Guid.NewGuid().ToString());
- }
- }
- builder.Logging.EnableEnrichment(); // Enable log enrichment
- builder.Services.AddStaticLogEnricher<MachineNameEnricher>();
- builder.Services.AddLogEnricher<UserIdEnricher>();
