2010-11-07 109 views
4

我在做生產支持,依靠日誌進行故障排除。我發現日誌信息現在非常混亂。日誌信息最佳實踐

您能否提供寫入日誌信息的最佳做法或指導?

順便說一句:我們正在使用log4Net。你有其他圖書館的建議嗎?

謝謝。

回答

6

理想情況下,您的日誌消息應該包含何時,什麼,何處,誰以及觸發該消息的事件的嚴重程度的某些指示的詳細信息。

  • 包括日期和時間。如果您的應用程序跨時區分佈,還包括時區指示符。如果每個人都確切知道什麼時間03:11:04在他們的時區,它會消除混淆。
  • 包含記錄嚴重性級別。
  • 在日誌消息中包含觸發日誌消息的模塊或類的某些指示。
  • 如果可能的話,鼓勵開發者在郵件中包含特定信息:例如'File corrupt',比'File corrupt:'C:\ foo \ bar.dat''
  • if可能的是,開發人員在錯誤消息中包含某種會話或事務ID。能夠過濾來自發生錯誤的事務消息的日誌並忽略所有正常的事務都很方便。
  • 在錯誤日誌中包含錯誤代碼通常是一個好主意。

我想第二個建議給@Oded保持消息整潔。對於常規的東西,日期&時間,日誌級別,錯誤代碼,我會嘗試將它們格式化爲固定寬度,並將它們放在開始位置。它使掃描日誌變得更容易。

至於關於日誌消息格式化的好的指南,我唯一遇到的問題是「Release It!」一書的第17章:http://www.pragprog.com/titles/mnee/release-it上面的許多建議都是基於此。

+1

這本書看起來很有用 – Ricky 2010-11-07 13:06:58

2

ELMAH是一個很好的日誌記錄庫,不是log4net的一個不錯的替代方案。

關於你的日誌格式(你說的信息是「雜亂」,雖然你沒有解釋到底是什麼意思) - 確保每個條目明顯與其他人分開,並且它被格式化爲可讀的方式(間距,換行符等)。

2

@corriganjc有很多很好的建議。

我會添加一些細節: 如果可能,請考慮使用UTC記錄消息。一方面,看看在「你的」時區產生的信息會很煩人,然後必須記住正確的數量來抵消他們「正確地」解釋它們。另一方面,所有日誌消息都可以按時間/日期排序,無需進一步解釋。 (如果您從兩個時區記錄了消息,並且已使用「本地」時間記錄了這些消息,則只有在將它們帶到共同時區時才能對它們進行排序)。

使用GlobalContext,ThreadContext和LogicalThreadContext對象將其他上下文注入到消息中。建議記錄諸如「會話ID」或「事務ID」之類的建議是很好的建議,並且可以使用「上下文」對象最有效地完成,而不是通過將這些值明確地添加到實際的日誌記錄調用站點。您可以設置上下文一次,並添加一個格式化選項,將該上下文永遠記錄下來。

如果使用上下文對象,可以考慮讓他們沒有試圖增加他們的背景下,當使錯別字這使得開發人員可以參考「標準」值名稱,甚至定義字符串常量:

//Context value names 
public static class DiagnosticContextValueNames 
{ 
    public static string TransactionId = "transactionid"; 
    public static string SessionId = "sessionid"; 
} 

//In your code 
log4net.ThreadContext.Properties[DiagnosticContextValueNames.TransactionId] = GetTransactionId(); 
log4net.ThreadContext.Properties[DiagnosticContextValueNames.SessionId] = GetSessionId(); 

//Somewhere later on... 
logger.Info("hello"); // this message can be tagged with the transaction id and session id if you use the appropriate formatting options 

你甚至可以考慮在GlobalContext.Properties,ThreadContext.Properties等,擴展方法幫助指導開發者正確的設置上下文值:

public static class LoggingExtensions 
{ 
    public static void SetTransactionId(this ThreadContextProperties props, string trans) 
    { 
    props["TransactionId"] = trans; 

    // Or, using constants as defined above... 
    props[ThreadContextValueNames.TransactionId] = trans; 
    } 
} 


// In your code... 
log4net.ThreadContext.Properties.SetTransactionId(GetTransactionId()); 

// As compared to this: 
log4net.ThreadContext.Properties["transactionid"] = GetTransactionId(); 

如果包裝或log4net的記錄器繼承,你可以添加索姆e上下文信息,從而減輕開發人員的負擔。有一個正確的方式來包裝或繼承log4net記錄器,但它不是火箭科學。關鍵是將log4net傳遞給你的包裝記錄器的類型。 cfeduke在this post中的回答給出了一種包裝log4net記錄器的方法。

你可以按照他的例子,但實現所有日誌調用的「ILogger.Log」方法。裏面的「日誌」,您可以添加您希望您的所有日誌消息的屬性:

// This approach requires more effort than simply populating the context properties "normally", and 
// is probably overkill for most situations. However, it can prove useful if you are able 
// to have access to the context information that you want to log from within the Log method 
// of the logger. 
public void Log(type loggerBoundaryDeclaringType, LogLevel level, object message, object exception) 
{ 
    log4net.ThreadContext.Properties["transactionid"] = GetTransactionId(); 
    log4net.ThreadContext.Properties["sessionid"] = GetSessionId(); 
    _logger.Log(loggerBoundaryDeclaringType, level, message, exception); 
} 

至於其他日誌的平臺,您可以看看NLog。新版本最近作爲Beta版發佈。它有許多與log4net類似的功能。

您可能還會考慮使用舊的System.Diagnostics.TraceSource。如果你走這條路,在codeplex上查看Ukadc.Diagnostics。這是System.Diagnostics的插件庫,它提供了豐富的消息格式化功能(類似於您可以使用log4net和NLog執行的操作)。 Ukadc.Diagnostics的一個好處是它是一個僅配置的依賴項。您不必採用源或引用依賴來使用它。

1
> ... we're using log4Net. Do you have any suggestion on alternative library? 

您可以使用common.logging(http://netcommon.sourceforge.net)這是一個很小的記錄,包裝與

  • log4net的
  • n日誌
  • 企業庫記錄

一起工作由於必須配置什麼日誌記錄引擎,它使日誌記錄配置有點複雜要使用並且您還必須配置日誌記錄引擎。

它的日誌API靈感來自log4net-api