NLog是一個記錄日志組件,和log4net一樣被廣泛使用,它可以將日志保存到文本文件、CSV、控制台、VS調試窗口、數據庫等。最近剛用到這個組件,覺得不錯,水一篇。
下載
通過Nuget安裝NLog,你也可以同時安裝NLog.Config,它會在項目目錄下幫你建立一個配置文件NLog.config,不過不需要,我們直接手動建立一個,你也可以將配置的信息寫入到 App.config/Web.config,我比較喜歡獨立出來,不與其它配置摻和在一起。

配置
在項目根目錄下新建一個NLog.config,基本目錄結構:targets下面配置日志輸出目標及相關參數,rules下面配置目標輸出規則。
<?xml version="1.0" ?> <nlog> <targets> <target></target> <target></target> </targets> <rules> <logger></logger> <logger></logger> </rules> </nlog>
記得在NLog.config的屬性中設置 Copy to Output Directory: Copy always

現在我們要將日志輸出到文本文件,數據庫,VS調試窗口,完整配置文件如下:
<?xml version="1.0" ?>
<!--<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogLevel="Trace"
internalLogFile="D:\work\log.txt">-->
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true">
<targets>
<!-- Log in a separate thread, possibly queueing up to
messages. When the queue overflows, discard any
extra messages-->
<!-- write logs to file -->
<target name="file" xsi:type="AsyncWrapper" queueLimit="5000" overflowAction="Discard">
<target xsi:type="File" fileName="${basedir}/logs/${shortdate}.log" layout="${longdate} ${level:uppercase=true} ${event-context:item=Action} ${message} ${event-context:item=Amount} ${stacktrace}" />
</target>
<!-- write log message to database -->
<target name="db" xsi:type="AsyncWrapper" queueLimit="5000" overflowAction="Discard">
<target type="Database" dbProvider="mssql" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=EFinance;Persist Security Info=True;User ID=sa;Password=123456;">
<commandText>
INSERT INTO Log(Timestamp,Level,Message,Action,Amount,StackTrace) VALUES(@time_stamp, @level, @message, @action, @amount, @stacktrace);
</commandText>
<!-- database connection parameters -->
<parameter name="@time_stamp" layout="${date}" />
<parameter name="@level" layout="${level:uppercase=true}" />
<parameter name="@message" layout="${message}" />
<parameter name="@action" layout="${event-context:item=Action}" />
<parameter name="@amount" layout="${event-context:item=Amount}" />
<parameter name="@stacktrace" layout="${stacktrace}" />
</target>
</target>
<!--write log message to Visual Studio Output-->
<target name="debugger" xsi:type="Debugger" layout="NLog: ${date:format=HH\:mm\:ss} | ${level:uppercase=true:padding=-5} | ${message}" />
</targets>
<rules>
<!--TRACE,DEBUG,INFO,WARN,ERROR,FATAL-->
<logger name="*" minlevel="Trace" writeTo="debugger" />
<!--INFO,WARN,ERROR,FATAL-->
<logger name="*" minlevel="Info" writeTo="db" />
<!--DEBUG,INFO,WARN,ERROR,FATAL-->
<logger name="*" minlevel="Debug" writeTo="file" />
</rules>
</nlog>
封裝
簡單兩句就可以使用NLog了:
NLog.Logger logger = Nlog.LogManager.GetCurrentClassLogger();
logger.Fatal("發生致命錯誤");
logger.Warn("警告信息");
但是這樣只能記錄了NLog的內置字段,我們定義的 Amount, Action都不能寫入,接下來我們來封裝一個Logger:
public class Logger
{
NLog.Logger _logger;
private Logger(NLog.Logger logger)
{
_logger = logger;
}
public Logger(string name) : this(LogManager.GetLogger(name))
{
}
public static Logger Default { get; private set; }
static Logger()
{
Default = new Logger(NLog.LogManager.GetCurrentClassLogger());
}
#region Debug
public void Debug(string msg, params object[] args)
{
_logger.Debug(msg, args);
}
public void Debug(string msg, Exception err)
{
_logger.Debug(err, msg);
}
#endregion
#region Info
public void Info(string msg, params object[] args)
{
_logger.Info(msg, args);
}
public void Info(string msg, Exception err)
{
_logger.Info(err, msg);
}
#endregion
#region Warn
public void Warn(string msg, params object[] args)
{
_logger.Warn(msg, args);
}
public void Warn(string msg, Exception err)
{
_logger.Warn(err, msg);
}
#endregion
#region Trace
public void Trace(string msg, params object[] args)
{
_logger.Trace(msg, args);
}
public void Trace(string msg, Exception err)
{
_logger.Trace(err, msg);
}
#endregion
#region Error
public void Error(string msg, params object[] args)
{
_logger.Error(msg, args);
}
public void Error(string msg, Exception err)
{
_logger.Error(err, msg);
}
#endregion
#region Fatal
public void Fatal(string msg, params object[] args)
{
_logger.Fatal(msg, args);
}
public void Fatal(string msg, Exception err)
{
_logger.Fatal(err, msg);
}
#endregion
#region Custom
public void Process(Models.Log log)
{
var level = LogLevel.Info;
if (log.Level == Models.EFLogLevel.Trace)
level = LogLevel.Trace;
else if (log.Level == Models.EFLogLevel.Debug)
level = LogLevel.Debug;
else if (log.Level == Models.EFLogLevel.Info)
level = LogLevel.Info;
else if (log.Level == Models.EFLogLevel.Warn)
level = LogLevel.Warn;
else if (log.Level == Models.EFLogLevel.Error)
level = LogLevel.Error;
else if (log.Level == Models.EFLogLevel.Fatal)
level = LogLevel.Fatal;
var ei = new MyLogEventInfo(level, _logger.Name, log.Message);
ei.TimeStamp = log.Timestamp;
ei.Properties["Action"] = log.Action;
ei.Properties["Amount"] = log.Amount;
_logger.Log(level, ei);
}
#endregion
/// <summary>
/// Flush any pending log messages (in case of asynchronous targets).
/// </summary>
/// <param name="timeoutMilliseconds">Maximum time to allow for the flush. Any messages after that time will be discarded.</param>
public void Flush(int? timeoutMilliseconds = null)
{
if (timeoutMilliseconds != null)
NLog.LogManager.Flush(timeoutMilliseconds.Value);
NLog.LogManager.Flush();
}
}
public class MyLogEventInfo : LogEventInfo
{
public MyLogEventInfo() { }
public MyLogEventInfo(LogLevel level, string loggerName, string message) : base(level, loggerName, message)
{ }
public override string ToString()
{
//Message format
//Log Event: Logger='XXX' Level=Info Message='XXX' SequenceID=5
return FormattedMessage;
}
}
public class Log : IEntityBase<long>
{
public long Id { get; set; }
/// <summary>
/// 日志級別 Trace|Debug|Info|Warn|Error|Fatal
/// </summary>
public string Level { get; set; }
public string Message { get; set; }
public string Action { get; set; }
public string Amount { get; set; }
public string StackTrace { get; set; }
public DateTime Timestamp { get; set; }
private Log() { }
public Log(string level, string message, string action = null, string amount = null)
{
this.Level = level;
this.Message = message;
this.Action = action;
this.Amount = amount;
}
}
使用:
下面是測試方法,我們一共輸出9條日志,這9條日志將輸出到哪個目標,由配置文件中的Rules/logger決定
Logger.Default.Trace("Hello World! Trace");
Logger.Default.Info("Hello World! Info");
Logger.Default.Warn("Hello World! Warn");
Logger.Default.Debug("Hello World! Debug");
Logger.Default.Error("Hello World! Error");
Logger.Default.Fatal("Hello World! Fatal");
Logger.Default.Process(new Models.Log(Models.EFLogLevel.Info, "Hello World! Info", "TEST", "100.00"));
Logger.Default.Process(new Models.Log(Models.EFLogLevel.Debug, "Hello World! Debug", "TEST", "100.00"));
Logger.Default.Process(new Models.Log(Models.EFLogLevel.Error, "Hello World! Error", "TEST", "100.00"));
Logger.Default.Flush();
因為我們在Target中設置了異步,所以如果我們想當場看到輸出結果,就需要使用Flush()方法,實際輸出日志時就不需要了。
結果:
查看日志記錄:

