日志ILog(文件日志/控制臺日志/控件日志/網(wǎng)絡(luò)日志)

日志組件是NewLife系列組件最早最基礎(chǔ),同時也是流血流淚最多的一個模塊,它的底蘊(yùn)定能感動每一個用戶!
沒有日志的應(yīng)用系統(tǒng)是不完整的。系統(tǒng)遇到啥問題,翻日志看看當(dāng)時上下文,實(shí)在分析不出問題,修改代碼再打幾個日志……這是每一個程序員的日常寫照。
不少同學(xué)喜歡調(diào)試程序,但是聽過“薛定諤的貓”這個故事的人不多。有時候程序跑起來沒問題,調(diào)試就有問題;有時候跑起來有問題,調(diào)試就沒有問題。就像是薛定諤的貓,測不準(zhǔn)原理,調(diào)試觀察本身干涉了程序運(yùn)行。這個時候就需要看日志。
單片機(jī)嵌入式設(shè)備、安卓移動應(yīng)用、Linux嵌入式應(yīng)用,雖然都可以在線調(diào)試,但也會有許多不方便的地方。如果能夠配合使用日志,將會事半功倍。
Nuget包:NewLife.Core
源碼地址:
https://github.com/NewLifeX/X/tree/master/NewLife.Core/Log
Get Started
新建控制臺項(xiàng)目 ConsoleApp1 ,放到 D:\Test,其它目錄也可以


從Nuget引用 NewLife.Core ,安裝最新版本。

打開Program.cs的Main函數(shù),寫入一下代碼
XTrace.UseConsole();XTrace.WriteLine("Hello NewLife!");
點(diǎn)擊XTrace左邊圖標(biāo),可選“using NewLife.Log;”自動添加命名空間引用。

點(diǎn)擊上方綠色啟動三角符號,或者按下F5,啟動應(yīng)用程序。

可以看到打開一個控制臺窗口,并輸入一行日志
13:15:06.270 1 N - Hello NewLife!
這就是我們前面代碼輸出的內(nèi)容:XTrace.WriteLine("Hello NewLife!");
這也是最簡單最常見的日志用法:XTrace.WriteLine
XTrace是靜態(tài)跟蹤類,WriteLine等日志輸出方法,本質(zhì)上是調(diào)用實(shí)現(xiàn)了ILog接口的XTrace.Log。
日志接口ILog
ILog是日志輸出標(biāo)準(zhǔn)接口
/// <summary>寫日志</summary>/// <param name="level">日志級別</param>/// <param name="format">格式化字符串</param>/// <param name="args">格式化參數(shù)</param>void Write(LogLevel level, String format, params Object?[] args);/// <summary>調(diào)試日志</summary>/// <param name="format">格式化字符串</param>/// <param name="args">格式化參數(shù)</param>void Debug(String format, params Object?[] args);/// <summary>信息日志</summary>/// <param name="format">格式化字符串</param>/// <param name="args">格式化參數(shù)</param>void Info(String format, params Object?[] args);/// <summary>警告日志</summary>/// <param name="format">格式化字符串</param>/// <param name="args">格式化參數(shù)</param>void Warn(String format, params Object?[] args);/// <summary>錯誤日志</summary>/// <param name="format">格式化字符串</param>/// <param name="args">格式化參數(shù)</param>void Error(String format, params Object?[] args);/// <summary>嚴(yán)重錯誤日志</summary>/// <param name="format">格式化字符串</param>/// <param name="args">格式化參數(shù)</param>void Fatal(String format, params Object?[] args);/// <summary>是否啟用日志</summary>Boolean Enable { get; set; }/// <summary>日志等級,只輸出大于等于該級別的日志,默認(rèn)Info</summary>LogLevel Level { get; set; }
Write核心方法,很少使用,一般都使用 Info/Debug/Warn/Error/Fatal 等接口,最終都是調(diào)用Write,只是日志等級不同。
日志對象可以獨(dú)立控制是否啟用,以及日志等級Level。
已有日志等級:
/// <summary>日志等級</summary>public enum LogLevel : System.Byte{/// <summary>打開所有日志記錄</summary>All = 0,/// <summary>最低調(diào)試。細(xì)粒度信息事件對調(diào)試應(yīng)用程序非常有幫助</summary>Debug,/// <summary>普通消息。在粗粒度級別上突出強(qiáng)調(diào)應(yīng)用程序的運(yùn)行過程</summary>Info,/// <summary>警告</summary>Warn,/// <summary>錯誤</summary>Error,/// <summary>嚴(yán)重錯誤</summary>Fatal,/// <summary>關(guān)閉所有日志記錄</summary>Off = 0xFF}
文件日志
文本文件日志是最重要的日志,也是XTrace.Log的默認(rèn)實(shí)現(xiàn)。
文本文件日志是把日志逐行輸出到文本文件中,每天一個文件。
如果想要獨(dú)立存儲某個模塊的日志,可以實(shí)例化一個專屬的TextFileLog對象。推薦使用Create創(chuàng)建。
/// <summary>每個目錄的日志實(shí)例應(yīng)該只有一個,所以采用靜態(tài)創(chuàng)建</summary>/// <param name="path">日志目錄或日志文件路徑</param>/// <param name="fileFormat"></param>/// <returns></returns>public static TextFileLog Create(String path, String fileFormat = null);/// <summary>每個目錄的日志實(shí)例應(yīng)該只有一個,所以采用靜態(tài)創(chuàng)建</summary>/// <param name="path">日志目錄或日志文件路徑</param>/// <returns></returns>public static TextFileLog CreateFile(String path);
文件日志內(nèi)部有隊列、延遲關(guān)閉等復(fù)雜邏輯,強(qiáng)烈建議使用單例,Create可確保單例實(shí)現(xiàn)。
文本文件日志主要特性:
每天一個文件,例如 2021_06_25.log
每個文件最大10M,(可在core.config中配置LogFileMaxBytes),超過后產(chǎn)生新的日志文件,例如 2021_06_25_2.log
日志目錄為Log子目錄,(可配置LogPath)
日志目錄中最多只保存最新100個日志文件,(可配置LogFileBackups)
日志等級,可配置LogLevel,默認(rèn)Info,大于等于該等級才輸出日志到文件
日志文件格式,可配置LogFileFormat,默認(rèn) {0:yyyy_MM_dd}.log,也可以按照日志等級區(qū)分目錄,例如 {1}/{0:yyyy_MM_dd}.log
日志寫入使用隊列實(shí)現(xiàn),避免影響應(yīng)用層性能
如果連續(xù)5秒沒有日志寫入,則自動關(guān)閉日志文件句柄,此時用戶可以根據(jù)需要移動或刪除日志文件
這里的10M和100個,最大日志占用1G,可以有效的避免異常信息寫爆磁盤!(說多都是淚……)
來看看上面Demo的日志文件
#Software: ConsoleApp1#ProcessID: 38144 x64#AppDomain: ConsoleApp1#FileName: D:\Test\ConsoleApp1\ConsoleApp1\bin\Debug\net5.0\ConsoleApp1.exe#BaseDirectory: D:\Test\ConsoleApp1\ConsoleApp1\bin\Debug\net5.0\#TempPath: C:\Users\Stone\AppData\Local\Temp\#CommandLine: D:\Test\ConsoleApp1\ConsoleApp1\bin\Debug\net5.0\ConsoleApp1.dll#ApplicationType: Console#CLR: 5.0.7, .NET 5.0.7#OS: Microsoft Windows NT 10.0.19042.0, X6/Stone#CPU: 8#GC: IsServerGC=False, LatencyMode=Interactive#ThreadPool: Min=32/32, Max=32767/1000, Available=32766/1000#Date: 2021-06-25#字段: 時間 線程ID 線程池Y/網(wǎng)頁W/普通N/定時T 線程名/任務(wù)ID 消息內(nèi)容#Fields: Time ThreadID Kind Name Message13:42:42.463 1 N - NewLife.Core v8.10.2021.0604 Build 2021-06-07 09:05:06 .NETCoreApp,Version=v5.013:42:42.465 1 N - X組件核心庫 ?2002-2021 NewLife13:42:42.466 1 N - ConsoleApp1 v1.0.0 Build 2000-01-01 .NETCoreApp,Version=v5.013:42:42.466 1 N - ConsoleApp113:42:42.466 1 N - Hello NewLife!
可以看到,日志文件非常完善,還有一個很完整的日志頭。
文本日志文件格式,參考了多款微軟產(chǎn)品,頭部井號#隔開的行是注釋行,用于說明情況。
通過日志頭,可以了解到一下信息:
軟件名ConsoleApp1,取自進(jìn)程名
進(jìn)程Id,是否64位進(jìn)程
應(yīng)用程序域,這個現(xiàn)在沒有太多意義了
執(zhí)行文件名,全路徑
基準(zhǔn)目錄,全路徑。這個非常重要,很多人的控制臺程序正常,改為系統(tǒng)服務(wù)以后異常,很大可能性就是因?yàn)檫@個基準(zhǔn)目錄變成了操作系統(tǒng)目錄。
臨時目錄,X組件有時候需要使用臨時目錄
命令行參數(shù)
應(yīng)用類型,.NETCore里面基本上都是Console了,有點(diǎn)難以區(qū)分WinForm和Web
.NET版本,CLR版本
操作系統(tǒng)、CPU等
GC設(shè)置
線程池設(shè)置值。
日志字段格式介紹
字段格式:
時間,時分秒和毫秒。這里的毫秒特別重要,可以精確知道各個操作執(zhí)行耗時情況
線程Id,如果每個日志所屬線程不加以區(qū)分,在多線程環(huán)境下就會一團(tuán)糟
線程類型,線程池Y、網(wǎng)頁W、普通N、定時T
線程名/任務(wù)Id
日志內(nèi)容
由此可見,日志組件特別適用于分析多線程問題。
設(shè)計如此詳盡的日志頭,主要為了能夠準(zhǔn)確記錄程序的執(zhí)行上下文環(huán)境,特別對于客戶端應(yīng)用來說尤為重要!
控制臺日志
前面例程中,Main函數(shù)開頭有一行 XTrace.UseConsole() ,意思是使用控制臺日志。如果沒有這一行,XTrace.WriteLine默認(rèn)只會寫入文本文件日志。加上后,同時寫文件和控制臺。
控制臺日志ConsoleLog沒有日志頭,其它跟文本文件日志一樣,輸出時間、線程信息和日志內(nèi)容。
控制臺日志多了個彩色顯示,不同線程以不同顏色區(qū)分,便于快速區(qū)分同一個線程的日志。受制于控制臺顏色樣本不足,某些情況下不同線程可能使用相同的顏色。內(nèi)置10種顏色,線程Id對顏色個數(shù)取余。
除了WinForm和早期ASP.Net,否則一般都使用 XTrace.UseControle() 把日志同步輸出到控制臺。對應(yīng)用性能有嚴(yán)格要求時,可以注意這一行關(guān)閉控制臺日志。
切記!??!控制臺日志不宜過多,否則會嚴(yán)重影響應(yīng)用性能,因?yàn)榭刂婆_數(shù)據(jù)內(nèi)部帶有鎖需要排隊。
控件日志
對于WinForm應(yīng)用來說,希望能夠把日志輸出到某個富文本框之中。控件日志TextControlLog為此而生!
XTrace中有擴(kuò)展方法 UseWinFormControl :
/// <summary>在WinForm控件上輸出日志,主要考慮非UI線程操作</summary>/// <remarks>不是常用功能,為了避免干擾常用功能,保持UseWinForm開頭</remarks>/// <param name="control">要綁定日志輸出的WinForm控件</param>/// <param name="useFileLog">是否同時使用文件日志,默認(rèn)使用</param>/// <param name="maxLines">最大行數(shù)</param>public static void UseWinFormControl(this Control control, Boolean useFileLog = true, Int32 maxLines = 1000)
在碼神工具 NewLife.XCoder 的網(wǎng)絡(luò)調(diào)試工具中,F(xiàn)rmMain_Load 有以下代碼:
txtReceive.UseWinFormControl();
這里的txtReceive是富文本框RichTextBox,負(fù)責(zé)數(shù)據(jù)接收區(qū),同時用于顯示日志。
因此,UseWinFormControl 用于把日志重定向到富文本框,第二參數(shù)useFileLog指定繼續(xù)寫文件日志。
網(wǎng)絡(luò)日志
NewLife.Core 組件也支持Android和iOS開發(fā)(基于Xamarin),由于設(shè)備上的日志很不好實(shí)時查看,因而設(shè)計了網(wǎng)絡(luò)日志。NetworkLog通過UDP協(xié)議把日志發(fā)送到局域網(wǎng)某個目標(biāo)地址。
配置文件core.config中指定NetworkLog配置項(xiàng),例如 udp://10.0.0.3:514 ,也可以使用廣播地址 udp://255.255.255.255:514 。然后在開發(fā)機(jī) 10.0.0.3 上開一個碼神工具,網(wǎng)絡(luò)工具監(jiān)聽UDP514端口即可接收日志。
嵌入式Linux應(yīng)用開發(fā)也可以使用同樣辦法。
網(wǎng)絡(luò)日志降低了我們對移動應(yīng)用和嵌入式應(yīng)用的調(diào)試依賴。
星塵日志中心
網(wǎng)絡(luò)日志還有一個隱藏技能,core.config 的 NetworkLog 填寫http地址時,支持星塵日志中心。例如 http://star.newlifex.com:6600/log。
網(wǎng)絡(luò)日志內(nèi)部使用隊列緩沖數(shù)據(jù),按批發(fā)送到星塵服務(wù)端,服務(wù)端分表分庫存儲。
【推薦】.NET Core開發(fā)實(shí)戰(zhàn)視頻課程 ★★★
.NET Core實(shí)戰(zhàn)項(xiàng)目之CMS 第一章 入門篇-開篇及總體規(guī)劃
【.NET Core微服務(wù)實(shí)戰(zhàn)-統(tǒng)一身份認(rèn)證】開篇及目錄索引
Redis基本使用及百億數(shù)據(jù)量中的使用技巧分享(附視頻地址及觀看指南)
.NET Core中的一個接口多種實(shí)現(xiàn)的依賴注入與動態(tài)選擇看這篇就夠了
用abp vNext快速開發(fā)Quartz.NET定時任務(wù)管理界面
在ASP.NET Core中創(chuàng)建基于Quartz.NET托管服務(wù)輕松實(shí)現(xiàn)作業(yè)調(diào)度
現(xiàn)身說法:實(shí)際業(yè)務(wù)出發(fā)分析百億數(shù)據(jù)量下的多表查詢優(yōu)化
