我想了解人们如何在实际应用程序中处理跟踪和登录。这里有一些问题可能有助于解释你的答案。
框架
你使用什么框架?
log4net
System.Diagnostics.Trace
System.Diagnostics.TraceSource
日志应用程序块
其他的吗?
如果你使用跟踪,你使用Trace.Correlation.StartLogicalOperation吗?
您是手动编写这些代码,还是使用某种形式的面向方面编程来完成这些代码?愿意分享一段代码片段吗?
您是否提供了任何形式的跟踪源粒度?例如,WPF TraceSources允许你在不同的级别上配置它们:
系统。Windows -所有WPF的设置
System.Windows.Animation -重写动画。
听众
您使用什么日志输出?
文本文件
XML文件
事件日志
其他的吗?
如果使用文件,您是使用滚动日志还是单个文件?如何让人们可以使用这些日志?
查看
您使用什么工具查看日志?
记事本
尾巴
事件查看器
系统中心运营经理/微软运营经理
WCF服务跟踪查看器
其他的吗?
如果您正在构建ASP。NET解决方案,你也用ASP。NET运行状况监视?运行状况监控器事件中是否包含跟踪输出?Trace.axd呢?
那么自定义性能计数器呢?
我不得不加入推荐log4net的行列,在我的案例中,从平台灵活性(desktop . net / compact Framework, 32/64位)的角度来看。
但是,将其包装在私有标签API中是一种主要的反模式。log4net。ILogger已经是Commons Logging包装器API的. net对等体,因此耦合已经被最小化,而且由于它也是一个Apache库,通常甚至不需要担心,因为您没有放弃任何控制:如果必须,可以使用它。
我所见过的大多数家用包装器库也会犯一个或多个错误:
Using a global singleton logger (or equivalently a static entry point) which loses the fine resolution of the recommended logger-per-class pattern for no other selectivity gain.
Failing to expose the optional Exception argument, leading to multiple problems:
It makes an exception logging policy even more difficult to maintain, so nothing is done consistently with exceptions.
Even with a consistent policy, formatting the exception away into a string loses data prematurely. I've written a custom ILayout decorator that performs detailed drill-down on an exception to determine the chain of events.
Failing to expose the IsLevelEnabled properties, which discards the ability to skip formatting code when areas or levels of logging are turned off.
我们在工作中使用Log4Net作为日志记录提供者,并为日志实例使用单例包装器(尽管单例正在审查中,质疑它们是否是一个好主意)。
我们选择它的原因如下:
在各种环境上进行简单的配置/重新配置
良好的预建附件数量
我们用的一个CMS已经内置了
大量的日志级别和相关配置
我应该提一下,这是从ASP讲的。NET开发的观点
我可以看到使用. net框架中的Trace的一些优点,但我并不完全相信它,主要是因为我使用的组件并没有真正执行任何Trace调用。据我所知,我唯一经常使用的是System.Net.Mail。
所以我们有一个包装log4net的库,在我们的代码中,我们只需要这样的东西:
Logger.Instance.Warn("Something to warn about");
Logger.Instance.Fatal("Something went bad!", new Exception());
try {
var i = int.Parse("Hello World");
} catch(FormatException, ex) {
Logger.Instance.Error(ex);
}
在方法中,我们检查日志记录级别是否启用,这样就不会对log4net API进行冗余调用(因此,如果Debug未启用,调试语句将被忽略),但当我有时间时,我将更新它以公开这些语句,以便您可以自己进行检查。这将防止在不应该进行的情况下进行评估,例如:
Logger.Instance.Debug(string.Format("Something to debug at {0}", DateTime.Now);
这将变成:
if(Logger.DebugEnabled) Logger.Instance.Debug(string.Format("Something to debug at {0}", DateTime.Now);
(节省了一点浪费时间)
默认情况下,我们在两个位置进行日志记录:
网站的文件系统(未提供的文件扩展名)
电子邮件发送错误和致命
文件以每天卷或10mb (IIRC)的方式完成。我们不使用EventLog,因为它需要比我们通常想要的站点更高的安全性。
我发现记事本可以很好地读取日志。
我不经常在asp.net中开发,但是当涉及到记录器时,我认为许多最佳实践是通用的。以下是我多年来对日志的一些随机想法:
框架
Use a logger abstraction framework - like slf4j (or roll your own), so that you decouple the logger implementation from your API. I have seen a number of logger frameworks come and go and you are better off being able to adopt a new one without much hassle.
Try to find a framework that supports a variety of output formats.
Try to find a framework that supports plugins / custom filters.
Use a framework that can be configured by external files, so that your customers / consumers can tweak the log output easily so that it can be read by commerical log management applications with ease.
Be sure not to go overboard on custom logging levels, otherwise you may not be able to move to different logging frameworks.
日志输出
Try to avoid XML/RSS style logs for logging that could encounter catastrophic failures. This is important because if the power switch is shut off without your logger writing the closing </xxx> tag, your log is broken.
Log threads. Otherwise, it can be very difficult to track the flow of your program.
If you have to internationalize your logs, you may want to have a developer only log in English (or your language of choice).
Sometimes having the option to insert logging statements into SQL queries can be a lifesaver in debugging situations. Such as:
-- Invoking Class: com.foocorp.foopackage.FooClass:9021
SELECT * FROM foo;
You want class-level logging. You normally don't want static instances of loggers as well - it is not worth the micro-optimization.
Marking and categorizing logged exceptions is sometimes useful because not all exceptions are created equal. So knowing a subset of important exceptions a head of time is helpful, if you have a log monitor that needs to send notifications upon critical states.
Duplication filters will save your eyesight and hard disk. Do you really want to see the same logging statement repeated 10^10000000 times? Wouldn't it be better just to get a message like:
This is my logging statement - Repeated 100 times
也看看我的这个问题。
我没有资格评论。net的日志,因为我的面包和butter是Java,但是在过去的8年里,我们在日志方面有了一个迁移,你可能会发现一个有用的类比来回答你的问题。
我们从JVM中的每个线程都使用的Singleton记录器开始,并为整个进程设置日志记录级别。如果我们不得不调试系统的一个非常特定的部分,就会产生大量的日志,所以第一个教训是对日志进行分段。
当前的日志记录器允许多个实例,其中一个被定义为默认实例。我们可以实例化任意数量的具有不同日志级别的子日志记录器,但是这种体系结构最有用的方面是能够通过简单地更改日志属性为单个包和类创建日志记录器。第二课是创建一个灵活的系统,允许在不更改代码的情况下重写其行为。
我们使用的是包裹在Log4J周围的Apache公共日志库。
希望这能有所帮助!
*编辑*
After reading Jeffrey Hantin's post below, I realized that I should have noted what our internal logging wrapper has actually become. It's now essentially a factory and is strictly used to get a working logger using the correct properties file (which for legacy reasons hasn't been moved to the default position). Since you can specify the logging configuration file on command line now, I suspect it will become even leaner and if you're starting a new application, I'd definitely agree with his statement that you shouldn't even bother wrapping the logger.
我不得不加入推荐log4net的行列,在我的案例中,从平台灵活性(desktop . net / compact Framework, 32/64位)的角度来看。
但是,将其包装在私有标签API中是一种主要的反模式。log4net。ILogger已经是Commons Logging包装器API的. net对等体,因此耦合已经被最小化,而且由于它也是一个Apache库,通常甚至不需要担心,因为您没有放弃任何控制:如果必须,可以使用它。
我所见过的大多数家用包装器库也会犯一个或多个错误:
Using a global singleton logger (or equivalently a static entry point) which loses the fine resolution of the recommended logger-per-class pattern for no other selectivity gain.
Failing to expose the optional Exception argument, leading to multiple problems:
It makes an exception logging policy even more difficult to maintain, so nothing is done consistently with exceptions.
Even with a consistent policy, formatting the exception away into a string loses data prematurely. I've written a custom ILayout decorator that performs detailed drill-down on an exception to determine the chain of events.
Failing to expose the IsLevelEnabled properties, which discards the ability to skip formatting code when areas or levels of logging are turned off.