2015-02-10 85 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块有时会希望引发异常并且有时会扼杀它们,但其他方式的行为完全相同,则有一个用于选择问题报告行为的参数将比为独立代码和等待异常场景。