搬运NLog

搬运NLog

原文  http://www.cnblogs.com/tongyi/p/NLog.html

targets:输出目标节点

target:配置一个输出目标

Type输出类型:

  •   Console        输出到控制台
  •   Debugger     输出到VS输出窗口
  •   File        输出到文件
  •   Mail        输出为邮件发送
  •   Network        输出到网络地址
  •   Database        输出到数据库

 

具体参数说明:

layout – 日志呈现的文本内容。默认为:

 ${longdate}|${level:uppercase=true}|${logger}|${message}

 

lineEnding – 行结束模式。

可选值:

  •   CR – 在每尾部插入回车符号(ASCII 13)。
  •   CRLF – 在每行尾部插入回车和换行符号(ASCII 13 & ASCII 10)。
  •   Default – 在每行尾部插入平台相关的行结束符号(默认)。
  •   LF - 在每行尾部插入换行符号(ASCII 10)。
  •   None – 不插入任何行结束符号。

 

archiveAboveSize – 存档上限值。当日志文件大于此值是,将自动存档。其类型为Long。

注意:在多进程并发记录日志的情况下,启用该选项可能会大幅降低日志记录速度。在单进程时,为了达到最佳性能,可以考虑设置ConcurrentWrites为false。

 

archiveEvery – 是否在每个设定时间刻自动存档日志文件。

可选值:

  • Day – 每日存档。
  • Hour – 每小时存档。
  • Minute – 每分钟存档。
  • Month – 每月存档。
  • None – 不按时间固定存档。
  • Year – 每年存档。

备注:作为写日志的一部分,文件移动到存档位置的操作发生的时间变换时刻。例如,当前时间从10点变至11点,则当在写第11点或11点之后的第一个写操作时,触发日志文件归  档。

注意:在多进程并发记录日志的情况下,启用该选项可能会大幅降低日志记录速度。在单进程时,为了达到最佳性能,可以考虑设置ConcurrentWrites为false。

 

filename – 写入日志的文件名称。支持Layout。

备注:文件名字符串中可能包含布局呈现器中的实例变量。这样可以通过配置单个目标节点,而将日志写入多个文件中。

以下fileName属性值将使得NLog在应用程序启动目录下,根据日志级别不同,将日志信息写到不同的文件中。

${basedir}/${level}.log

因此,所有的Debug级别日志写入到Debug.log文件中,所有的Info级别日志写入到Info.log文件中,其它以此类推。同时,也可以结合其它布局呈现器实例,组成所要的日志文件名称。

 

 deleteOldFileOnStartUp – 启动时,是否删除旧的日志文件。其取值类型为Boolean,默认为false。

备注:此选项,仅在“fileName”参数为单个文件时有效。

 

性能优化选项

 concurrentWirtes – 是否允许使用通过多个进程的方式,将日志信息并行写入文件中。其取值类型为Boolean,默认为true。

备注:这使得多进程记录日志成为可能。NLog使用一种特别的技术使用文件保持打开状态以备写入。

 openFileCacheTimeout – 文件保持打开状态的最大时间秒数。如果这个数字为负数,则在一定不活动时间后,文件不会自动关闭。其取值类型为Integer,默认值为-1。(即默 认状态下文件始终处于打开状态以备写入。)

openFileCacheSize – 保持打开状态的文件数量。当通过设置单个文件类型目标,且结果写入多个不同文件(如根据日志等级或日志对象名称)时,则可将此属性设置为一个较 高的值以改善性能。其取值类型为Integer,默认值为5。

备注:这些文件是在最近最少使用算法基础管理的,此算法在缓存空间不足时将最长时间内没有使用的文件Flush。一般来说,不应当把此参数设置过大,最好不要超过10-15,这是因同时保持多个文件处于打开状态,对系统资源来说是一个很大的消耗。

networkWrites – 是否通过多线程由不同的网络主机并行向文件中写入日志。其取值类型为Boolean,默认值为false。

备注:通过此此种方式,可以有效阻止文件长期保存为打开状态。

concurrentWriteAttemptDelay – 在再次尝试将日志写入文件之前延迟的毫秒数。其取值类型为Integer,默认值为1。

备注:实际的延迟时间,是一个介于0到指定参数值之间的随机整数,且在每次尝试失败之后,都会将此参数加倍。假使此参数值为10,则第一次重试写入 的延迟时间(毫秒数)在 0-10之间的一个随机数,第二次重试时为0-20之间的一个随机数,第三次重试时为0-40之间的一个随机数,第四次重试时为0-80之间的一个随机数 等等,以此类推。

concurrentWriteAttempts – 在NLog丢弃日志信息之前的追加(尝试重写)写次数。其取值类型为Integer,默认值为10。

bufferSize – 日志文件缓存区大小(单位:字节)。其取值类型为Integer,默认值为32768(32KB)。

autoFlush – 在每次日志信息后,是否自动刷新文件缓存区。其取值类型为Boolean,默认值为true。

keepFileOpen – 是否保持日志文件处于打开状态,以代替其在每次日志写事件发生时频繁打开和关闭。其取值类型为Boolean,默认值为false。

备注:设置此属性为true,有助于提高性能。


 

下载

通过Nuget安装NLog,你也可以同时安装NLog.Config,它会在项目目录下帮你建立一个配置文件NLog.config,不过不需要,我们直接手动建立一个,你也可以将配置的信息写入到 App.config/Web.config,我比较喜欢独立出来,不与其它配置掺和在一起。

 

配置

在项目根目录下新建一个NLog.config,基本目录结构:targets下面配置日志输出目标及相关参数,rules下面配置目标输出规则。

1
2
3
4
5
6
7
8
9
10
11
<?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
        5000 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)配置 internalLogLevel, internalLogFile,可以查看NLog输出日志时的内部信息,比如你配置文件有错误,很有帮助,不过项目发布后还是关闭比较好,以免影响效率;
  • 在target外面罩了一个 <target>并且xsi:type为 AsyncWrapper,即表示这条 target 将异步输出,这里我将文件和数据库日志异步输出;
  • db target内指定了数据库连接字符串 connectionString,SQL语句,SQL参数,还可以指定数据库/表创建和删除的脚本(推荐看NLog源码示例,这里不介绍),同时我们自定义了2个参数 action和amount;
  • target参数里有些是NLog内置参数,比如message,level,date,longdate,exception,stacktrace等,NLog在输出时会自动赋值;
  • layout设置了每条日志的格式;
  • 在rules节点,我们分别指定了三个target输出日志的级别,NLog用于输出日志的级别包括:Trace,Debug,Info,Warn,Error,Fatal,可以设置 minlevel设置最小级别,也可以用 levels定义你所有需要的级别(多个用逗号分隔)。

 

封装

简单两句就可以使用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;
        }
    }
复制代码
  • Models.Log是我们项目里的日志对象,它对应一个数据表Log,NLog将日志数据写入到这个表;
  • Process(Models.Log)是我们处理自定义对象的日志方法,用LogEventInfo来写入;
  • 重写 LogEventInfo.ToString() 是因为 LogEventInfo的Message格式是“Log Event: Logger='XXX' Level=Info Message='XXX' SequenceID=5”,不便于查阅,我们只需要我们设置的Message。

 

使用:

下面是测试方法,我们一共输出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()方法,实际输出日志时就不需要了。

 

结果:

查看日志记录:


全部评论

相关推荐

评论
点赞
收藏
分享

全站热榜

更多

创作者周榜

更多
正在热议
更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务