问题
I am using ASP.NET core with NLog, using it as a replacement for the original ASP.NET Core logger with the NLog.Web.AspNetCore nugget package.
NLog contains a useful Func() delegate signature that allows to performs arguments evaluation only if the corresponding logging level is enabled:
static readonly Logger log = LogManager.GetCurrentClassLogger();
log.Trace(() => request.JsonSerializer.Serialize(body));
I am using ASP.NET with NLog, but it sounds like this feature is not available:
private ILogger<MyController> log;
log.Trace(() => request.JsonSerializer.Serialize(body));
Before undertaking to write myself a method, I would like to know if I missed something, I have not find anything about such logging methods with a delegate argument using ASP.NET Core with NLog.
回答1:
There is no such thing in the Microsoft.Extensions.Logging abstractions, and the way it is built, it isn’t exactly easy to do such a thing. While you can easily add extension methods to it, and actually all log calls are extension methods, the base Log
method is what determines whether or not to log somethings since it is the only thing that actually has access to the configured log level.
That being said, the logging abstractions to use something that may make it possible to do something similar to this. For that, consider the signature of the ILogger.Log
method:
void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
As you can see, there isn’t actually a string being passed to it, but just a state
and a formatter
. In the default extension methods, the state is a FormattedLogValues
object and the formatter is just a method that calls ToString()
on the state, i.e. the FormattedLogValues
object.
The FormattedLogValues
is what actually builds the formatted string, and that’s also where the structured logging is happening. So it is actually a bad idea to serialize some object in your log message; you can just pass that directly to the logger.
But what you could do here is provide your own overloads to Log
that take a function instead which is then wrapped into some state object that executes the function when ToString()
is being called.
回答2:
There is not much change in Nlog Implementation for Asp.net core 2.0.
Setup 1: you need to install Nuget package Click here
Setup 2: you need to create Nlog config file with below configuration.
<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>
Setup 3: Need to update Startup file.
NLog.GlobalDiagnosticsContext.Set("defaultConnection", Connection string); NLog.LogManager.LoadConfiguration(env.ContentRootPath + "\\NLog.config");
Setup 4: We have created custom Nlog manager.
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);
}
}
Custom Event parameter for logging :
private static void SetLogEventInfo(LogEventInfo theEvent, NLogData nLogData) {
theEvent.Properties["SessionId"] = nLogData.SessionId;
theEvent.Properties["BrowserDetail"] = nLogData.BrowserDetail;
}
Model for NLog logging.
public class NLogData {
public string SessionId {
get;
set;
}
public string BrowserDetail {
get;
set;
}
}
来源:https://stackoverflow.com/questions/51238835/asp-net-core-logging-with-func-argument