代码执行期间报告信息:最佳设计 [英] Reporting information during code execution: best design

查看:110
本文介绍了代码执行期间报告信息:最佳设计的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



假设你有以下(愚蠢的,简单的)案例,我一直怀疑设计正确的执行报告。我将使用python。

  def doStuff():
doStep1()
doStep2()
doStep3()

现在,假设你想给出各种步骤的报告,如果有的话出现错误等不是真的调试:只是应用程序的信息行为。



第一个简单的解决方案是打印

  def doStuff():
打印开始做东西
打印我开始做第1步
doStep1()
打印我做了第1步
打印我开始做第2步
doStep2()
打印我做了第2步
打印我是开始做第3步
doStep3()
打印我做了第3步



一般来说,这是非常糟糕的。假设这个代码最终会在库中。我不会指望我的图书馆打印出来的东西。我希望它默默地做这份工作。不过,有时我想提供信息,不仅在调试情况下,还要让用户知道某些事情实际上正在完成。打印也是坏的,因为您无法控制您的邮件的处理。它只是去stdout,没有什么可以做的,除了重定向。



另一个解决方案是有一个模块进行记录。

  def doStuff():
Logging.log(开始做东西)
Logging.log(我开始做步骤1)
doStep1()
Logging.log(我做了第1步)
Logging.log(我开始做第2步)
doStep2 )
Logging.log(我做了第2步)
Logging.log(我开始做第3步)
doStep3()
Logging.log(我做了第3步)

这有一个优点,你知道一个独特的地方你的日志记录服务,您可以根据需要修改此服务。您可以将其静音,将其重定向到文件,stdout甚至网络。缺点是您与日志记录模块有很强的耦合。基本上你的代码的每个部分都取决于它,并且你有电话记录到处都可以。



第三个选项是拥有一个清晰接口的报表对象,并且你通过$ do $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $
reporter.log(我开始做第1步)
doStep1()
reporter.log(我做了第1步)
reporter.log(I我开始做第2步)
doStep2()
reporter.log(我做了第2步)
reporter.log(我开始做第3步)
doStep3()
reporter.log(我做了第3步)

如果他们有更多的话,你也可以将记者对象传递给doStepX()。
优点:减少与模块的耦合,但它引入了与NullReporter对象的实例化的耦合。这可以通过使用None作为默认值并在调用日志之前进行检查来解决,这是笨拙的,因为在python你必须每次都写一个条件(在C中你可以定义一个宏)


$ b $

如果记者不是没有:
reporter.log(开始做东西)
#等等...

编辑:
另一个选项是工作类似Qt,并有一个emit()信号策略。当您的代码执行时,它会发送具有适当状态代码的信息,任何有兴趣的人都可以订阅信号并提供信息。非常干净,非常分离,但需要一点编码,因为我不认为这可以用包含的python电池快速完成。



最后,你可以使用有意义的错误消息引发异常,但是当您退出错误条件时,这当然可以使用。它不适用于偶尔的报告。



编辑:我想澄清一个事实,即情况更笼统,而不仅限于一系列被调用的步骤。它也可能涉及控制结构:

 如果断开连接:
打印尝试连接
connect )
else:
打印从远程主机获取文件列表
getRemoteList()

报告也可能在实际的例程中,所以你将在connect()和getRemoteList()例程中有一个print作为第一个语句。



因此,问题是:




  • 您认为某些代码的最佳设计是什么(特别是在图书馆)同时沉默时,噪音可能会破坏客户端,但冗长的时候有用?

  • 如何处理逻辑代码和报告代码之间的平衡混合?

  • 代码和错误检查之间的混合已经解决了例外。从代码逻辑中分离报告的噪音可以做些什么?






编辑:更多想法的想法



我认为这不仅仅是将Logging代码与逻辑代码分离。我认为这也是信息生产与信息消费脱钩的问题。已经存在类似的技术,特别是处理UI事件,但是我并没有看到与日志记录问题相同的模式。





$ b $编辑:我接受了马塞洛的回答,因为他指出在这种情况下妥协是最好的解决方案的事实证据,并没有任何银弹。然而,所有其他人也是有趣的答案,我真的很高兴能够提升他们。感谢您的帮助!

解决方案

我认为有一点你必须画一条线,妥协。
我没有办法完全解除系统日志记录,因为你必须在某个地方以某种方式发送这些消息。



我会去默认的日志记录模块,因为...它是默认的模块。它有很好的文档,并带有默认的库,所以在这里没有依赖关系。另外,你可以保存自己重新开发轮子。



这就是说,如果你真的在做新的事情,你可以创建一个全球的记者对象。您可以在流程开始时进行实例化和配置(日志记录,无日志记录,重定向流等),即使在每个进程/功能/步骤的基础上),也可以从任何地方调用它,无需传递(也许在多线程环境,但这将是最小的)。



您还可以将其放在另一个线程中,并捕获日志事件a la Qt。


I always had doubts when it comes to designing proper report of execution.

Say you have the following (stupid, to be simple) case. I will use python.

def doStuff():
    doStep1()
    doStep2()
    doStep3()

Now, suppose you want to give a report of the various steps, if something goes wrong etc. Not really debug: just informative behavior of the application.

A first, easy solution is to put prints

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"

In general, this is quite bad. Suppose that this code is going to end up in a library. I would not expect my library to print stuff out. I would expect it to do the job silently. Still, sometimes I would like to provide information, not only in debug situations, but also to keep the user informed that something is actually in the process of being done. Print is also bad because you don't have control of the handling of your messages. it just goes to stdout, and there's nothing you can do about it, except redirection.

Another solution is to have a module for logging.

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")

This has the advantage that you sort of know a unique place for your logging service, and you can tinker this service as much as you want. You can silence it, redirect it onto a file, to stdout, or even to a network. Disadvantage is that you get a very strong coupling with the Logging module. Basically every part of your code depends on it, and you have calls to logging everywhere.

The third option is to have a report object with a clear interface, and you pass it around

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")

Eventually, you can also pass the reporter object to doStepX() if they have more to say. Advantage: it reduces coupling with a module, but it introduces coupling with the instantiation of the NullReporter object. This can be solved by using None as default and checking before calling log, which is clumsy, because in python you have to write a conditional every time (in C you could define a macro)

def doStuff(reporter=None):
    if reporter is not None:
        reporter.log("starting doing stuff")
        # etc...

Edit: Another option is to work Qt-like, and have an emit() signal strategy. As your code executes, it emits information with proper status codes, and anyone interested can subscribe to the signals and provide info. Nice and clean, very decoupled, but requires a little of coding, as I don't think this can quickly be done with the python battery included.

Finally, you can raise exceptions with a meaningful error message, but this of course can be used only if you are exiting from an error condition. it does not work for occasional reporting.

Edit: I'd like to clarify the fact that the situation is more general, and not limited just to a sequence of invoked steps. it could also involve control structures:

 if disconnected:
     print "Trying to connect"
     connect()
 else:
     print "obtaining list of files from remote host"
     getRemoteList()

The report could also be into the actual routines, so you would have a "print" in the connect() and getRemoteList() routines as a first statement.

The question therefore are:

  • What do you think is the best design for some code (notably in the case of a library) to be at the same time silent when noise could be disruptive for the client, but verbose when useful?
  • How to handle a balanced intermix between logic code and reporting code ?
  • Intermixing between code and error checking has been solved with exceptions. What could be done to partition the "noise" of reporting from the code logic ?

Edit: more thoughts for the mind

I think it's not only a matter of decoupling the Logging code from the logic code. I think it's also a matter of decoupling the information production from the information consumption. Similar techniques already exist, in particular to handle UI events, but I don't really see the same patterns applied to the logging problem.


Edit: I accepted the answer from Marcelo because he points out at the factual evidence that a compromise is the best solution in this case, and there's no silver bullet. However, all the others were interesting answers as well, and I was really pleased to upvote all of them. Thanks for the help!

解决方案

I think there is a point where you must draw a line and make a compromise. I see no way to completely decouple logging from the system because you have to send those messages somewhere and in a way that someone understands.

I would go with the default logging module, because... it's the default module. It's well documented and comes with the default library, so no dependency issues here. Also, you save yourself from reinventing the wheel.

That said, if you are really into doing something new, you could make a global reporter object. You can instantiate and configure it at the beginning of your process (logging, no logging, redirecting streams, etc. Even in a per process/function/step basis) and call it from everywhere, no need to pass it around (maybe in a multi threaded environment, but that would be minimal).

You can also put it inside another thread and catch log events a la Qt.

这篇关于代码执行期间报告信息:最佳设计的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆