C# 为什么日志记录没有';不要使用字符串插值
我一直在跟踪,效果很好 我对这条线有个问题C# 为什么日志记录没有';不要使用字符串插值,c#,logging,.net-core,C#,Logging,.net Core,我一直在跟踪,效果很好 我对这条线有个问题 _logger.LogWarning(LoggingEvents.GetItemNotFound, "GetById({ID}) NOT FOUND", id); 我想知道他们为什么不使用 为什么扩展会有一个params对象[]argsparamater 当你可以用字符串发送所有信息时,有什么意义呢 我想这是有原因的,但我一直找不到任何解释。我想知道我应该使用哪种方法才能正确登录.NETCore 至少有两个原因 首先,记录日期早于字符串插值,微软还没
_logger.LogWarning(LoggingEvents.GetItemNotFound, "GetById({ID}) NOT FOUND", id);
我想知道他们为什么不使用
为什么扩展会有一个params对象[]args
paramater
当你可以用字符串发送所有信息时,有什么意义呢
我想这是有原因的,但我一直找不到任何解释。我想知道我应该使用哪种方法才能正确登录.NETCore 至少有两个原因
首先,记录日期早于字符串插值,微软还没有发明时间机器。字符串插值仅于2015年7月在C#6中引入,但日志记录方法遵循自dotnet framework 2.0以来在Microsoft.Build.Utilities
中使用的相同模式
第二,表现。如果使用字符串插值并将字符串作为参数传递,则插值将在调用Log
之前完成。但是,并不是每次调用日志都会导致记录某些内容,这取决于配置
如果您在DEBUG
级别记录某些内容,并且当前的配置是针对信息
级别,那么执行字符串插值是浪费时间的,您可以只说“谢谢,但不谢谢”,然后在不处理参数后立即返回
第二,性能
在内部,most记录器基本上如下所示:
void LogDebug(string Message, params object[] args){
if(this.DebugEnabled){
Log.Write(string.Format(Message,args));
}
}
// 1 with parameters
LogDebug("GetById({ID}) NOT FOUND", id);
// 2 interpolated
LogDebug($"GetById({id}) NOT FOUND");
因此,如果未启用调试,则会少执行一次插值操作。我怀疑问题可以重新表述为: 为什么不像EF Core对参数化查询所做的那样,它们不提供重载,接受使用字符串插值语法传递消息模板和参数 我得说他们是对的。此时,使用FormattableString的好处微乎其微,但会造成很多混乱 我刚刚发现,尽管语义日志库看起来很适合这种情况 语义日志记录 有人可能会认为
FormattableString
将是像Serilog这样的语义日志库的一个很好的补充。在这种情况下,插值字符串确实会丢失重要信息
电话
Log.Information("Logged in {UserId}", loggedInUserId);
它不仅基于模板记录字符串,还将保留参数的名称和值,并将它们提供给过滤器和目标。在以下情况下获得同样的结果不是很好吗
Log.Information($"Logged in {loggedInUserId}");
并解释说:
Log.Information($“启用类别{new[]{1,2,3}”)代码>
在SeriLogg的情况下,我认为将{USERID }这样的属性名看作冗余是不正确的;在一个实施良好的测井策略中,它们是画面中极其重要的一部分,值得他们自己考虑。您不会让变量名决定关系数据库中的表名和列名——这里考虑的是完全相同的权衡
原始解释 实际上,这是EF-Core最有争议的特性之一,并且很容易导致人们希望通过使用参数来避免的SQL注入和转换问题 此电话: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);
从SQL(字符串)调用,并将生成:
SELECT * FROM Customers WHERE City = London
这是无效的。即使你知道风险,落入这种陷阱也太常见了
当您已经有预定义的查询或消息时,它根本没有帮助。这种用法在日志记录中更为常见,在日志记录中,您(应该)使用在已知位置定义的特定消息模板,而不是在每个日志位置中使用外观类似的字符串
有人可能会说,因为人们已经开始在EF Core 1.0中使用字符串插值,导致查询无效。添加FormattableString
重载,EF核心团队能够缓解这种情况,同时更容易意外导致不同的问题
此时,日志设计人员决定避免这种混淆。记录原始字符串不会产生如此灾难性的后果。记录字符串插值的日期。谁会这么做?可能是因为他们想为不在C#6上的人提供支持?而且,由于现有的日志框架具有params object[]
重载,这也符合各种控制台方法的定义,例如console.WriteLine
。同样,这些方法当时没有字符串插值,只要上下文中有ID
属性或变量,字符串插值就可以工作。当然,这意味着您将丢失有关上下文、属性、变量等的所有信息,并且只有一个字符串需要解析才能找到它包含的内容。1) 为什么不只记录字符串?因为参数很重要,因为字符串实际上只是一个描述,而真正的可操作信息是类别、事件、严重性和相关性参数的一部分。日志框架可以使用这些信息来选择目标、消息字符串等。语义日志也使用这些信息。一个更重要的原因是,这不是一个好主意。EF Core对p使用字符串插值
SELECT * FROM Customers WHERE City = London