2015-02-10 90 views
1

我正在設計一個小型庫,它可以幫助登錄到不同的目的地(文件,數據庫等)。但是,如果出現錯誤(例如無法寫入文件),我不確定是否應該拋出異常?應該記錄代碼拋出異常?

如果我拋出異常(與記錄相關),使用我的庫的應用程序開發人員可以清楚地看到記錄不會按預期發生。另一方面,它可能是問題的另一個來源。

如果我壓制例外而只是悄悄地不記錄,開發者可能會錯過重要的信息,例如,數據庫無法到達。

是否有任何建議,一般準則(如果一個然後b等)如何處理這個?


正如我至今讀:

Microsofts Guidelines for Exceptions狀態:

✗沒有公有成員,可以基於一些選項扔與否。

因此,選擇是否拋出異常將違反這些準則,但如果不確定拋出異常的可能性有多大,它們不會發出拋出異常的聲明。

我還在this question/answer中讀到我不應該捕捉異常,因爲我無法對它們做任何有意義的事情,但問題是針對企業級系統,而我的問題是在更一般的層面上提出的。

+7

這似乎是一個設計決定。我不認爲有一個絕對正確的答案。 – 2015-02-10 15:47:15

+2

^同意。這對於https://programmers.stackexchange.com/來說似乎更合適,儘管它可能仍然不符合堆棧交換問題的一般要求,因爲答案可能是有見地的。 – ajp15243 2015-02-10 15:47:56

+0

一種可能性是將輸出異常輸出到「Trace」。他們可以使用你的庫來正常登錄,但他們可以選擇配置'Trace',並且記錄錯誤將寫入文件或Windows事件日誌中,這應該總是成功。 – 2015-02-10 15:49:46

回答

3

不要教條地遵守任何指導原則。諮詢指導方針,然後做你認爲最適合解決眼前問題的方法。

記錄器是一個特殊的軟件:它有特殊的需求和考慮。因此,微軟發佈的指南並不適用於您的記錄器,其方式與適用於通用軟件的方式完全相同。

在我的書中,根據「Is-This-A-Development-Environment」標誌來改變記錄器的行爲並且拋出異常(如果是true),或者抑制這些異常否則容易出錯的介質)。

+0

非常真實。實際上,我以前沒有考慮過這個問題! – 2015-02-10 17:09:08

1

有意思的是,就在本週我爲我的一個應用程序添加了一個新的NLog目標,它沒有記錄,但也沒有抱怨。因此,我感到NLog團隊已經做出了關於失敗日誌目標的決定。我可以告訴你,NLog默默無法登錄到目標。

但是 - 不完全。他們這樣做有一個內部的記錄,你可以用它來調試記錄:https://github.com/NLog/NLog/wiki/Internal-Logging 您可以配置像這樣:

<nlog internalLogFile="c:\log.txt" internalLogLevel="Trace"> 
    <targets> 
     <!-- target configuration here --> 
    </targets> 
    <rules> 
     <!-- log routing rules --> 
    </rules> 
</nlog> 

由於NLOG(與log4net的一起)可能是用於.NET最大的日誌記錄庫,這可能對你感興趣。

我見過的另一件事是,一些圖書館引用https://www.nuget.org/packages/Common.Logging/,我發現它非常優雅。這是一個非常輕量級的軟件包,包含一系列可用於登錄的接口。然後調用程序集通過使用適用於NLog或Log4Net的適配器來控制輸出發生的情況,並繼續使用預先存在的目標。

+0

NLog的策略只能解決問題,並不能解決問題。如果在使用內部記錄器時'C:'磁盤已滿(或超出用戶配額)會發生什麼?它會拋出嗎? – 2015-02-10 15:57:31

+0

好點 - 我不知道。 – 2015-02-10 15:58:22

1

正如評論已經指出的那樣,這是一個設計決定,所以沒有從技術意義上說是正確的答案。

我通常不喜歡這樣:

  • 如果出現問題,那我就拋出一個異常的第一次嘗試。
  • 我在日誌框架本身內部捕獲了這個異常,並將其寫入系統的事件日誌(應該總是成功)。
  • 如果由於某種原因也失敗了,我會默默吞下錯誤。
  • (可選)您可能會在調試版本中重新引發異常,或將其寫入調試輸出。
0

我建議有很多情況下,來自微軟的引用語句應該被忽略。我建議作爲一個日誌記錄類的模式,將有一個方法返回一個「日誌抑制」標記,然後扼殺在日誌記錄過程中發生的異常,但有一個方法,取消對數抑制的影響令牌,並根據傳入的參數返回已被抑制的異常列表,否則當列表非空時拋出包含列表的組合異常。我會進一步建議記錄請求要求令牌以後進先出的方式使用,並且在取消先前創建的效果之前未能取消效果應該被認爲是一種例外 - 值得使用錯誤。

即使它違背了微軟的建議,有一個方法拋出或不基於參數有兩個優勢無法以其他方式獲得:

  1. 有很多情況下這將支持一試的操作/ do模式調用支持相同模式的方法。如果公共try/do方法鏈接到一個使用參數區分「try」和「do」的方法,並且要調用的嵌套方法也支持這樣一個參數,那麼可以使用「try」和「do 「方法共享相同的實現。如果所有公共方法都是「只嘗試」或「只做」,則「do」需要內部方法中的問題出現爲它們拋出的異常,「try」不希望嵌套「do」方法拋出異常將有趕上,那麼即使調用程序試圖在內部使用的共享代碼,他們會最終不得不:

    if (throwOnException) 
    { 
        thing.ReadData(whatever); 
        success = true; 
    } 
    else 
    { 
        success = thing.TryReadData(whatever); 
    } 
    

    的代碼足夠大,它應該是它自己的方法片段,但其語義上屬於比客戶更多thing

  2. 一個try/finally塊應該只沒有,如果一切都在tryfinally段內成功拋出異常退出。但是,如果在try中發生異常,那麼傳播該異常通常比由finally中引發的異常覆蓋該異常要好。無論try塊是否成功,finally代碼的行爲通常都是相同的,之外應當允許try塊成功傳播時發生的異常,而應該抑制try塊出現故障時出現的異常。

無論是C#,也不VB提供了finally塊知道try是否成功的一個好方法,但它是可能的。如果finally塊有時會希望引發異常並且有時會扼殺它們,但其他方式的行爲完全相同,則有一個用於選擇問題報告行爲的參數將比爲獨立代碼和等待異常場景。