C# 消息模板中未使用的属性的Serilog字段名称

C# 消息模板中未使用的属性的Serilog字段名称,c#,logging,serilog,C#,Logging,Serilog,我正在测试Serilog,在字段名方面遇到了一些问题 我想添加日志条目,其中一个字段包含在消息模板中,另一个字段仅存储在日志中,用于查询 我想做一些简单的事情,比如: logger.Debug("Recalculation performed for operation {OperationId}", operationId, operationTypeId, otherId, anotherId); 但这会导致字段名不具有友好名称,因为它们不在消息模板中:

我正在测试Serilog,在字段名方面遇到了一些问题

我想添加日志条目,其中一个字段包含在消息模板中,另一个字段仅存储在日志中,用于查询

我想做一些简单的事情,比如:

logger.Debug("Recalculation performed for operation {OperationId}", 
                operationId, operationTypeId, otherId, anotherId);
但这会导致字段名不具有友好名称,因为它们不在消息模板中:

{
   "@timestamp":"2016-10-20T16:57:02.0623798+01:00",
   "level":"Debug",
   "messageTemplate":"Recalculation performed for operation {OperationId}",
   "fields":{  
      "OperationId":1024,
      "__1":16,
      "__2":32,
      "__3":256,
      "SourceContext":"SerilogTest.Worker"
   }
}
我知道我可以将所有字段放入一个类中,并使用ForContext方法将它们包含在日志条目中:

internal class OperationData
{
    public int OperationId { get; set; }

    public int OperationTypeId { get; set; }

    public int OtherId { get; set; }

    public int AnotherId { get; set; }
}

var operationData = new OperationData
                {
                    OperationId = 1024,
                    OperationTypeId = 16,
                    OtherId = 32,
                    AnotherId = 256
                };

var operationLogger = logger.ForContext("OperationData", 
                        operationData, destructureObjects: true);
operationLogger.Debug("Recalculation performed for operation {OperationId}",
                         operationData.OperationId);
这让我得到了我想要的结果:

{
   "@timestamp":"2016-10-20T18:00:35.4956991+01:00",
   "level":"Debug",
   "messageTemplate":"Recalculation performed for operation {OperationId}",
   "fields":{  
      "OperationId":1024,
      "OperationData":{  
         "_typeTag":"RecalulationResult",
         "OperationId":1024,
         "OperationTypeId":16,
         "OtherId":32,
         "AnotherId":256
      },
      "SourceContext":"SerilogTest.Worker"
   }
}

但是,仅仅为了拥有友好的字段名,似乎需要付出很多努力。我必须创建一个新的logger实例,创建一个包含日志消息所有相关字段的类型,然后执行日志。有没有比这更简单的字段命名方法?

匿名类型可以用更少的代码实现上述功能:

logger
    .ForContext("Operation", new {operationTypeId, otherId, anotherId}, true)
    .Debug("Recalculation performed for operation {OperationId}", operationId);
或者,也可以包括事件中的所有内容:

logger.Debug("Recalculation performed for operation {@Operation}", new {
        Id = operationId, TypeId = operationTypeId, OtherId = otherId, 
        AnotherId = anotherId
    });
如果您发现有许多消息希望包含相同的属性,那么最好将它们推到
LogContext

using (LogContext.PushProperty("OperationId", operationId))
{
    logger.Debug("Recalculation performed");

    // ...etc...

    logger.Debug("Something else");
}

在这种情况下,两个事件都将有一个与之关联的
操作ID
。您可以将多个属性推送到日志上下文中。只需确保将
Enrich.FromLogContext()
添加到
LoggerConfiguration
即可使用此样式。

我曾假设匿名类型无法工作,因为Serilog必须使用反射,并且反射不能很好地与匿名类型配合使用。我将尝试一下。@GlenThomas Reflection对匿名类型非常有效。。有哪些具体问题?@user2864740我过去在使用基于反射的库(例如带有匿名类型的Dapper)时遇到过问题。可能它是.NET framework的旧版本,但我确信当类型为匿名时,该类型的属性元数据不可用或减少。