【发布时间】:2009-04-12 00:37:06
【问题描述】:
在设计正确的执行报告时,我一直有疑问。
假设您有以下(愚蠢的,简单来说)案例。我会用python。
def doStuff():
doStep1()
doStep2()
doStep3()
现在,假设您想要报告各个步骤,如果出现问题等。不是真正的调试:只是应用程序的信息行为。
第一个简单的解决方案是放置打印件
def doStuff():
print "starting doing stuff"
print "I am starting to do step 1"
doStep1()
print "I did step 1"
print "I am starting to do step 2"
doStep2()
print "I did step 2"
print "I am starting to do step 3"
doStep3()
print "I did step 3"
总的来说,这很糟糕。假设这段代码最终会出现在一个库中。我不希望我的图书馆把东西打印出来。我希望它能够默默地完成这项工作。尽管如此,有时我还是想提供信息,不仅是在调试情况下,而且还要让用户知道某些事情实际上正在完成的过程中。打印也很糟糕,因为您无法控制消息的处理。它只是进入标准输出,除了重定向之外,你无能为力。
另一种解决方案是有一个用于日志记录的模块。
def doStuff():
Logging.log("starting doing stuff")
Logging.log("I am starting to do step 1")
doStep1()
Logging.log("I did step 1")
Logging.log("I am starting to do step 2")
doStep2()
Logging.log("I did step 2")
Logging.log("I am starting to do step 3")
doStep3()
Logging.log("I did step 3")
这样做的好处是您知道日志服务的独特位置,并且您可以随意修改此服务。您可以将其静音、将其重定向到文件、stdout 甚至网络。缺点是您与 Logging 模块的耦合非常强。基本上你的代码的每一部分都依赖于它,而且你到处都可以调用日志记录。
第三种选择是有一个界面清晰的报表对象,然后你传递它
def doStuff(reporter=NullReporter()):
reporter.log("starting doing stuff")
reporter.log("I am starting to do step 1")
doStep1()
reporter.log("I did step 1")
reporter.log("I am starting to do step 2")
doStep2()
reporter.log("I did step 2")
reporter.log("I am starting to do step 3")
doStep3()
reporter.log("I did step 3")
最后,如果他们有更多话要说,您也可以将记者对象传递给 doStepX()。 优点:它减少了与模块的耦合,但它引入了与 NullReporter 对象的实例化的耦合。这可以通过使用 None 作为默认值并在调用 log 之前检查来解决,这很笨拙,因为在 python 中你必须每次都编写一个条件(在 C 中你可以定义一个宏)
def doStuff(reporter=None):
if reporter is not None:
reporter.log("starting doing stuff")
# etc...
编辑: 另一种选择是像 Qt 一样工作,并有一个 emit() 信号策略。当您的代码执行时,它会发出带有适当状态代码的信息,任何有兴趣的人都可以订阅信号并提供信息。漂亮干净,非常解耦,但需要一点编码,因为我认为使用随附的 python 电池无法快速完成。
最后,您可以使用有意义的错误消息引发异常,但这当然只能在您退出错误条件时使用。它不适用于偶尔的报告。
编辑:我想澄清一个事实,即情况更普遍,而不仅限于一系列调用的步骤。它还可能涉及控制结构:
if disconnected:
print "Trying to connect"
connect()
else:
print "obtaining list of files from remote host"
getRemoteList()
报告也可以包含在实际的例程中,因此您将在 connect() 和 getRemoteList() 例程中作为第一条语句进行“打印”。
因此问题是:
- 您认为对于某些代码(尤其是在库的情况下)而言,在噪音可能对客户端造成干扰时保持沉默但在有用时冗长的最佳设计是什么?
- 如何处理逻辑代码和报告代码之间的平衡混合?
- 代码和错误检查之间的混合已通过异常解决。如何将报告的“噪音”从代码逻辑中分离出来?
编辑:头脑中的更多想法
我认为这不仅仅是将 Logging 代码与逻辑代码分离的问题。我认为这也是信息生产与信息消费脱钩的问题。类似的技术已经存在,特别是用于处理 UI 事件,但我并没有真正看到相同的模式应用于日志记录问题。
编辑:我接受了 Marcelo 的回答,因为他指出事实证据表明在这种情况下妥协是最好的解决方案,并且没有灵丹妙药。然而,所有其他的答案也很有趣,我真的很高兴为所有答案投票。感谢您的帮助!
【问题讨论】:
-
我添加了一个赏金,看看是否可以对这个问题进行进一步的讨论。还有,这是 mu 的第一次赏金开放,所以我也很好奇。