2012-12-28 56 views
3

我想寫我自己的日誌記錄類(在C#),它實現了一個標準接口,這是我可以從代碼的任何部分調用。靈活的日誌界面設計

我的想法是讓多個Log類實現Logger接口,每個Log類都爲其特定的日誌目標,例如,FileLogger將實現日誌記錄到文件,TextBox記錄器將實現登錄到Form中的Multi Line TextBox ,DBLogger將執行日誌記錄到數據庫表等。

此外,每個記錄器類可以有一個嵌套記錄器或鏈式記錄器類,以便從應用程序代碼對Log()方法的單個調用可以記錄消息在多個目的地;例如在一次調用中登錄到Form上的文件和文本框。

我現在面臨的困難是:

通常我登錄到運行日誌文件(將包含調試所需的所有日誌消息),審查日誌文件(僅包含日誌信息進行審查由用戶或需要用戶操作),屏幕上的多行文本框(其將複製所有日誌消息以向用戶提供進度指示)和另一多行文本框(其將只記錄用戶審閱所需的消息)。

當我打電話logger.Log(消息),一些消息可能不適用於特定日誌目的地。例如,某些消息可能只打算記錄在正在運行的日誌文件或進度文本框中,但不會記錄在用戶審閱文本框中,反之亦然。

由於記錄儀將被鏈接,這樣一個函數調用可以登錄到所有需要的目的地,如何可以在特定的記錄器識別日誌消息不適用於它,並因此忽略日誌消息?

我的示例日誌接口是:

public interface Logger 
{ 
    public void Log(string msg); 
    public void Log(string msgType, string msg); 
    public void InitLogSession(); 
    public void EndLogSession(); 
    public void AddLogger(Logger chainedLogger); 
    public void RemoveLogger(Logger chainedLogger); 
} 

public class FileLogger : Logger 
{ 
     //implement methods 
} 

public class TextBoxLogger : Logger 
{ 
     //implement methods 
} 

public class DBLogger : Logger 
{ 
     //implement methods 
} 

EDIT 1:

爲了更精確,可能有4個記錄程序:2個文件記錄器和2個文本記錄器。一個特定的消息是爲1個文本記錄器和1個文件記錄器而設的;我的設計應如何處理?

編輯2: 請不要建議現有的日誌框架。我只是想自己寫!

編輯3: 確定。我有一個設計。請給出您的反饋,並填補空白。

修訂後的界面:

public interface Logger 
{ 
    public void Log(string msg); 
    public void Log(string msgType, string msg); 
    public void Log(int loggerIds, string msg); 
    public void Log(int loggerIds, string msgType, string msg); 
    public void InitLogSession(); 
    public void EndLogSession(); 
    public int getLoggerId(); 
} 

public enum LoggerType 
{ 
    File, 
    TextBox 
}; 

public class LoggerFactory 
{ 
    public Logger getLogger(LoggerType loggerType) 
    { 

    } 
} 

的的LoggerFactory類將實例化一個記錄器的唯一方式。這個類將爲記錄器的每個實例分配一個唯一的ID。這個唯一的ID將是2的冪。例如,第一個記錄器將獲得id 1,第二個將獲得id 2,第三個將獲得4,並且第四個將獲得8,依此類推。

返回的記錄器對象可以被轉換爲特定的類,並且調用者可以設置更多的值,比如filePath,textbox等,否則我可以在LoggerFactory中有多個方法:每種類型的記錄器都有一個將接受具體的參數。

因此,假設我們有4個伐木工人有IDS 1,2,4,8。 必須由第一和第三個記錄器處理的特定消息(即,記錄器的ID 1和4)具有使用以下函數來記錄:

public void Log(int loggerIds, string msg); 

的值被傳遞到loggerIds應該是「0101」。每個記錄器將檢查其記錄器ID位是否爲ON。如果是的話,只有它會記錄消息。

現在在函數簽名中,我提到了int類型,但是它是用於執行位操作和比較的特定優化類型?

在這種方法中,最大數量可能有限制。的伐木工人,但這對我來說很好。請提供您的反饋。

注意:目前我仍在.NET 2.0上。如果可能的話,在.NET 2.0中建議解決方案,否則我可以移動到更高版本。

本設計的缺點:每個需要登錄的類需要了解應用程序實例化的所有可用記錄器,並據此設置位模式。任何想法如何有鬆散耦合的設計?

+1

好吧... _you_用來決定什麼記錄器記錄什麼信息的邏輯是什麼? –

+0

我認爲這是他的問題。 –

+0

你想把這作爲一個練習嗎?因爲有框架已經做得很好(比如[log4net](http://logging.apache.org/log4net/))。這些框架使用配置文件來定義單個記錄器的行爲方式(如果以及在何處發送它們的輸出)。代碼中的每個記錄器都需要有一個唯一的名稱,以此來確定輸出(或多個輸出)。 – Groo

回答

8

爲什麼不看(或實際使用)現有的日誌框架,如log4netNLog

它們具有日誌級別的概念(例如跟蹤,信息,錯誤等)以及能夠根據日誌名稱(通常是調用日誌記錄調用的完全限定類型名稱)進行過濾。然後,您可以將這些映射到一個或多個「目標」。

+0

+1 log4net規則! – Luca

+0

不要重新安裝輪子。去NLog或log4net(這兩個框架都非常成熟,在我們使用log4net的企業中)和AOP :) – Simon

+2

我想自己做這個。此時我不想學習第三方庫。日誌級別將無濟於事,因爲可能只需要在所選目標中記錄相同日誌級別的不同消息。 – AllSolutions

1

由於devdigital寫道,這些框架通常這樣做是通過提供測井等指定方法:警告(「......‘),不合格(’...」)...

你也可以找該城堡項目的logging facility的界面​​。 (也許嘗試谷歌ILogger.cs源代碼)

如果你仍然堅持你的方法鏈接記錄器與通用接口(你也必須實現鏈接機制),你將不得不提供一種將日誌級別記錄到Log()方法。這可能只是一個整數或枚舉。

像這樣:

public interface Logger 
    { 
     public void Log(LogLevel level, string msg); 
     public void Log(LogLevel level, string msgType, string msg); 
     public void InitLogSession(); 
     public void EndLogSession(); 
     public void AddLogger(Logger chainedLogger); 
     public void RemoveLogger(Logger chainedLogger); 
    } 

有了這樣的日誌記錄級別枚舉:

public enum LogLevel 
{ 
    Info, 
    Warn, 
    Debug, 
    Error, 
    Fail 
} 

伐木者使用會那麼責任鏈中進行選擇。

+0

關於日誌級別,這是真的。但OP的問題似乎更多地與配置記錄器有不同的目標(例如log4net中的「appender」)有關。 – Groo

+0

在我的設計中,記錄級別或消息類型在參數msgType中被捕獲。但是,特定類型的消息也可能旨在僅記錄在少數目的地。那麼如何處理呢?例如,INFO類型的某些消息可能需要記錄到進度文本框以及審閱文本框中,而另一種類型爲INFO的消息可能只需要記錄在進度文本框中。 – AllSolutions

1

前段時間我寫了自己的記錄器。說實話,它不像免費提供的那麼好,我意識到我正在試圖重新發明一個已經是圓形的輪子!

我看到你想要編寫自己的代碼,但它可能仍然是一個想法,看看開源的解決方案,並可能使用它們或修改他們自己的特定需求

我現在用TracerX:http://www.codeproject.com/Articles/23424/TracerX-Logger-and-Viewer-for-NET這是一個開源項目,因此可以輕鬆修改您需要的源代碼。其他提到的伐木者當然也很好。

編輯

這是基於公認的答案在這裏,我的問題:How to pass status information to the GUI in a loosely coupled application所以我要求在這個沒有新鮮感。我認爲你的日誌信息很簡單

我建議的答案是你使用的消息類型可以處理(例如)根據在運行時傳遞給它的邏輯或通過使用工廠根據運行時間條件創建不同的消息類型。

所以

  1. 創建具有一個處理方法一個抽象消息類或接口。
  2. 創建許多繼承自抽象類或接口的消息類型,它們代表要執行的不同類型的日誌記錄。處理方法可以確定將它們發送到哪裏。
  3. 考慮使用工廠在運行時創建所需的消息類型,因此您無需事先確定需要的類型
  4. 當您生成日誌消息時,請使用進程消息將消息路由到記錄儀你想要它去
+0

這裏的每個人都建議使用現有的日誌框架。但現有的日誌框架能否滿足我的要求?假設1條日誌消息適用於4個記錄器中的2個(而不是基於記錄級別) - 現有框架可以處理這種情況嗎? – AllSolutions

+0

我可以看到你有一個特定的問題。我有一個類似的問題,我希望將狀態消息與應用程序日誌分開發送給用戶。我可能會去一個單獨的課程來處理用戶數據。我可以建議你看看我上面發佈的TracerX文章嗎?它確實使用日誌記錄級別來分隔哪裏,但查看器的代碼確實允許進行一系列搜索。我攔截日誌請求並使用一個小類將它們發送到正確的地方。這又可能不是你想要的,因爲它與代碼緊密耦合。 – ScruffyDuck

+0

我用完了空間。我認爲我們所說的是看一個現有的基礎枯燥的管道工作框架,並擴展到您的需求,而不是從頭開始。但是我可以看到這可能無法正常工作。 – ScruffyDuck

0

這似乎是一個很好的地方使用擴展方法

創建您的基類,然後爲其創建擴展方法

BaseLogger(LogMessage).toTextBoxLog().toFileLog().toDatabaseLog(). 

這樣,你總是叫BaseLogger然後只有擴展方法需要的地方。

0

「請不要建議現有的日誌框架,我只是想自己寫!」

接受的答案:不要重新發明輪子!使用這個現有的日誌框架!

捂臉

最好的答案,這就是我的回答,是這樣的。 如果您想要即插即用功能,請使用接口。您可以使其易於配置。這是高級別運行。

  1. 使用一個配置文件來表示你想要什麼類型的記錄儀 它實現你的日誌接口

  2. 使用反射來實例化你 您的配置文件中拉在運行時類型。

  3. 將您剛剛通過構造函數注入進來的記錄器接口傳入您的類中。

你不是通過界面設計重新發明輪子。 如果你使你的接口足夠一般,它是實現非特定的(理想情況下)。 這意味着如果log4net進入廢話或不再支持,您不必RIP輸出和修改您的所有呼叫代碼。這就像將一盞燈直接連接到你的房子打開它。爲了愛上帝,請不要這樣做。 接口定義了組件交互的契約,而不是實現。

我能想到的唯一的事情就是,查看現有的日誌記錄框架,查找常見元素,並將界面編寫爲常見功能的交集。顯然會有你想念的功能。這取決於你想要多大的靈活性。您可以使用Log4net或Microsoft事件查看器記錄器,或兩者兼而有之!沒有實施細節被重新實施。這是一個更少的耦合系統,而不是將代碼中的所有內容都綁定到一個技術/框架。