zoukankan      html  css  js  c++  java
  • C# 使用NLog记录日志

    引用:https://www.cnblogs.com/felixnet/p/5498759.html

    NLog是一个记录日志组件,和log4net一样被广泛使用,它可以将日志保存到文本文件、CSV、控制台、VS调试窗口、数据库等。最近刚用到这个组件,觉得不错,水一篇。

    下载

    通过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()方法,实际输出日志时就不需要了。

    结果:

    查看日志记录:

    nlog 的可以写在app.config 文件

    <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <variable name="logLayout" value="${time}|${assembly-version}|${pad:padding=5:inner=${level:uppercase=true}}|${pad:padding=20:inner=${logger:shortName=true}}|${message}|${exception:format=toString,Data:maxInnerExceptionLevel=1};" />
      <targets async="true">
        <target name="asyncFile" xsi:type="File" fileName="${basedir}/logfile_${shortdate}.log" layout="${logLayout}" concurrentWrites="true" keepFileOpen="false" archiveAboveSize="10240000" maxArchiveFiles="100" archiveEvery="Day" />
        <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="asyncFile" />
      </rules>
    </nlog>

  • 相关阅读:
    Windows Azure Web Site (19) Azure Web App链接到VSTS
    Windows Azure Virtual Machine (35) Azure VM通过Linked DB,执行SQL Job
    Azure PowerShell (16) 并行开关机Azure ARM VM
    Windows Azure Virtual Network (12) 虚拟网络之间点对点连接VNet Peering
    Azure ARM (21) Azure订阅的两种管理模式
    Windows Azure Platform Introduction (14) 申请海外的Windows Azure账户
    Azure ARM (20) 将非托管磁盘虚拟机(Unmanage Disk),迁移成托管磁盘虚拟机(Manage Disk)
    Azure ARM (19) 将传统的ASM VM迁移到ARM VM (2)
    Azure ARM (18) 将传统的ASM VM迁移到ARM VM (1)
    Azure Automation (6) 执行Azure SQL Job
  • 原文地址:https://www.cnblogs.com/bruce1992/p/15691969.html
Copyright © 2011-2022 走看看