【问题标题】:ASP.NET Core Logging with Func() argument带有 Func() 参数的 ASP.NET Core 日志记录
【发布时间】:2018-07-09 05:41:56
【问题描述】:

我正在使用带有 NLog 的 ASP.NET 核心,将其用作带有 NLog.Web.AspNetCore 块包的原始 ASP.NET Core 记录器的替代品。

NLog 包含一个有用的 Func() 委托签名,它允许仅在启用相应的日志记录级别时执行参数评估:

static readonly Logger log = LogManager.GetCurrentClassLogger();
log.Trace(() => request.JsonSerializer.Serialize(body));

我正在使用带有 NLog 的 ASP.NET,但听起来此功能不可用:

private ILogger<MyController> log;
log.Trace(() => request.JsonSerializer.Serialize(body));

在着手为自己编写一个方法之前,我想知道我是否遗漏了什么,我还没有找到关于使用带有 NLog 的 ASP.NET Core 的委托参数的此类日志记录方法的任何信息。

【问题讨论】:

    标签: c# logging asp.net-core nlog


    【解决方案1】:

    在 Microsoft.Extensions.Logging 抽象中没有这样的东西,而且它的构建方式,做这样的事情并不容易。虽然您可以轻松地为其添加扩展方法,并且实际上所有日志调用都是扩展方法,但基本的 Log 方法决定是否记录某些内容,因为它是唯一真正具有访问配置的日志级别。

    话虽这么说,日志抽象使用一些东西可能会做类似的事情。为此,请考虑ILogger.Log 方法的签名:

    void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
    

    如您所见,实际上并没有传递给它的字符串,而只是一个state 和一个formatter。在默认扩展方法中,状态是FormattedLogValues 对象,格式化程序只是在状态上调用ToString() 的方法,即FormattedLogValues 对象。

    FormattedLogValues 是实际构建格式化字符串的地方,这也是结构化日志记录发生的地方。因此,序列化日志消息中的某些对象实际上是一个坏主意;您可以直接将其传递给记录器。

    但是您可以在此处为Log 提供您自己的重载,该重载采用一个函数,然后将其包装到某个状态对象中,该状态对象在调用ToString() 时执行该函数。

    【讨论】:

    • 为 Log 提供一个新的重载通常是 NLog.Web.AspNetCore 包可以实现的。我本可以尝试拉取有关它的请求,但是包装我自己的扩展方法要快得多。非常感谢您的宝贵意见!
    【解决方案2】:

    Asp.net core 2.0 的 Nlog 实现没有太大变化。

    设置1:需要安装Nuget包Click here

    设置 2:您需要使用以下配置创建 Nlog 配置文件。

    <nlog>
    
      <!-- the targets to write to -->
    
       <targets>
        <!-- write logs to file  -->
        <target filename="${basedir}/logs/${shortdate}.log" layout="            
                 -----------Time Stamp: ${longdate}----------              
                 Log Level: ${level}${newline}                        
                 Logger Name : ${logger}${newline}            
                 Log Message : ${message}${newline}            
                 Exception Message: ${event-context:item=ErrorMessage}${newline}      
                 Browser Detail:  ${event-context:item=BrowserDetail}${newline}              
                 Session Id: ${event-context:item=SessionId}" name="file" xsi:type="File">
    
     <target br="" connectionstring="${gdc:item=defaultConnection}" dbprovider="Oracle.ManagedDataAccess.Client.OracleConnection, 
     Oracle.ManagedDataAccess, Version=2.0.12.0, Culture=neutral, PublicKeyToken=89b483f429c47342" keepconnection="false" name="database" xsi:type="Database"> 
     commandText="INSERT INTO TableName (LOG_LEVEL,LOGGER_NAME,SESSION_ID,BROWSER_DETAIL) values(:LOGLEVEL,:LOGGERNAME,:SESSIONID,:BROWSERDETAIL)">
          <parameter layout="${level:uppercase=true}" name="LOGLEVEL">
          <parameter layout="${logger}" name="LOGGERNAME">
          <parameter layout="${event-context:item=SessionId}" name="SESSIONID">
          <parameter layout="${event-context:item=BrowserDetail}" name="BROWSERDETAIL">
        </parameter></parameter></parameter></parameter></target>
      </target></targets>
    
       <rules>
        <!--All logs, including from Microsoft-->
        <logger minlevel="Error" name="*" writeto="file">
        <logger minlevel="Trace" name="*" writeto="database">
        <!--Skip non-critical Microsoft logs and so log only own logs-->
        <logger final="true" maxlevel="Info" name="Microsoft.*">
        <!-- BlackHole -->
      </logger></logger></logger></rules>
    </nlog>
    

    设置 3:需要更新启动文件。

    NLog.GlobalDiagnosticsContext.Set("defaultConnection", Connection string);    NLog.LogManager.LoadConfiguration(env.ContentRootPath + "\\NLog.config");
    

    设置 4:我们创建了自定义 Nlog 管理器。

    public static class NLogManager {
    
     public static ILogger _logger = NLog.LogManager.GetCurrentClassLogger();
    
     public static void InfoLog(NLogData nLogData) {
      LogEventInfo theEvent = new LogEventInfo(LogLevel.Info, NLogManager._logger.Name, nLogData.Message);
      SetLogEventInfo(theEvent, nLogData);
      _logger.Log(theEvent);
     }
    
    
     public static void DebugLog(NLogData nLogData) {
      LogEventInfo theEvent = new LogEventInfo(LogLevel.Debug, NLogManager._logger.Name, nLogData.Message);
      SetLogEventInfo(theEvent, nLogData);
      _logger.Log(theEvent);
     }
    
    
     public static void ErrorLog(NLogData nLogData) {
      LogEventInfo theEvent = new LogEventInfo(LogLevel.Error, NLogManager._logger.Name, nLogData.Message);
      SetLogEventInfo(theEvent, nLogData);
      _logger.Log(theEvent);
     }
    }
    

    用于记录的自定义事件参数:

    private static void SetLogEventInfo(LogEventInfo theEvent, NLogData nLogData) {
     theEvent.Properties["SessionId"] = nLogData.SessionId;
     theEvent.Properties["BrowserDetail"] = nLogData.BrowserDetail;
    }
    

    NLog 日志记录模型。

    public class NLogData {
     public string SessionId {
      get;
      set;
     }
     public string BrowserDetail {
      get;
      set;
     }
    }
    

    【讨论】:

    • 尽管它实际上并不能像 NLog.Web.AspNetCore 那样真正替代 ASP.Net Core 日志引擎,但无论如何这是一个关于如何包装 NLog 的好例子。谢谢你。
    猜你喜欢
    • 1970-01-01
    • 2016-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多