c# - 为什么 Logging 不使用字符串插值

标签 c# logging .net-core

我一直在关注Logging in ASP.NET Core哪个工作正常。

我对这条线有疑问

_logger.LogWarning(LoggingEvents.GetItemNotFound, "GetById({ID}) NOT FOUND", id);

我想知道为什么他们不使用 $ - string interpolation

_logger.LogWarning(LoggingEvents.GetItemNotFound, $"GetById({ID}) NOT FOUND");

为什么 LogWarning扩展有一个 params object[] args 参数?

当您可以将所有内容都发送到字符串消息中时,有什么意义呢?

我认为这是有原因的,但我无法在任何地方找到解释。我想知道我应该使用哪种方法才能正确登录 .net 核心。

最佳答案

我怀疑这个问题可以改写为:

Why didn't they provide overloads that accept a FormattableString to pass message templates and parameters using string interpolation syntax, like EF Core does for parameterized queries?

我会说他们做对了。 此时使用 FormattableString 的好处微乎其微,但会造成很多困惑。

我刚发现 Serilog's author explains why this isn't such a good idea尽管语义日志库看起来很适合这种情况

语义日志记录

可以说 FormattableString 将是 Serilog 等语义日志库的一个很好的补充。在这种情况下,内插字符串确实丢失了重要信息。

电话

Log.Information("Logged in {UserId}", loggedInUserId);

不会只记录基于模板的字符串,它会保留参数的名称和值并将它们提供给过滤器和目标。用 :

获得相同的结果不是很好吗?
Log.Information($"Logged in {loggedInUserId}");

Serilog's author doesn't think so并解释说:

  1. 好的变量名不一定是好的属性名
  2. 漏洞并不总是有明显的名称,例如 Log.Information($"Enabling categories {new[]{1, 2, 3}}");

并得出结论

String interpolation is a great feature, one I’ve looked forward to in C# for a long time. The idea of providing direct support for Serilog is a very interesting one and worth exploring, but I’m increasingly convinced it’s unnecessary.

Interpolation is nice when it keeps code DRY, cutting out the redundant clutter of {0} and {1} and preventing parameter mismatches.

In the case of Serilog, I think it’s incorrect to consider the property names like {UserId} as redundant; in a well-implemented logging strategy they’re an incredibly important part of the picture that deserve their own consideration. You wouldn’t let variable names determine the table and column names in a relational database – it’s exactly the same trade-off being considered here.

原文解释

这实际上是 EF Core 最具争议的功能之一,并且很容易导致人们希望通过使用参数来避免的 SQL 注入(inject)和转换问题。

这个电话:

string city = "London";
var londonCustomers = context.Customers
    .FromSql($"SELECT * FROM Customers WHERE City = {city}");

调用 FromSql(FormattableString) 并将创建一个参数化查询:

SELECT * FROM Customers WHERE City = @p0

并将London作为参数值传递。

另一方面:

string city = "London";
var query=$"SELECT * FROM Customers WHERE City = {city}";
var londonCustomers = context.Customers.FromSql(query);

调用 FromSql(string) 并生成:

SELECT * FROM Customers WHERE City = London

这是无效的。即使您确实知道风险,落入这个陷阱也太常见了。

当您已经有预定义的查询或消息时,它根本无济于事。这种用法在日志记录中更为常见,您(应该)使用在众所周知的位置定义的特定消息模板,而不是在每个日志位置散布看起来相似的字符串。

有人可能会争辩说 this addition made EF Core 2.0 somewhat safer因为人们已经开始在 EF Core 1.0 中使用字符串插值,导致查询无效。添加 FormattableString 重载后,EF Core 团队能够缓解那种场景,同时更容易意外导致不同的问题。

此时日志设计者决定避免这种混淆。记录原始字符串不会造成如此灾难性的后果。

关于c# - 为什么 Logging 不使用字符串插值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52200484/

相关文章:

linux - 在日志文件中与脚本 shell (linux 批处理)和重定向融洽相处

c++ - Boost Log Formatter 使用与关键字相同的字符串

.net-core - .NET Core/Standard .csproj 文件,嵌入许可证文件而不将其添加到使用包的项目中?

c# - 使用 xUnit 和 asp.net core 测试我的服务

c# - OpenXML SpreadsheetML 横向文本

c# - 发送http post请求返回部分结果

c# - 检测 XML 的更好方法?

c# - 如何一次性删除通用列表中的所有空元素?

apache-flex - 使用 flex 进行集中式日志记录

c# - 具有Docker容器的MVC Net Core的好处