前言
本文歡迎轉載,作者原創地址: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接口注入的方式吶,相信大家都有各自的理解視情況而定的吧......
