有人告诉我使用 log4net 将“日志记录”添加到我的代码中,问题是没有人可以及时旅行并查看日志记录需要用来解决哪些现实世界问题。
因此,是否存在一套关于记录内容的准则,以便获得合理的成本/收益权衡?
所以:
应该添加什么类型的日志记录
到一个有用的应用程序
稍后?
(代码使用了很多WCF,一侧是Winforms,另一侧是通常在同一台机器上运行的“服务器”)
——
我已经排除了AJM的答案来制作有用的博客帖子中有很多评论,但如果有人提出了一套很好的“经验法则”我可能会改变预期的答案。
I have been told to add “logging” to my code using log4net, the problem is no one can travel in time and see what real world problems the logging will need to be used to solve.
Therefore is there a set of guidlines anyway as to what to log so as to get a reasonable cost/benefit trade off?
Therefore:
What kinds of logging should one add
to an application that would be useful
later?
(The code uses a lot of WCF, one side is in Winforms, the other side is a “server” that normally run on the same machine)
--
I have excepted AJM's answers to do the useful blog post with lot of comments it points to, but if someone comes up with a nice set of "rules of thumb" I am likely to change the expected answer.
发布评论
评论(9)
需要记住的一件事是,虽然您的配置将处理不同级别的日志记录,但您可能会在日志调用中造成沉重的开销。例如:
这显然只会在您有一个监听 DEBUG 日志的记录器时记录该对象,但是无论您的日志记录级别如何,构建 XML 对象的调用都会运行,并且可能会导致相当大的速度减慢。
正确的解决方案是:
One thing to bear in mind is that whilst your configuration will handle logging at different levels, you may be causing heavy overhead in your log calls. For example:
This will obviously only log the object if you have a logger listening to DEBUG logs, however the call to build the XML object will run regardless of your logging level and could cause some considerable slowdowns.
The correct solution would be:
我发现这篇文章非常有帮助:http://blog.codinghorror.com/the- Problem-with-logging/
特别是,我认为极简主义方法确实是可行的方法。过去,我尝试记录太多日志,但这会使代码膨胀。
另外,日志条目越多越好的想法也是错误的,因为它会使日志本身膨胀。我现在认为日志记录的主要好处是提供“立足点”或对正在发生的事情的概述。如果特定区域需要更多细节,那就这样吧,但默认位置应该越少越好
I found this article very helpful: http://blog.codinghorror.com/the-problem-with-logging/
In particular I think a minimalist approach is indeed the way to go. In the past I've tried to log too much but this bloats the code
Also the thinking that the more log entries the better is wrong because it bloats the logs themselves. I now look at loggings main benefit as providing a "foothold" or overview of what is going on. If more detail is needed for particular areas then so be it but the default position should be less is better
对于此类问题,我最喜欢的信息来源是 Release It - 一本来自 Pragmatic 的书伙计们。强烈强烈推荐。
他们关于您的问题的基本观点是,日志记录应该适合操作级别的需要。运营人员最关心的是站点可能出现故障的异常情况(即连接池已满、与服务器的连接已断开等)。确保消息是不言自明的,并且非常清楚问题所在,如果适用,修复是什么。编写供人类消费的消息。
我在函数入口/出口样式日志中看不到什么意义。顶级捕获异常的堆栈跟踪很有用,记录可能发生系统崩溃的区域(即完整连接池)也很有用,就像记录系统之前崩溃的区域一样。
My favorite source of information for this kind of question is Release It - a book from the Pragmatic guys. Highly highly recommended.
Their basic point in regards to your question is that logging should be geared toward what is needed at the operational level. Operations guys are most concerned with exceptional things where the site may be going down (i.e. connection pool is full, connection to a server is down, etc.) Make sure the messages are self-explanatory and exceedingly clear as to what the problem is, and if applicable what the fix is. Write the messages for human consumption.
I see little point in function entry/exit style logs. Stack traces for top-level caught exceptions are useful, logging around areas where system crash can happen (i.e. full connection pool) is useful, as is logging around areas where the system crashed before.
一般来说,对于日志记录,我按以下顺序添加日志记录:
显然,我很少到达最后一个,如果您自己动手,则第一个是微不足道的log4net 的包装器并使用处置模式,可能还有一点反射魔法。
第二个通常是在验收/集成和回归测试期间完成,因为主要逻辑流程和问题区域已被识别。在这个阶段添加日志记录也是相当少的,因为您通常知道在调试和测试时需要在哪里添加它。
第三个通常(无论如何对我来说)仅在经历回归或特别重要的代码部分中完成。
我已经为 log4net 实现了一个基本的包装器对象,它为我提供了直接日志记录功能以及一个上下文对象,该对象可以与 IDisposable 一起使用,将“进入/退出”逻辑包装在一个很好的方便的包中。
In general with logging I add logging in the following order:
Obviously I rarely get to the last one, the first one is trivial to do if you roll your own wrapper for log4net and use the disposing pattern, and possibly a little reflection magic.
The 2nd one is done generally during acceptance/integration and regression testing as major logic flow and problem areas are identified. Adding logging at this stage is also fairly minimal as you know in general where you need to add it as you are debugging and testing.
The 3rd is generally (for me anyways) only done in sections of code that experience regressions, or are particularly important.
I have implemented a basic wrapper object for log4net which provides me direct logging capabilities as well as a context object which can be used with IDisposable to wrap "enter/exit" logic in a nice convient package.
log4net 的一大优点是您可以将事件记录到不同的类别。默认值为“调试”、“信息”、“警告”和“错误”。我喜欢这些表示
调试 - 非常详细,包含大量调试信息。例如,SQL 查询。
信息 - 值得了解的有用信息。
警告 - 没有什么致命的,但操作员应该意识到这个问题。
错误 - 应用程序现在不稳定,日志包含诊断信息,例如异常消息和堆栈跟踪。
在代码中使用这些,例如
_log.Info("Updating object.");
会将 INFO 级别消息写入任何感兴趣的侦听器。
然后,您可以在配置中连接侦听器来处理日志消息。这是我正在使用的一个:
这表示:发送到控制台的所有错误消息,从记录器 Warehouse.Core 发送到给定文件的所有信息消息。
由于类别与侦听器的连接是在配置中完成的,因此您可以在部署后更改日志记录。如果没有任何东西在监听,那么记录日志几乎不会造成性能损失。
关于日志记录的成本与收益,在太多日志记录(没有人会使用的巨大日志)和日志记录不足(一行显示“失败”)之间肯定存在一个最佳点。
我的策略是在 INFO 处记录可能失败的内容:外部依赖项(应用程序启动、服务调用、SQL 连接),并在 DEBUG 处记录更复杂的内容代码(业务逻辑中的诊断消息、单个 SQL 调用、某些方法调用)。
在不寻常的情况下(例如)采用通常不采用的默认值,会出现 WARN,异常情况会出现 ERROR 或 FATAL。
另外:请记住,WCF 有一个最优秀的服务跟踪查看器,它允许您“深入”到各个数据包以及堆栈两端如何处理它们。这也可以通过配置实现,无需更改代码。因此,我通常只会对 WCF 服务调用和响应进行非常简短的日志记录。
One of the great things about log4net is that you can log events to different categories. The defaults are Debug, Info, Warning and Error. I like these to mean
Debug - very verbose, contains lots of debugging information. For example, SQL queries.
Info - useful information that's good to know.
Warning - nothing fatal but an operator should be aware of the problem.
Error - the application is now unstable, the log contains diagnostic information such as the exception message and stack trace.
Use these in code, so e.g.
_log.Info("Updating object.");
would write an INFO level message to any listener that was interested.
Then you can hook up listeners in configuration to do things with the log messages. Here's one that I'm using:
This says: all ERROR messages to the console, all INFO messages from the logger Warehouse.Core to the given file.
Because this wiring of categories to listeners is done in configuration, you can alter the logging after deployment. There's virtually no performance penalty to logging if nothing's listening.
Regarding the costs versus benefits of logging there definitely is a sweet spot between too much logging (huge logs that nobody will use) and not enough (a single line that says "fail").
My policy is to log at INFO what could fail: external dependencies (application startup, service calls, SQL connections), and at DEBUG the more complex bits of meaty code (diagnostic messages in business logic, individual SQL calls, some method invocations).
Unusual situations where (for example) defaults are taken that aren't usually would go to WARN, and exceptions go to ERROR or FATAL.
Also: bear in mind that WCF has a most excellent service trace viewer that allows you to "drill down" to individual packets and how they're processed by both ends of the stack. That, too, is available by configuration without code changes. Because of this I'll generally just do very abbreviated logging of WCF service calls and responses.
日志记录不是一件容易的事,但我的经验是,所有日志都应该可供责任方搜索。错误的有用目标是直接电子邮件(在某些情况下是短信)。但最终所有日志数据都应该可以在具有合理用户界面的数据库中进行搜索。
当特定帐户收到电子邮件时,可以对其进行处理并直接放入数据库中。有一些类别和处理规则如下:
调试的内容可以通过不同的方式写入数据库,但需要考虑性能。不应在“生产模式”下将大量数据写入数据库。这应该每天/每周进行一次。最好的方法是生成一个本地文件(例如 XML 或纯文本),并在维护时间(晚上)将该文件放入数据库中。应该可以启动/停止调试会话,并且仅在调试会话完成时将调试信息写入数据库。
调试组件可以实现为 WCF 和 log2net,并直接访问数据库和/或定期放入数据库的本地文件存储。
一件事很清楚......所有错误/异常都应该记录在某处。没有什么比丢失错误消息更令人恼火的了:)
调试愉快!
Logging is not an easy task, but my experience is that all logs should be searchable for responsible parties. An useful target for errors are email directly (and in some cases sms). But in the end all logging data should be searchable in a database with a sesible user interface.
When the email is received to a specific account, this can be processed and put in the database directly. There are som categories and handling rules below:
The content of the debugging can be written to the database in different way, but we need to concider performance. Large amount of data should not be written to database in "production mode". This should be done in daily/weekly bases. The best way is to produce a local file (such as XML or plain text) and put this file into the database during maintenance hours (at night). It should be possible to start/stop a debug session and only write the debug information to the database when the debug session is completed.
The debug component could be implemented as a WCF and log2net and directy access to the database and/or a local file store that is put into the database on regular basis.
One thing is clear...ALL errors/exception should be logged somewhere. Nothing is more irritating than lost error messages :)
Happy debugging!
如果您从自己的异常类抛出异常,或者更好的是,所有异常类都派生自基类,请在(基)异常构造函数中添加错误级别日志记录;使您不必记住每次接球/投掷。如果您有大量代码库,则很有用。
对于 CLR 或第 3 方异常,记录 Exception.ToString() 而不仅仅是消息,否则您会错过完整的堆栈跟踪(假设程序员没有吞下异常或重新抛出无内部异常)
在您知道的区域中重点关注调试细节或者怀疑您会遇到问题(只需询问 QA 或技术支持去哪里查找;-)
如果您遵循稳健性原则,那么当您忽略或更改输入或预期行为时,您可能需要 INFO 或 WARN 日志记录。如果您的 WCF 服务开始接收意外(但可解析)的输入,这可能会很有用。
为了确保您的应用程序性能良好,请勿在默认情况下启用调试级别日志记录的情况下运送/安装它,错误或警告可能是正确的方法。
我不同意已接受答案的最后一部分,因为 log4net 具有很棒的过滤功能;条件是您的程序员明白日志记录是有成本的(根据 CK 的答案),并且他们(以及 QA 和技术支持)了解过滤器,并且在 DEBUG 上配置所有内容是一个坏主意。如果您在 DEBUG 级别记录大型对象图、xml 文档、数据库结果等,请将其包装在一些代码中以减少费用:
我建议您遵循 推荐 每类静态记录器方法,只是因为当您必须实际使用它并缩小范围时,它应该使日志记录更加有用关于使用过滤器的问题,例如 LoggerMatchFilter。
如果您遵循这种方法并且愿意承受(相当小的)性能损失,那么这里有一种方法,它使用堆栈跟踪为任何类创建 ILog 对象,并确保配置文件已连接以监视更改:
If you throw exceptions from your own exception classes, or even better, all your exception classes derive from a base class, add ERROR level logging in the (base) exception constructor; saves you having to remember on each catch/throw. Useful if you have a large code base.
For CLR or 3rd party exceptions, log Exception.ToString() not just the message, otherwise you miss the full stack trace (assuming programmers are not swallowing exceptions or re-throwing sans inner exception)
Focus on DEBUG detail in areas where you either know or suspect you will have issues (just ask QA or Tech Support where to look;-)
If you follow the robustness principle, then you may want INFO or WARN logging when you ignore or change inputs, or expected behaviour. This could be useful if your WCF service starts receiving unexpected (but parseable) input.
To ensure your application performs well, don't ship/install it with DEBUG level logging enabled by default, ERROR or WARN is probably the way to go.
I disagree with the last part of the accepted answer, because log4net has awesome filtering capabilities; on the condition that your programmers understand that logging comes at a cost (as per CK's answer) and they (and QA and Tech Support) know about the filters, and that configuring everything at DEBUG is a bad idea. If you are logging at DEBUG level a large object graph, xml document, db result, et cetera, wrap it in some code that reduces the expense:
I would suggest you follow the recommended static logger-per-class approach, simply because it should make logging more useful when you have to actually use it and narrow down on a problem using filters, e.g. LoggerMatchFilter.
If you follow this approach and are willing take a (fairly small) performance hit, here's one way which uses a stack trace to create ILog objects for any class and ensure the config file is wired up to monitor for changes:
将事件记录到事件查看器。
明智地使用信息、调试、警告和错误。
开发时在生产中显示所有内容(使用服务器端的控制台 - 见下文),仅记录错误(可配置)
我在每个类的请求中创建一个记录器,为其提供 typeof(myClass) 但这是可选的...
我'我在 DEV 中将 WCF 作为控制台应用程序托管 - 因此在控制台中查看服务器日志也很容易,但是一旦它成为服务,您就必须使用事件查看器......
啊 - 如果您比较的话,它非常快它到 WCF“调用时间”(从客户端调用到服务器),因此它并不会真正影响您的时间,除非您有类似疯狂的日志(例如 nHibernate))
Log events to event viewer.
Use wisely INFO DEBUG WARNING and ERROR.
when developing show everything (use the console on the server side- see below) on production , log only errors (configurable)
I create a logger in the begging of each class giving it the typeof(myClass) but that's optional...
I'm hosting the WCF in DEV as a console app - so watching the server log is easy also in the console, but once it becomes a service, you have to use event viewer....
ah - and it is very fast if you compare it to WCF "calling times" (calling from client to server) so it doesn't really effect your times, unless you has something the logs like crazy (nHibernate for example) )
对于 WCF 来说,可能有更好的方法来做到这一点;对于 WinForms,您可以考虑查看 PostSharp。这将允许您记录方法调用,而不会使您的代码混乱。在幕后您仍然可以使用优秀的 log4net。
警告:我自己没有使用过它;我在代码训练营中看到过一个令人印象深刻的演示。
There's probably a better way to do this for WCF; for WinForms, you might consider looking at PostSharp. This would allow you to log method calls without cluttering your code. Behind the scenes you'd still be using the excellent log4net.
Caveat: I haven't used it myself; I've seen a very impressive presentation on it at a code camp.