Serilog仅记录数组的第一个元素

10

我正在使用Serilog 2.10.0来记录.NET 5上ASP.NET Core应用程序中的日志。当尝试记录一个只有一个参数且该参数为数组的事件时,我遇到了问题。以下是一些示例代码和带有JSON文件池的日志输出:

var myArray = new string[] { "foo", "bar" };
logger.LogInformation("Log stuff: {@MyArray}", myArray);

{"@t":"2021-02-22T14:09:46.8673482Z","@mt":"Log stuff: {@MyArray}","MyArray":"foo","SourceContext":"MyNamespace.MyClass"}
logger是通过依赖注入注入的ILogger。记录的事件只包含我的字符串数组的第一个元素。如果我添加另一个参数,则字符串数组将被正确记录。我尝试过带有和不带有@符号,以及不同的sink
这是一个带有附加参数的修改后示例,它按照我的预期工作:
var myArray = new string[] { "foo", "bar" };
logger.LogInformation("Log stuff: {baz} {@MyArray}", "baz", myArray);

{"@t":"2021-02-22T14:19:21.3580354Z","@mt":"Log stuff: {baz} {@MyArray}","baz":"baz","MyArray":["foo","bar"],"SourceContext":"MyNamespace.MyClass"}

我怀疑我对可变函数如何确定模板字符串中的参数和变量之间的映射存在误解。但我找不到一种方法来正确地处理仅带有一个数组参数的日志消息,而不添加无关的额外参数,则无法使其正常工作。
我该如何让Serilog正确处理仅带有一个数组参数的日志消息?

不确定 Serilog.Log.Information 是否存在同样的问题?如果您直接使用它,我怀疑它会被 https://github.com/Suchiman/SerilogAnalyzer 检测到。 - Ruben Bartelink
@RubenBartelink:我认为现在最好的做法是注入ILogger,但我也遇到过整个代码都依赖于Serilog的项目。BR - Roar S.
2
Serilog的日志记录器尝试避免这种情况 - https://github.com/serilog/serilog/blob/dev/src/Serilog/Core/Logger.cs#L366 - 但当事件从MEL传递时,无法检测到该情况。 - Nicholas Blumhardt
3个回答

18

我能够重现你的问题。问题被Resharper标记,如下面的截屏所示。

在此输入图片描述

如果我们查看LoggerExtensions#LogInformation的源代码,则其具有以下签名:

public static void LogInformation(this ILogger logger, string message, params object[] args)

最后一个参数是params object[] args,当传入单个数组时,该方法会将该数组视为参数列表并将其转换为object[],而您的意图是将该数组作为参数传入。通过像这样更改模板来确认:

_logger.LogInformation("Log stuff: {FirstElement} {SecondElement}", myArray); 

这将输出记录内容: foo bar。以上代码与以下代码具有相同的逻辑和行为:

_logger.LogInformation("Log stuff: {FirstElement} {SecondElement}", "foo", "bar");

将数组更改为例如列表或者像@IharYakimush建议的那样,将数组简单地转换成object,可以解决这个问题,因为现在集合会被视为一个参数,而不是参数列表。

_logger.LogInformation("Log stuff: {MyArray}", (object)myArray);

5
不需要进行不必要的列表创建。使用以下方法:_logger.LogInformation("日志内容:{MyArray}", (object)myArray); - Ihar Yakimush
@IharYakimush:谢谢,我采纳了你的建议并重新表述了我的答案。敬礼 - Roar S.
将我的参数作为“params object[] args”传递对我很有帮助。谢谢。 - Satheesh K

2
也许你可以将日志语句更改为类似以下的内容
logger.LogInformation("Log stuff: {baz} {myArrayString}", "baz",  String.Join(", ", myArray));

2
你正在使用的解构运算符 @ 可能是问题的原因。根据 Serilog 文档 https://github.com/serilog/serilog/wiki/Structured-Data#collections,这应该可以直接使用:
var fruit = new[] { "Apple", "Pear", "Orange" };
Log.Information("In my bowl I have {Fruit}", fruit);

这将产生以下JSON:
{ "Fruit": ["Apple", "Pear", "Orange"] }

所以,不需要将其转换为对象!

1
通过代码进行实时测试表明,这个建议是错误的,@操作符并不是问题的根源。文档中的集合代码示例并没有按预期工作。按照被接受的答案中描述的使用(object)转换解决了这个问题。上面链接的维基文档自2017年5月以来没有被编辑过,很可能与当前结构化日志记录集合数据的行为不同步。 - camelCase
1
@camelCase 我亲自在一个.NET 6项目中使用Serilog.AspNetCore 6.1.0测试了上述代码,实际上它并不按照描述/预期的方式工作。经过一番尝试,我发现以下代码可以正常工作:List<string> fruit = new List<string> { "Apple", "Pear", "Orange" }; Log.Information("在我的碗里有{Fruit}", fruit);我将编辑我的回答,谢谢! - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接