當前位置:
首頁 > 知識 > 一個簡單的 C 非同步日誌記錄器

一個簡單的 C 非同步日誌記錄器

Clearcove.Logging是一個非常簡單的日誌庫,旨在通過直接許可條款滿足大多數日誌記錄需求。

介紹

我知道你在想什麼——代碼世界真的需要另一個日誌庫嗎?

如果你在.NET中尋找一個日誌庫,那麼你有很多選擇。有NLog,Log4Net,Enterprise Logging,erilog and Common.Logging,這些只是我現在暫時能想到的。我們不難找到一些由才華橫溢的開發人員編寫的日誌庫,他們花費了大量時間和精力創建了一些功能強大且功能豐富的軟體。

那麼,這個問題是否還需要解決呢?

一個簡單的 C 非同步日誌記錄器

背景

幾個月前,我進入了一個日誌庫市場。我是一個商業桌面應用程序的創建者,該商業桌面應用程序通過互聯網分發。因此,我有三個硬性需求:

  1. 非同步寫入日誌條目。我看到過有太多的應用程序因為是同步日誌記錄,因而出現了嚴峻的性能問題。
  2. 庫應該儘可能小。我不希望我的用戶就為了一個簡單的日誌功能就得下載和載入1 MB的DLL。越小越好。
  3. 我不想增加應用程序許可的複雜性。目前,我的客戶必須同意我的許可條款。添加具有單獨許可條款的第三方組件可能意味著需要額外的工作來評估我的產品。也許這有點偏執,但我只是想保持簡單。

我認為這些都是非常簡單的要求,但事實證明,我找不到任何符合我需求的產品。特別是,我發現許多日誌庫的許可條款是我無法接受的,因為我不想被迫分發「另一個」許可證。

所以我決定自己來寫日誌庫——Clearcove.Logging。它只有83行代碼,非常輕巧。完整的實現放在一個單獨的.cs文件中,以便在不必導入庫的情況下重用。代碼是用VS 2017編寫的,但我曾試圖編寫可與早期版本兼容的代碼。日誌庫以.NET 2.0為目標,為了吸引更多的用戶。

我認為這種日誌記錄方法是一個很好的選擇,是因為:

  1. 應用程序沒有複雜的日誌記錄需求
  2. 這是一個小程序,讓你從簡化的部署中受益
  3. 許可複雜性必須保持在最低限度

那麼它是怎樣工作的?

使用代碼

首先,我要知道我想記錄什麼信息。我想要一個簡單的API,可以用來記錄時間戳、記錄器名稱、線程ID和消息等信息。我對Log4Net API非常熟悉,並且從中借鑒了很多。

要聲明和使用記錄器,可以使用如下語法:

var log = new Logger(typeof(Program)); // Class level declaration.
log.Error("My error message", exception); // Logging from within a method.
log.Info("My info message");

如果你以前使用過其他日誌記錄庫,那麼你可能熟悉這種語法。

數據封裝

接下來,我要將我的日誌條目表示為一個簡單的對象。這樣做的主要原因是我希望我的記錄器能夠提升日誌記錄事件。有時我會在創建單元和集成測試時使用這些事件,因為我發現它們可以提供幫助。這只是個人喜好。如果你對提升日誌記錄事件不感興趣,則可以簡化此代碼。

日誌記錄事件封裝在LogMessageInfo 對象中,該對象的實現方式如下:

public sealed class LogMessageInfo
{
public readonly DateTime Timestamp;
public readonly string ThreadId;
public readonly string Level;
public readonly string Logger;
public readonly string Message;
}

編寫日誌條目

上面用於API實現和數據封裝部分的代碼雖然冗長但非常簡單。但是,非同步日誌記錄略有差別。例如,如果拋出導致應用程序關閉的異常,那麼會發生什麼情況?我們如何知道所有日誌條目將按照接收到的順序編寫?有若干方法可以解決這個問題。 Clearcove.Logger 就是其中一種簡單但不優雅的方式:

static void Main(string[] args)
{
var targetLogFile = new FileInfo("./MyApp.log");
Logger.Start(targetLogFile); // Loggers will complains if you skip initialization
try
{
Run(args);
}
finally
{
Logger.ShutDown(); // Removing this line may result in lost log entries.
}
}

這是一個Clearcove.Logging 背離其他實現,例如Log4Net的示例。我們必須告訴我們的記錄器何時開始記錄以及何時停止記錄。在嘗試將任何日誌條目寫入日誌文件之前,我們必須執行這個操作。將Logger.ShutDown() 調用放在finally語句中應該使我們的記錄器有機會在應用程序關閉之前將所有待處理的日誌條目寫入日誌文件。當然,也有日誌條目不寫入的情況。例如,如果機器沒電了。如果其中有些邊緣情況是你所關心的,則可能需要考慮同步日誌記錄。

Clearcove.Logging 通過使用單個System.Thread.Timer 實例來實現非同步日誌寫入。我們沒有設置線程計時器的周期,因此計時器只會觸發一次。在所有待處理日誌條目被成功寫入日誌文件後,計時器將重置,等到下一個間隔觸發。這種行為類似於在計時器上設置一段時間,但會阻止計時器在間隔延遲的情況下被多次觸發。

最後,通過簡單調用File.AppendAllText將日誌條目寫入文件。這種調用可能不是多次寫入日誌文件最有效的方法,但是出於保持代碼儘可能簡單的前提。

好了。一個非常簡單的日誌實現完成了,它完全能夠滿足大多數應用程序的日誌需求。而且非常適合我,幫助我解決了所有的日誌記錄問題,同時將依賴關係降到最低。

進一步的工作

記錄器簡單的好處之一是它很容易理解,並且可以快速定製以滿足你的需求。例子包括滾動日誌文件,同步日誌記錄,外部配置等。這些功能的實現就留給大家練習吧。玩的開心!

此記錄器實現的一個很大的缺點是它只是.NET。我打算儘快發布這個日誌記錄庫的Java實現。

另外,請注意,一些CodeProject用戶可能會在下面發布增強功能。我會嘗試在不增加複雜性的情況下合併更改,但如果你發現此記錄器不怎麼滿足你的需求,則可能需要閱讀下面的注釋。

興趣點

讓我陷入混亂的一件事是希望簡化軟體許可。我努力想使得Clearcove.Logger 免費,而不增加許可複雜性。根據我的研究,我相信Ms-PL是最寬容的許可證。不但簡單,易於閱讀和理解,並且重要的是要求你的二進位發行版「在遵循本許可證的許可下」發布。在我看來,這個陳述是一個開放的解釋,給了我們很大的靈活性。當然,我的看法是,一方面軟體應該儘可能免費,另一方面應該仍然給予用戶需要的保護。如果你有更加開放的許可建議,請告訴我。

一個簡單的 C 非同步日誌記錄器

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 程序員小新人學習 的精彩文章:

查看linux版本及lsb release安裝及一些想法
Faster-RCNN訓練自己的數據集

TAG:程序員小新人學習 |