簡體   English   中英

使用log4net包含日志記錄的最佳做法是什么?

[英]What are the best practices for including logging using log4net?

我被告知使用log4net將“日志記錄”添加到我的代碼中,問題是沒有人可以及時訪問並查看需要使用日志記錄解決的實際問題。

因此,無論如何都要有一套指導,以便獲得合理的成本/收益權衡

因此:

應該在以后有用的應用程序中添加哪種日志記錄?

(代碼使用了很多WCF ,一方是Winforms,另一方是通常在同一台機器上運行的“服務器”)

-

我已經將AJM的答案排除在做有用的博客文章之前,並指出了很多評論,但如果有人想出一套很好的“ 經驗法則 ”,我很可能會改變預期的答案。

需要記住的一點是,雖然您的配置將處理不同級別的日志記錄,但您可能會在日志調用中造成大量開銷。 例如:

// some kind of loop
// do some operations
Logger.LogDebug(myObject.GetXmlRepresentation());
// end loop

如果您有一個記錄器監聽DEBUG日志,這顯然只會記錄該對象,但是無論您的日志記錄級別如何,構建XML對象的調用都會運行,並且可能導致一些相當大的速度減慢。


正確的解決方案是:

// some kind of loop
// do some operations
if (Logger.IsDebug)
{
    Logger.LogDebug(myObject.GetXmlRepresentation());
}
// end loop

我發現這篇文章非常有用: http//blog.codinghorror.com/the-problem-with-logging/

特別是我認為極簡主義的方法確實是要走的路。 在過去,我試圖記錄太多,但這會使代碼膨脹

還認為越多的日志條目越好,因為它會使日志本身膨脹。 我現在將loggings的主要好處看作是提供“立足點”或概述正在發生的事情。 如果特定區域需要更多細節,那么它是默認位置應該更少更好

我最喜歡這類問題的信息來源是Release It--一本來自Pragmatic人的書。 強烈推薦。

他們關於您的問題的基本觀點是,日志記錄應該針對運營級別所需的內容。 運營人員最關心的是網站可能出現故障的特殊情況(即連接池已滿,與服務器的連接已關閉等)確保消息不言自明,並且非常清楚問題是什么,如果適用,修復是什么。 寫下供人食用的信息。

我在功能進入/退出樣式日志中看到了一點點。 頂級捕獲異常的堆棧跟蹤很有用,可以記錄可能發生系統崩潰的區域(即完整連接池),以及記錄系統崩潰之前的區域。

通常,對於日志記錄,我按以下順序添加日志記錄:

  1. 功能輸入/退出
  2. 函數內部的主要邏輯步驟
  3. 詳細記錄所有中間計算

很顯然,我很少到達最后一個,如果你為log4net滾動你自己的包裝並使用處理模式,可能還有一些反射魔法,那么第一個很容易做到。

第二個通常在驗收/集成和回歸測試期間完成,因為主要邏輯流程和問題區域被識別。 在此階段添加日志記錄也相當少,因為您通常知道在調試和測試時需要添加日志記錄。

第三個通常(對我來說無論如何)只在經歷回歸的代碼部分中完成,或者特別重要。

我已經為log4net實現了一個基本的包裝器對象,它為我提供了直接的日志記錄功能以及一個上下文對象,可以與IDisposable一起使用,將“進入/退出”邏輯包裝在一個漂亮的易用包中。

log4net的一大優點是您可以將事件記錄到不同的類別。 默認值為Debug,Info,Warning和Error。 我喜歡這些意思

調試 - 非常詳細,包含大量調試信息。 例如,SQL查詢。
信息 - 有用的信息很有用。
警告 - 沒什么致命的,但操作員應該意識到這個問題。
錯誤 - 應用程序現在不穩定,日志包含診斷信息,例如異常消息和堆棧跟蹤。

在代碼中使用這些,例如

_log.Info("Updating object.");

會向任何感興趣的聽眾寫一個INFO級別的消息。

然后,您可以在配置中連接偵聽器使用日志消息執行操作。 這是我正在使用的一個:

<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date [%thread] %-5level %logger [%ndc] - %message%newline" />
  </layout>
</appender>
<appender name="FileAppender" type="log4net.Appender.FileAppender">
  <file value="c:\temp\servicelog.txt" />
  <appendToFile value="true" />
  <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date [%thread] %-5level %logger [%ndc] - %message%newline%exception" />
  </layout>
</appender>
<root>
  <level value="ERROR" />
  <appender-ref ref="ConsoleAppender" />
</root>
<logger name="Warehouse.Core">
  <level value="INFO" />
  <appender-ref ref="FileAppender" />
</logger>
</log4net>

這表示:所有ERROR消息都發送到控制台,所有INFO消息都從記錄器Warehouse.Core發送到給定文件。

由於偵聽器的類別連接是在配置中完成的,因此您可以在部署后更改日志記錄。 如果沒有人正在收聽,那么記錄幾乎沒有性能損失。


關於伐木的成本與效益,在太多的伐木(沒有人會使用的大型原木)和不夠的(一條線說“失敗”)之間肯定會有一個最佳點。

我的策略是記錄INFO可能失敗的東西:外部依賴(應用程序啟動,服務調用,SQL連接),以及DEBUG更復雜的內容代碼(業務邏輯中的診斷消息,單個SQL調用,一些方法調用)。

不常見的情況(例如)默認值通常不會轉到WARN,異常轉到ERROR或FATAL。

另外:請記住,WCF具有最優秀的服務跟蹤查看器,允許您“向下鑽取”到單個數據包以及它們如何由堆棧的兩端處理。 在沒有代碼更改的情況下,配置也可以使用它。 因此,我通常只會對WCF服務調用和響應進行非常簡短的記錄。

應該在以后有用的應用程序中添加哪種日志記錄?

如果從自己的異常類中拋出異常,甚至更好,所有異常類都派生自基類,在(基本)異常構造函數中添加ERROR級別日志記錄; 節省你必須記住每次捕獲/拋出。 如果你有一個很大的代碼庫,這很有用。

對於CLR或第三方異常,請記錄Exception.ToString()而不僅僅是消息,否則您將錯過完整的堆棧跟蹤(假設程序員不會吞下異常或重新拋出sans內部異常)

在您知道或懷疑您將遇到問題的區域專注於DEBUG詳細信息(只需詢問質量保證或技術支持在哪里查看;-)

如果遵循穩健性原則 ,那么當您忽略或更改輸入或預期行為時,您可能需要INFO或WARN日志記錄。 如果您的WCF服務開始接收意外(但可解析)輸入,這可能很有用。

為了確保您的應用程序運行良好,請不要在默認情況下啟用DEBUG級別日志記錄的情況下發送/安裝它,ERROR或WARN可能是最佳選擇。

我不同意接受的答案的最后部分,因為log4net具有很棒的過濾功能; 在你的程序員理解日志記錄成本(根據CK的答案)並且他們(以及QA和技術支持)知道過濾器的情況下,並且在DEBUG配置所有內容是一個壞主意。 如果您在DEBUG級別登錄大型對象圖,xml文檔,db結果等,請將其包裝在一些代碼中,以減少開銷:

if (log.IsDebugEnabled)
{
    log.DebugFormat("Loaded in {0} ms {1}", timer.ElapsedMilliseconds, dataSet.GetXml());
}

我建議你遵循推薦的靜態logger-per-class方法,因為它必須使日志更有用,當你必須實際使用它並使用過濾器縮小問題時,例如LoggerMatchFilter。

如果您遵循這種方法並且願意采用(相當小的)性能命中,這里有一種使用堆棧跟蹤為任何類創建ILog對象並確保配置文件連接以監視更改的方法:

public static class LogFactory
{
    /// <summary>
    /// Create log whose name is the calling methods class name.
    /// </summary>
    /// <remarks>
    /// <para>
    /// Configures the log repository if it hasn't been configured before.
    /// </para>
    /// <para>
    /// Creates a debug log message right after getting the logger, this follows
    /// the log4net recommendation to log first message as early as possible.
    /// </para>
    /// </remarks>
    /// <returns>Log ready for work.</returns>
    public static log4net.ILog Create()
    {
        var method = new StackTrace().GetFrame(1).GetMethod();
        var log = log4net.LogManager.GetLogger(method.DeclaringType);

        if (log4net.LogManager.GetRepository().Configured == false)
        {
            try
            {
                new FileIOPermission(FileIOPermissionAccess.Read,
                    AppDomain.CurrentDomain.SetupInformation.ConfigurationFile)
                    .Demand();

                var configFile = new FileInfo(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
                log4net.Config.XmlConfigurator.ConfigureAndWatch(configFile);
                log.DebugFormat("Log4net configured and watching {0}", configFile.FullName);
            }
            catch (System.Security.SecurityException e)
            {
                log.DebugFormat("Unable to watch config file due to security permissions. {0}", e.ToString());
            }
        }

        log.DebugFormat("Logging {0}", log.Logger.Name);

        return log;
    }
}

記錄並不是一件容易的事,但我的經驗是所有日志都應該可以為負責任的各方搜索。 錯誤的有用目標是直接發送電子郵件(在某些情況下是短信)。 但最終所有日志記錄數據都應該可以在具有可選用戶界面的數據庫中進行搜索。

當收到特定帳戶的電子郵件時,可以將其處理並直接放入數據庫。 下面有som類別和處理規則:

  • 嚴重錯誤:應立即使用電子郵件/短信
  • 未來問題:每日/每周電子郵件
  • 調試信息==>每日/每周電子郵件,其中包含自上次以來產生的調試信息量的通知。

調試的內容可以以不同的方式寫入數據庫,但我們需要調整性能。 在“生產模式”下不應將大量數據寫入數據庫。 這應該在每日/每周的基礎上完成。 最好的方法是生成本地文件(例如XML或純文本),並在維護時間(晚上)將此文件放入數據庫。 應該可以啟動/停止調試會話,並且僅在調試會話完成時將調試信息寫入數據庫。

調試組件可以實現為WCF和log2net,並且可以定期訪問數據庫和/或定期放入數據庫的本地文件存儲。

有一件事是清楚的......所有錯誤/異常都應記錄在某處。 沒有什么比失去的錯誤消息更令人惱火:)

快樂的調試!

將事件記錄到事件查看器。

明智地使用INFO DEBUG WARNING和ERROR。

開發時顯示生產中的所有內容(在服務器端使用控制台 - 見下文),僅記錄錯誤(可配置)

我在每個類的乞討中創建一個記錄器,給它typeof(myClass),但這是可選的......

我在DEV中作為控制台應用程序托管WCF - 所以在控制台中也很容易看到服務器日志,但是一旦它成為服務,你必須使用事件查看器....

啊 - 如果你將它與WCF“調用時間”(從客戶端調用到服務器)的速度非常快,那么它不會真正影響你的時間,除非你有像瘋了一樣的日志(例如nHibernate))

對於WCF,可能有更好的方法來做這件事; 對於WinForms,您可以考慮查看PostSharp 這將允許您記錄方法調用而不會使代碼混亂。 在幕后你仍然會使用優秀的log4net。

警告:我自己沒有用過它; 我在代碼營看到了一個非常令人印象深刻的演示文稿。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM