Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/logging/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么日志记录没有';不要使用字符串插值_C#_Logging_.net Core - Fatal编程技术网

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}”)
  • 并得出结论

    字符串插值是一个很好的特性,我在C#中期待已久。为Serilog提供直接支持的想法非常有趣,值得探索,但我越来越相信这是没有必要的

    当插值保持代码干燥时,它很好,可以消除{0}和{1}的冗余杂波,并防止参数不匹配

    在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