【框架学习与探究之日志组件--Log4Net与NLog】

前言

本文欢迎转载,作者原创地址:http://www.cnblogs.com/DjlNet/p/7604340.html


近日,天气渐冷,懒惰的脑虫又开始作祟了,导致近日内功修炼迟迟未能进步,依然徘徊在XXX框架学习当中,当然了并不是说这种学习不好,只是感觉收益不高,但是今天博主依然还是老酒新装,把在单体应用架构当中对于Log这块使用最平凡的两款日志组件拿来说道一二,也是对后面框架集成做好铺垫的准备....其实也算是对框架学习系列的一个凑数行为,捂脸.....


抛出问题和思考

按照国际惯例,这里还是给出各自的官方地址,Log4net:https://logging.apache.org/log4net/ , Nlog :http://nlog-project.org/,这里博主可能就不会去一一解释各种组件当中的重要元素、关键类以及使用API和关于Provider的配置了,这里着重还是博主自己工作或者项目当中常规使用到的一些东西备份记录,所以想看详细解读的同学,可以移步去官方链接或者搜索园中其他相关文,所以老司机就可能需要绕道儿了....其实就目前项目使用log组件程度而言,多半是用来记录应用程序日志的,且大多数是以文本的方式(也就是txt、log)来记录日志,方便在程序上线之后免于远程调试以及不好跟踪的问题,那么问题来了,应用程序大家也知道日积月累的产生的日志量,肯定是很多的,那么为了方便我们好去跟踪问题,应该怎么样去分类存储日志文件方便开发者追溯问题!!!多说一句,当我们的API服务成百上千,我们的应用程序或者系统几十上百,那么这个时候我们的日志还处于单体应用体系的话,一条完整的服务调用连的日志跟踪就是一个大麻烦,亦或者需要统筹各自应用的异常行为和错误数据等等,所以当我们的形态达到一定规模之后,我们需要的就是分布式日志处理分析的平台,关键词:ELK 请自行搜索,感叹社区轮子的威力,不过那都是后话了.....


Log4net处理方案

这里我们按照上面的需求和限定范围得知,log4net 日志框架组件历史由来已久且在使用性和或灵活性上面都颇为好评,众所周知我们的日志等级分为: DEBUG、INFO、WARN、ERROR、FATAL,日志等级由低到高的一个过程,所以这个等级分类也是我们需要参考的一个点,其次就是需要按照年份、月份来划分文件夹,最后才是以日期作为文件名,log作为文件后缀名(txt一样),按照如上所说需要配置的 log4net.config 配置如下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <!--添加自定义节点:log4net type:解析类名,程序集名(log4net.dll)-->
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
  </configSections>
  <log4net>
    <root>
      <!--<level value="DEBUG"/>-->
      <!--控制级别,由低到高: ALL|DEBUG|INFO|WARN|ERROR|FATAL|OFF-->
      <!--比如定义级别为INFO,则INFO级别向下的级别,比如DEBUG日志将不会被记录-->
      <level value="ALL"/>
      <!--根据log级别记录到不同的日志文件-->
      <appender-ref ref="DebugLogger" />
      <appender-ref ref="InfoLogger" />
      <appender-ref ref="WarnLogger" />
      <appender-ref ref="ErrorLogger" />
      <appender-ref ref="FatalLogger" />
    </root>

    <!--Debug文件日志记录器-->
    <appender name="DebugLogger" type="log4net.Appender.RollingFileAppender">
      <!--日志存放文件夹-->
      <file value="Log\Debug\"/>
      <!--是否追加到文件-->
      <appendToFile value="true" /> 
      <!--记录日志写入文件时,不锁定文本文件,防止多线程时不能写Log,官方说线程非安全-->
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <!--使用UTF-8编码-->
      <Encoding value="UTF-8" />
      <!--最多产生的日志文件数,超过则只保留最新的n个。设定值value="-1"为不限文件数-->
      <maxSizeRollBackups value="-1"/>
      <!--是否只写到一个文件中-->
      <StaticLogFileName value="false"/>
      <!--按照何种方式产生多个日志文件(日期[Date],文件大小[Size],混合[Composite])-->
      <rollingStyle value="Date" />
      <!--日期的格式,每天换一个文件记录,如不设置则永远只记录一天的日志,需设置-->
      <param name="datePattern" value="yyyy/yyyy-MM/yyyy-MM-dd.'log'" />
      <!--过滤设置,LevelRangeFilter为使用的过滤器。-->
      <filter type="log4net.Filter.LevelRangeFilter">
        <levelMin value="DEBUG" />
        <levelMax value="DEBUG" />
      </filter>
      <!--日志格式-->
      <layout type="log4net.Layout.PatternLayout">
        <!-- 输出格式 日期,日志级别,消息,换行-->
        <param name="ConversionPattern" value="%date [%-5p] %message%n" />
      </layout>
    </appender>

    <!--InfoLog文件日志记录器-->
    <appender name="InfoLogger" type="log4net.Appender.RollingFileAppender">
      <!--日志存放文件夹-->
      <file value="Log\Info\"/>
      <!--是否追加到文件-->
      <appendToFile value="true" />
      <!--记录日志写入文件时,不锁定文本文件,防止多线程时不能写Log,官方说线程非安全-->
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <!--使用UTF-8编码-->
      <Encoding value="UTF-8" />
      <!--最多产生的日志文件数,超过则只保留最新的n个。设定值value="-1"为不限文件数-->
      <maxSizeRollBackups value="-1"/>
      <!--是否只写到一个文件中-->
      <StaticLogFileName value="false"/>
      <!--按照何种方式产生多个日志文件(日期[Date],文件大小[Size],混合[Composite])-->
      <rollingStyle value="Date" />
      <!--日期的格式,每天换一个文件记录,如不设置则永远只记录一天的日志,需设置-->
      <param name="datePattern" value="yyyy/yyyy-MM/yyyy-MM-dd.'log'" />
      <!--过滤设置,LevelRangeFilter为使用的过滤器。-->
      <filter type="log4net.Filter.LevelRangeFilter">
        <levelMin value="INFO" />
        <levelMax value="INFO" />
      </filter>
      <!--日志格式-->
      <layout type="log4net.Layout.PatternLayout">
        <!-- 输出格式 日期,日志级别,消息,换行-->
        <param name="ConversionPattern" value="%date [%-5p] %message%n" />
      </layout>
    </appender>

    <!--WarnLog文件日志记录器-->
    <appender name="WarnLogger" type="log4net.Appender.RollingFileAppender">
      <!--日志存放文件夹-->
      <file value="Log\Warn\"/>
      <!--是否追加到文件-->
      <appendToFile value="true" />
      <!--记录日志写入文件时,不锁定文本文件,防止多线程时不能写Log,官方说线程非安全-->
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <!--使用UTF-8编码-->
      <Encoding value="UTF-8" />
      <!--最多产生的日志文件数,超过则只保留最新的n个。设定值value="-1"为不限文件数-->
      <maxSizeRollBackups value="-1"/>
      <!--是否只写到一个文件中-->
      <StaticLogFileName value="false"/>
      <!--按照何种方式产生多个日志文件(日期[Date],文件大小[Size],混合[Composite])-->
      <rollingStyle value="Date" />
      <!--日期的格式,每天换一个文件记录,如不设置则永远只记录一天的日志,需设置-->
      <param name="datePattern" value="yyyy/yyyy-MM/yyyy-MM-dd.'log'" />
      <!--过滤设置,LevelRangeFilter为使用的过滤器。-->
      <filter type="log4net.Filter.LevelRangeFilter">
        <levelMin value="WARN" />
        <levelMax value="WARN" />
      </filter>
      <!--日志格式-->
      <layout type="log4net.Layout.PatternLayout">
        <!-- 输出格式 日期,日志级别,消息,换行-->
        <param name="ConversionPattern" value="%date [%-5p] %message%n" />
      </layout>
    </appender>

    <!--ErrorLog文件日志记录器-->
    <appender name="ErrorLogger" type="log4net.Appender.RollingFileAppender">
      <!--日志存放文件夹-->
      <file value="Log\Error\"/>
      <!--是否追加到文件-->
      <appendToFile value="true" />
      <!--记录日志写入文件时,不锁定文本文件,防止多线程时不能写Log,官方说线程非安全-->
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <!--使用UTF-8编码-->
      <Encoding value="UTF-8" />
      <!--最多产生的日志文件数,超过则只保留最新的n个。设定值value="-1"为不限文件数-->
      <maxSizeRollBackups value="-1"/>
      <!--是否只写到一个文件中-->
      <StaticLogFileName value="false"/>
      <!--按照何种方式产生多个日志文件(日期[Date],文件大小[Size],混合[Composite])-->
      <rollingStyle value="Date" />
      <!--日期的格式,每天换一个文件记录,如不设置则永远只记录一天的日志,需设置-->
      <param name="datePattern" value="yyyy/yyyy-MM/yyyy-MM-dd.'log'" />
      <!--过滤设置,LevelRangeFilter为使用的过滤器。-->
      <filter type="log4net.Filter.LevelRangeFilter">
        <levelMin value="ERROR" />
        <levelMax value="ERROR" />
      </filter>
      <!--日志格式-->
      <layout type="log4net.Layout.PatternLayout">
        <!-- 输出格式 日期,日志级别,消息,换行-->
        <param name="ConversionPattern" value="%date [%-5p] %message%n" />
      </layout>
    </appender>

    <!--FatalLog文件日志记录器-->
    <appender name="FatalLogger" type="log4net.Appender.RollingFileAppender">
      <!--日志存放文件夹-->
      <file value="Log\Fatal\"/>
      <!--是否追加到文件-->
      <appendToFile value="true" />
      <!--记录日志写入文件时,不锁定文本文件,防止多线程时不能写Log,官方说线程非安全-->
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <!--使用UTF-8编码-->
      <Encoding value="UTF-8" />
      <!--最多产生的日志文件数,超过则只保留最新的n个。设定值value="-1"为不限文件数-->
      <maxSizeRollBackups value="-1"/>
      <!--是否只写到一个文件中-->
      <StaticLogFileName value="false"/>
      <!--按照何种方式产生多个日志文件(日期[Date],文件大小[Size],混合[Composite])-->
      <rollingStyle value="Date" />
      <!--日期的格式,每天换一个文件记录,如不设置则永远只记录一天的日志,需设置-->
      <param name="datePattern" value="yyyy/yyyy-MM/yyyy-MM-dd.'log'" />
      <!--过滤设置,LevelRangeFilter为使用的过滤器。-->
      <filter type="log4net.Filter.LevelRangeFilter">
        <levelMin value="FATAL" />
        <levelMax value="FATAL" />
      </filter>
      <!--日志格式-->
      <layout type="log4net.Layout.PatternLayout">
        <!-- 输出格式 日期,日志级别,消息,换行-->
        <param name="ConversionPattern" value="%date [%-5p] %message%n" />
      </layout>
    </appender>
    
  </log4net>
</configuration>

上面的配置楼主已经亲测可以是使用了,且已经按照我们的需求按照日志等级(这里是通过logger对应的filter来控制的)、年份、月份、日期这个要点分类存储了日志文件,且不同等级的日志文件存储在对应等级的文件夹下面,配置文件当中有较为详细的说明可以参考自己的需求自定义配置,例如修改为自己的layout展示效果等等,文件存储效果如下图:


从上图就可以看出基本满足了我们日常单体应用开发的需求了......这里贴出文件配置也是博主借此备份一下,日后好找....至于说怎么使用、异步还是同步那就看各位同学自己把握和封装了....,如果哪位老铁有更好的方式可以告知一二!!!


NLog处理方案

需求还是同上逻辑,且我们使用NLog依然还是以file作为基础实现配置,话不多说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"
      xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"
      autoReload="true"
      throwExceptions="false"
      internalLogLevel="Off" throwConfigExceptions="true">
  <!-- optional, add some variables
  https://github.com/nlog/NLog/wiki/Configuration-file#variables
  -->
  <!--<variable name="myvar" value="myvalue"/>-->
  <variable name="year" value="${date:format=yyyy}"/>
  <variable name="year_month" value="${date:format=yyyy-MM}"/>
  <!--
  See https://github.com/nlog/nlog/wiki/Configuration-file
  for information on customizing logging rules and outputs.
   -->
  <!-- all targets in this section will automatically be asynchronous -->
  <targets async="true">
    <!--
    add your targets here
    See https://github.com/nlog/NLog/wiki/Targets for possible targets.
    See https://github.com/nlog/NLog/wiki/Layout-Renderers for the possible layout renderers.
    -->
    <!--
    Write events to a file with the date in the filename.
    <target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log"
            layout="${longdate} ${uppercase:${level}} ${message}" />
    -->
    <target xsi:type="AsyncWrapper" name="MyLogger">
      <target xsi:type="File"
              layout="${longdate} ${uppercase:${level}} ${message}"
              fileName="${basedir}/Log/${level}/${year}/${year_month}/${shortdate}.log" encoding="utf-8" />
    </target>
  </targets>
  <rules>
    <!-- add your logging rules here -->
    <logger name="*" minlevel="Trace" maxlevel="Fatal" writeTo="MyLogger" />
    <!--
    Write all events with minimal level of Debug (So Debug, Info, Warn, Error and Fatal, but not Trace)  to "f"
    <logger name="*" minlevel="Debug" writeTo="f" />
    -->
  </rules>
</nlog>

注意这里的 nlog.config 配置想比较与log4net.config就简单许多,且通过wapper的方式就可以支持异步写入文件,注意这里需要自定义 variable 来达到以年份、月份建立对应文件夹存储日期命名的日志文件,因为这里 nlog 本身木有提供 ${year} 这种类似参数,所以需要自定义配置使用,还好 nlog 考虑到了这方面的灵活性,效果图参考如下:和log4net效果一致.....且对应日志等级的文件写入对应的等级文件夹中,至于更多的配置参考官方或者github wiki 吧


小总结

虽然这两个日志框架,我相信大多人都在使用且也知道一些组织结构或者调用API等等,所以博主这里算是“翻旧账”的行为了,主要是还是对常规日志文件存储的一个备份配置的小文章,途中也查询了相关资料,其实还有很多例如 layout 以及 header + footer 的消息美化,亦或者实现数据库,nosql存储日志等等,都看各自的需求,当然我们在使用日志组件的时候肯定是集成在系统中去使用的,那么何时我们用静态工具类LogHelper的方式还是ILog接口注入的方式呐,相信大家都有各自的理解视情况而定的吧......

posted @ 2017-11-09 10:15  DJLNET  阅读(4751)  评论(2编辑  收藏  举报