ASP.NET 带有 Func() 参数的核心日志记录
ASP.NET Core Logging with Func() argument
我将 ASP.NET 核心与 NLog 一起使用,将其用作带有 NLog.Web.AspNetCore 金块包的原始 ASP.NET 核心记录器的替代品。
NLog 包含一个有用的 Func() 委托签名,仅当启用相应的日志记录级别时才允许执行参数评估:
static readonly Logger log = LogManager.GetCurrentClassLogger();
log.Trace(() => request.JsonSerializer.Serialize(body));
我正在使用 ASP.NET 和 NLog,但听起来这个功能不可用:
private ILogger<MyController> log;
log.Trace(() => request.JsonSerializer.Serialize(body));
在着手给自己写一个方法之前,我想知道我是否遗漏了什么,我没有找到任何关于使用 ASP.NET Core with NLog 的委托参数的日志记录方法。
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()
时执行该函数。
Asp.net 核心 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;
}
}
我将 ASP.NET 核心与 NLog 一起使用,将其用作带有 NLog.Web.AspNetCore 金块包的原始 ASP.NET 核心记录器的替代品。
NLog 包含一个有用的 Func() 委托签名,仅当启用相应的日志记录级别时才允许执行参数评估:
static readonly Logger log = LogManager.GetCurrentClassLogger();
log.Trace(() => request.JsonSerializer.Serialize(body));
我正在使用 ASP.NET 和 NLog,但听起来这个功能不可用:
private ILogger<MyController> log;
log.Trace(() => request.JsonSerializer.Serialize(body));
在着手给自己写一个方法之前,我想知道我是否遗漏了什么,我没有找到任何关于使用 ASP.NET Core with NLog 的委托参数的日志记录方法。
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()
时执行该函数。
Asp.net 核心 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;
}
}