简介

NLog 是一个灵活且高性能的日志记录库,专为 .NET 平台设计。它允许开发者在应用程序中轻松地记录日志,并将日志输出到多种目标(如文件、数据库、控制台、邮件等)。NLog 以其配置简单、扩展性强和高性能著称,是 .NET 开发中最流行的日志记录库之一。

特点

  1. 高性能:NLog 经过优化,能够在高负载环境下高效记录日志。

  2. 灵活的配置:支持通过代码或配置文件(如 XML)进行配置。

  3. 多种日志目标:支持将日志输出到文件、数据库、控制台、邮件、网络等多种目标。

  4. 强大的日志格式控制:支持自定义日志格式,包括时间、日志级别、线程 ID、调用方法等信息。

  5. 日志过滤:可以根据日志级别、日志来源等条件过滤日志。

  6. 异步日志记录:支持异步日志记录,减少对主线程性能的影响。

  7. 跨平台:支持 .NET Framework、.NET Core、.NET 5/6/7 以及 Xamarin 等平台。

使用

  1. 安装 NLog

    通过 NuGet 安装 NLog

    dotnet add package NLog
    

    或者使用 NuGet 包管理器搜索并安装 NLog​。

  2. 配置 NLog

    NLog 支持通过代码或配置文件进行配置。推荐使用配置文件(NLog.config​),因为它更灵活且易于维护。

    在项目中添加 NLog.config​ 文件:

    <?xml version="1.0" encoding="utf-8" ?>
    <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          autoReload="true"
          throwConfigExceptions="true">
    	<targets>
    		<!-- 输出到控制台 -->
    		<target name="console" xsi:type="ColoredConsole" layout=">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ${newline}${longdate} ${level:uppercase=true} ${newline}Message:${message}${newline}Exception: ${exception:format=ToString}" />
    
    		<!-- 输出到文件 -->
    		<target name="errorfile" xsi:type="File" fileName="Logs/${shortdate}.log" archiveEvery="Day" archiveNumbering="Rolling" maxArchiveFiles="7" concurrentWrites="true" keepFileOpen="false"
    				layout=">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ${newline}${longdate} ${level:uppercase=true} [${machinename}] ${newline}Namespace:${event-properties:item=Namespace} ${newline}Class:${event-properties:item=Class} ${newline}Method:${event-properties:item=Method} ${newline}Message:${message} ${newline}Stacktrace:${stacktrace} ${newline}Exception: ${exception:format=ToString}" />
    
    		<target name="infofile" xsi:type="File" fileName="Logs/${shortdate}.log" archiveEvery="Day" archiveNumbering="Rolling" maxArchiveFiles="7" concurrentWrites="true" keepFileOpen="false"
    			    layout=">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ${newline}${longdate} ${level:uppercase=true} [${machinename}] ${newline}Message:${message}" />
    	</targets>
    
    	<rules>
    		<!-- 将所有日志输出到控制台 -->
    		<logger name="*" minlevel="Debug" writeTo="console" />
    
    		<logger name="*" minlevel="Debug" maxlevel="Warn" writeTo="infofile" />
    
    		<!-- 将 Error 及以上级别的日志输出到文件 -->
    		<logger name="*" minlevel="Error" writeTo="errorfile" />
    	</rules>
    </nlog>
    
  3. 在代码中使用 NLog

    在代码中,首先需要创建一个 Logger 实例,然后使用它记录日志

    using NLog;
    using System;
    
    class Program
    {
        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
    
        static void Main(string[] args)
        {
            Logger.Info("应用程序启动");
    
            try
            {
                int result = 10 / 0; // 故意引发异常
            }
            catch (Exception ex)
            {
                Logger.Error(ex, "发生了一个错误");
            }
    
            Logger.Info("应用程序结束");
        }
    }

    如果 NLog.config​ 文件不在项目根目录,而是位于其他目录(例如 Config​ 文件夹),你需要通过代码显式指定配置文件的位置。NLog 默认会在应用程序的根目录查找 NLog.config​ 文件,如果文件不在默认位置,可以通过以下方式加载配置文件。

    using NLog;
    using System;
    using System.IO;
    
    class Program
    {
        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
    
        static void Main(string[] args)
        {
            // 指定 NLog.config 文件的路径
            string nlogConfigPath = Path.Combine(AppContext.BaseDirectory, "Config", "NLog.config");
    
            // 加载配置文件
            LogManager.Setup().LoadConfigurationFromFile(nlogConfigPath);
    
            Logger.Info("应用程序启动");
    
            try
            {
                int result = 10 / 0; // 故意引发异常
            }
            catch (Exception ex)
            {
                Logger.Error(ex, "发生了一个错误");
            }
    
            Logger.Info("应用程序结束");
        }
    }
  4. 运行结果

    • 控制台输出:

      2025-01-01 12:00:00.0000 INFO 应用程序启动
      2025-01-01 12:00:00.0010 ERROR 发生了一个错误
      2025-01-01 12:00:00.0020 INFO 应用程序结束
    • 文件输出(logs/2025-01-01.log​):

      2025-01-01 12:00:00.0010 ERROR 发生了一个错误
  5. 可根据实际业务需求对该库做进一步的封装:

    using NLog;
    using System;
    using System.IO;
    using System.Reflection;
    
    namespace UtilityClass
    {
        public class LogUtil
        {
            private NLog.Logger _logger;
    
            static LogUtil()
            {
                Default = new LogUtil(NLog.LogManager.GetCurrentClassLogger());
                // 指定 NLog.config 文件的路径
                string nlogConfigPath = Path.Combine(AppContext.BaseDirectory, "Config", "NLog.config");
    
                // 加载配置文件
                LogManager.Setup().LoadConfigurationFromFile(nlogConfigPath);
            }
    
            public LogUtil(string name) : this(LogManager.GetLogger(name))
            {
            }
    
            private LogUtil(NLog.Logger logger)
            {
                _logger = logger;
            }
    
            public static LogUtil Default { get; private set; }
    
            #region Debug
    
            public void Debug(string msg)
            {
                if (_logger.IsDebugEnabled)
                    _logger.Debug(msg);
            }
    
            public void Debug(string msg, Exception err)
            {
                _logger.Debug(err, msg);
            }
    
            #endregion Debug
    
            #region Info
    
            public void Info(string msg)
            {
                if (_logger.IsInfoEnabled)
                    _logger.Info(msg);
            }
    
            #endregion Info
    
            #region Warn
    
            public void Warn(string msg)
            {
                if (_logger.IsWarnEnabled)
                    _logger.Warn(msg);
            }
    
            public void Warn(string msg, Exception err)
            {
                if (_logger.IsWarnEnabled)
                    _logger.Warn(err, msg);
            }
    
            #endregion Warn
    
            #region Trace
    
            public void Trace(string msg)
            {
                if (_logger.IsTraceEnabled)
                    _logger.Trace(msg);
            }
    
            public void Trace(string msg, Exception err)
            {
                if (_logger.IsTraceEnabled)
                    _logger.Trace(err, msg);
            }
    
            #endregion Trace
    
            #region Error
    
            public void Error(string msg)
            {
                if (_logger.IsErrorEnabled)
                    _logger.Error(msg);
            }
    
            public void Error(string msg, Exception err)
            {
                if (_logger.IsErrorEnabled)
                    _logger.Error(err, msg);
            }
    
            #endregion Error
    
            #region Fatal
    
            public void Fatal(string msg)
            {
                _logger.Fatal(msg);
            }
    
            public void Fatal(string msg, Exception err)
            {
                _logger.Fatal(err, msg);
            }
    
            #endregion Fatal
    
            #region Custom
    
            public void Error(MethodBase methodBase, Exception ex, string msg = null)
            {
                var logEvent = new LogEventInfo(LogLevel.Error, _logger.Name, null, msg, null, ex);
                logEvent.Properties["Namespace"] = methodBase.DeclaringType.Namespace;
                logEvent.Properties["Class"] = methodBase.DeclaringType.FullName;
                logEvent.Properties["Method"] = methodBase.Name;
                _logger.Error(logEvent);
            }
    
            #endregion Custom
    
            /// <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();
            }
        }
    }

NLog 的日志级别

NLog 支持以下日志级别(从低到高):

  1. Trace:用于调试的详细信息。

  2. Debug:调试信息,通常用于开发环境。

  3. Info:常规信息,例如应用程序启动、配置加载等。

  4. Warn:警告信息,表示潜在问题。

  5. Error:错误信息,表示发生了错误但应用程序仍可运行。

  6. Fatal:致命错误,表示应用程序无法继续运行。

NLog 的常用配置选项

  1. 输出目标(Targets)

    • ​Console​:输出到控制台。

    • File​:输出到文件。

    • Database​:输出到数据库。

    • Mail​:通过邮件发送日志。

    • Network​:通过网络发送日志。

  2. 日志格式(Layout)

    • ​${longdate}​:日期和时间。

    • ​${level}​:日志级别。

    • ${message}​:日志消息。

    • ${exception}​:异常信息。

    • ${stacktrace}​:堆栈跟踪信息。

    • ​${logger}​:日志记录器的名称。

    • ​${callsite}​:调用日志的方法名。

    • ​${callsite-linenumber}​:调用日志的代码行号。

    • ​${threadid}​:当前线程的 ID。

    • ​${machinename}​:机器名称。

    • ​${newline}​:换行符。

    • ​${event-properties:item}​:自定义属性(通过 LogEventInfo.Properties​ 设置)。

  3. 日志过滤(Rules)

    • 通过 minlevel​ 和 maxlevel​ 设置日志级别范围。

    • 通过 writeTo​ 指定输出目标。

NLog 的高级功能

  1. 异步日志记录:

    • 使用 AsyncWrapper​ 将日志记录操作异步化,减少对主线程的影响。

    <target name="asyncFile" xsi:type="AsyncWrapper">
      <target xsi:type="File" fileName="logs/${shortdate}.log" />
    </target>
  2. 日志归档:

    • 使用 File​ 目标的 archiveFileName​ 和 archiveEvery​ 参数实现日志归档。

    <target name="file" xsi:type="File"
            fileName="logs/${shortdate}.log"
            archiveFileName="logs/archive/{#}.log"
            archiveEvery="Day"
            archiveNumbering="Rolling"
            maxArchiveFiles="7" />
  3. 自定义日志目标:

    • 可以通过实现 Target​ 类创建自定义日志目标。

总结

NLog 是一个功能强大且易于使用的日志记录库,适用于各种 .NET 应用程序。通过灵活的配置和丰富的功能,NLog 能够满足从简单到复杂的日志记录需求。无论是开发调试还是生产环境,NLog 都是一个可靠的选择。