使用log4net包含日志记录的最佳做法是什么?

时间:2023-02-10 20:04:19

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.

我被告知使用log4net将“日志记录”添加到我的代码中,问题是没有人可以及时访问并查看需要使用日志记录解决的实际问题。

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)

(代码使用了很多WCF,一边是Winforms,另一边是通常在同一台机器上运行的“服务器”)

--

-

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.

我已经将AJM的答案排除在做有用的博客文章之前,并指出了很多评论,但如果有人提出了一套很好的“经验法则”,我很可能会改变预期的答案。

9 个解决方案

#1


5  

I found this article very helpful: http://blog.codinghorror.com/the-problem-with-logging/

我发现这篇文章非常有用: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

还认为越多的日志条目越好是错误的,因为它会使日志本身膨胀。我现在将loggings的主要好处看作是提供“立足点”或概述正在发生的事情。如果特定区域需要更多细节,那么它是默认位置应该更少更好

#2


7  

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:

要记住的一件事是,虽然您的配置将处理不同级别的日志记录,但您可能会在日志调用中造成沉重的开销。例如:

// some kind of loop
// do some operations
Logger.LogDebug(myObject.GetXmlRepresentation());
// end loop

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.

如果您有一个记录器监听DEBUG日志,这显然只会记录该对象,但是无论您的日志记录级别如何,构建XML对象的调用都会运行,并且可能导致一些相当大的速度减慢。


The correct solution would be:

正确的解决方案是:

// some kind of loop
// do some operations
if (Logger.IsDebug)
{
    Logger.LogDebug(myObject.GetXmlRepresentation());
}
// end loop

#3


5  

My favorite source of information for this kind of question is Release It - a book from the Pragmatic guys. Highly highly recommended.

我最喜欢这类问题的信息来源是Release It--一本来自Pragmatic人的书。强烈推荐。

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.

我在函数入口/出口样式日志中看到了一点点。*捕获异常的堆栈跟踪很有用,可以记录可能发生系统崩溃的区域(即完整连接池),以及记录系统之前崩溃的区域。

#4


2  

In general with logging I add logging in the following order:

通常,对于日志记录,我按以下顺序添加日志记录:

  1. Function Enter/Exit
  2. 功能进入/退出
  3. Major logic steps inside of a function
  4. 函数内部的主要逻辑步骤
  5. Verbose logging for all intermediate calculations
  6. 所有中间计算的详细日志记录

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.

显然我很少到达最后一个,如果你为log4net滚动你自己的包装并使用处理模式,可能还有一些反射魔法,那么第一个很容易做到。

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实现了一个基本的包装器对象,它为我提供了直接的日志记录功能以及一个上下文对象,它可以与IDisposable一起使用,将“进入/退出”逻辑包装在一个漂亮的方便包中。

#5


1  

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

log4net的一大优点是您可以将事件记录到不同的类别。默认值为Debug,Info,Warning和Error。我喜欢这些意思

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.

调试 - 非常详细,包含大量调试信息。例如,SQL查询。信息 - 有用的信息很有用。警告 - 没什么致命的,但操作员应该意识到这个问题。错误 - 应用程序现在不稳定,日志包含诊断信息,例如异常消息和堆栈跟踪。

Use these in code, so e.g.

在代码中使用这些,例如

_log.Info("Updating object.");

_log.Info(“正在更新对象。”);

would write an INFO level message to any listener that was interested.

会向任何感兴趣的听众写一个INFO级别的消息。

Then you can hook up listeners in configuration to do things with the log messages. Here's one that I'm using:

然后,您可以在配置中挂接侦听器以使用日志消息执行操作。这是我正在使用的一个:

<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date [%thread] %-5level %logger [%ndc] - %message%newline" />
  </layout>
</appender>
<appender name="FileAppender" type="log4net.Appender.FileAppender">
  <file value="c:\temp\servicelog.txt" />
  <appendToFile value="true" />
  <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date [%thread] %-5level %logger [%ndc] - %message%newline%exception" />
  </layout>
</appender>
<root>
  <level value="ERROR" />
  <appender-ref ref="ConsoleAppender" />
</root>
<logger name="Warehouse.Core">
  <level value="INFO" />
  <appender-ref ref="FileAppender" />
</logger>
</log4net>

This says: all ERROR messages to the console, all INFO messages from the logger Warehouse.Core to the given file.

这表示:所有ERROR消息都发送到控制台,所有INFO消息都从记录器Warehouse.Core发送到给定文件。

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

我的策略是记录INFO可能失败的东西:外部依赖(应用程序启动,服务调用,SQL连接),以及DEBUG更复杂的内容代码(业务逻辑中的诊断消息,单个SQL调用,一些方法调用)。

Unusual situations where (for example) defaults are taken that aren't usually would go to WARN, and exceptions go to ERROR or FATAL.

不常见的情况是(例如)默认值通常不会转到WARN,异常会转到ERROR或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.

另外:请记住,WCF有一个最优秀的服务跟踪查看器,允许您“深入”到单个数据包以及它们如何由堆栈的两端处理。在没有代码更改的情况下,配置也可以使用它。因此,我通常只会对WCF服务调用和响应进行非常简短的记录。

#6


1  

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:

当收到特定帐户的电子邮件时,可以将其处理并直接放入数据库。下面有som类别和处理规则:

  • Critical errors: should be availbale immediatly email/sms
  • 严重错误:应立即使用电子邮件/短信
  • Future issues: daily/weekly email
  • 未来问题:每日/每周电子邮件
  • Debug info ==> daily/weekly email with a notification on how much debug info is produces since last time.
  • 调试信息==>每日/每周电子邮件,其中包含自上次以来产生的调试信息量的通知。

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.

调试的内容可以以不同的方式写入数据库,但我们需要更好的性能。在“生产模式”下不应将大量数据写入数据库。这应该在每日/每周的基础上进行。最好的方法是生成本地文件(例如XML或纯文本),并在维护时间(晚上)将此文件放入数据库。应该可以启动/停止调试会话,并且仅在调试会话完成时将调试信息写入数据库。

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.

调试组件可以实现为WCF和log2net,并且可以直接访问数据库和/或定期放入数据库的本地文件存储。

One thing is clear...ALL errors/exception should be logged somewhere. Nothing is more irritating than lost error messages :)

有一件事是清楚的......所有错误/异常都应记录在某处。没有什么比失去的错误消息更令人恼火:)

Happy debugging!

快乐的调试!

#7


1  

What kinds of logging should one add to an application that would be useful later?

应该在以后有用的应用程序中添加哪种日志记录?

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.

如果从自己的异常类中抛出异常,甚至更好,所有异常类都派生自基类,在(基本)异常构造函数中添加ERROR级别日志记录;节省你必须记住每次捕获/抛出。如果你有一个很大的代码库,这很有用。

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)

对于CLR或第三方异常,请记录Exception.ToString(),而不仅仅是消息,否则您将错过完整的堆栈跟踪(假设程序员不会吞下异常或重新抛出sans内部异常)

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

在您知道或怀疑您将遇到问题的区域专注于DEBUG详细信息(只需询问QA或技术支持在哪里查看;-)

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.

如果遵循稳健性原则,那么当您忽略或更改输入或预期行为时,您可能需要INFO或WARN日志记录。如果您的WCF服务开始接收意外(但可解析)输入,这可能很有用。

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.

为了确保您的应用程序运行良好,请不要在默认情况下启用DEBUG级别日志记录的情况下发送/安装它,ERROR或WARN可能是最佳选择。

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:

我不同意接受的答案的最后部分,因为log4net具有很棒的过滤功能;条件是您的程序员理解日志记录是有代价的(根据CK的答案),他们(以及QA和技术支持)知道过滤器,并且在DEBUG配置所有内容是一个坏主意。如果您在DEBUG级别记录一个大对象图,xml文档,db结果等等,请将其包装在一些代码中以减少开销:

if (log.IsDebugEnabled)
{
    log.DebugFormat("Loaded in {0} ms {1}", timer.ElapsedMilliseconds, dataSet.GetXml());
}

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.

我建议你遵循推荐的静态logger-per-class方法,因为它必须使日志更有用,当你必须实际使用它并使用过滤器缩小问题时,例如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:

如果您遵循这种方法并且愿意采用(相当小的)性能命中,这里有一种使用堆栈跟踪为任何类创建ILog对象并确保配置文件连接以监视更改的方法:

public static class LogFactory
{
    /// <summary>
    /// Create log whose name is the calling methods class name.
    /// </summary>
    /// <remarks>
    /// <para>
    /// Configures the log repository if it hasn't been configured before.
    /// </para>
    /// <para>
    /// Creates a debug log message right after getting the logger, this follows
    /// the log4net recommendation to log first message as early as possible.
    /// </para>
    /// </remarks>
    /// <returns>Log ready for work.</returns>
    public static log4net.ILog Create()
    {
        var method = new StackTrace().GetFrame(1).GetMethod();
        var log = log4net.LogManager.GetLogger(method.DeclaringType);

        if (log4net.LogManager.GetRepository().Configured == false)
        {
            try
            {
                new FileIOPermission(FileIOPermissionAccess.Read,
                    AppDomain.CurrentDomain.SetupInformation.ConfigurationFile)
                    .Demand();

                var configFile = new FileInfo(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
                log4net.Config.XmlConfigurator.ConfigureAndWatch(configFile);
                log.DebugFormat("Log4net configured and watching {0}", configFile.FullName);
            }
            catch (System.Security.SecurityException e)
            {
                log.DebugFormat("Unable to watch config file due to security permissions. {0}", e.ToString());
            }
        }

        log.DebugFormat("Logging {0}", log.Logger.Name);

        return log;
    }
}

#8


0  

Log events to event viewer.

将事件记录到事件查看器。

Use wisely INFO DEBUG WARNING and ERROR.

明智地使用INFO DEBUG WARNING和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...

我在每个类的乞讨中创建一个记录器,给它typeof(myClass),但这是可选的......

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....

我在DEV中作为控制台应用程序托管WCF - 所以在控制台中也很容易看到服务器日志,但是一旦它成为服务,你必须使用事件查看器....

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“调用时间”(从客户端调用到服务器)的速度非常快,那么它不会真正影响你的时间,除非你有像疯了一样的日志(例如nHibernate))

#9


0  

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.

对于WCF,可能有更好的方法来做这件事;对于WinForms,您可以考虑查看PostSharp。这将允许您记录方法调用而不会使代码混乱。在幕后你仍然会使用优秀的log4net。

Caveat: I haven't used it myself; I've seen a very impressive presentation on it at a code camp.

警告:我自己没有用过;我在代码营看到了一个非常令人印象深刻的演示文稿。

#1


5  

I found this article very helpful: http://blog.codinghorror.com/the-problem-with-logging/

我发现这篇文章非常有用: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

还认为越多的日志条目越好是错误的,因为它会使日志本身膨胀。我现在将loggings的主要好处看作是提供“立足点”或概述正在发生的事情。如果特定区域需要更多细节,那么它是默认位置应该更少更好

#2


7  

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:

要记住的一件事是,虽然您的配置将处理不同级别的日志记录,但您可能会在日志调用中造成沉重的开销。例如:

// some kind of loop
// do some operations
Logger.LogDebug(myObject.GetXmlRepresentation());
// end loop

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.

如果您有一个记录器监听DEBUG日志,这显然只会记录该对象,但是无论您的日志记录级别如何,构建XML对象的调用都会运行,并且可能导致一些相当大的速度减慢。


The correct solution would be:

正确的解决方案是:

// some kind of loop
// do some operations
if (Logger.IsDebug)
{
    Logger.LogDebug(myObject.GetXmlRepresentation());
}
// end loop

#3


5  

My favorite source of information for this kind of question is Release It - a book from the Pragmatic guys. Highly highly recommended.

我最喜欢这类问题的信息来源是Release It--一本来自Pragmatic人的书。强烈推荐。

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.

我在函数入口/出口样式日志中看到了一点点。*捕获异常的堆栈跟踪很有用,可以记录可能发生系统崩溃的区域(即完整连接池),以及记录系统之前崩溃的区域。

#4


2  

In general with logging I add logging in the following order:

通常,对于日志记录,我按以下顺序添加日志记录:

  1. Function Enter/Exit
  2. 功能进入/退出
  3. Major logic steps inside of a function
  4. 函数内部的主要逻辑步骤
  5. Verbose logging for all intermediate calculations
  6. 所有中间计算的详细日志记录

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.

显然我很少到达最后一个,如果你为log4net滚动你自己的包装并使用处理模式,可能还有一些反射魔法,那么第一个很容易做到。

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实现了一个基本的包装器对象,它为我提供了直接的日志记录功能以及一个上下文对象,它可以与IDisposable一起使用,将“进入/退出”逻辑包装在一个漂亮的方便包中。

#5


1  

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

log4net的一大优点是您可以将事件记录到不同的类别。默认值为Debug,Info,Warning和Error。我喜欢这些意思

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.

调试 - 非常详细,包含大量调试信息。例如,SQL查询。信息 - 有用的信息很有用。警告 - 没什么致命的,但操作员应该意识到这个问题。错误 - 应用程序现在不稳定,日志包含诊断信息,例如异常消息和堆栈跟踪。

Use these in code, so e.g.

在代码中使用这些,例如

_log.Info("Updating object.");

_log.Info(“正在更新对象。”);

would write an INFO level message to any listener that was interested.

会向任何感兴趣的听众写一个INFO级别的消息。

Then you can hook up listeners in configuration to do things with the log messages. Here's one that I'm using:

然后,您可以在配置中挂接侦听器以使用日志消息执行操作。这是我正在使用的一个:

<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date [%thread] %-5level %logger [%ndc] - %message%newline" />
  </layout>
</appender>
<appender name="FileAppender" type="log4net.Appender.FileAppender">
  <file value="c:\temp\servicelog.txt" />
  <appendToFile value="true" />
  <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date [%thread] %-5level %logger [%ndc] - %message%newline%exception" />
  </layout>
</appender>
<root>
  <level value="ERROR" />
  <appender-ref ref="ConsoleAppender" />
</root>
<logger name="Warehouse.Core">
  <level value="INFO" />
  <appender-ref ref="FileAppender" />
</logger>
</log4net>

This says: all ERROR messages to the console, all INFO messages from the logger Warehouse.Core to the given file.

这表示:所有ERROR消息都发送到控制台,所有INFO消息都从记录器Warehouse.Core发送到给定文件。

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

我的策略是记录INFO可能失败的东西:外部依赖(应用程序启动,服务调用,SQL连接),以及DEBUG更复杂的内容代码(业务逻辑中的诊断消息,单个SQL调用,一些方法调用)。

Unusual situations where (for example) defaults are taken that aren't usually would go to WARN, and exceptions go to ERROR or FATAL.

不常见的情况是(例如)默认值通常不会转到WARN,异常会转到ERROR或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.

另外:请记住,WCF有一个最优秀的服务跟踪查看器,允许您“深入”到单个数据包以及它们如何由堆栈的两端处理。在没有代码更改的情况下,配置也可以使用它。因此,我通常只会对WCF服务调用和响应进行非常简短的记录。

#6


1  

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:

当收到特定帐户的电子邮件时,可以将其处理并直接放入数据库。下面有som类别和处理规则:

  • Critical errors: should be availbale immediatly email/sms
  • 严重错误:应立即使用电子邮件/短信
  • Future issues: daily/weekly email
  • 未来问题:每日/每周电子邮件
  • Debug info ==> daily/weekly email with a notification on how much debug info is produces since last time.
  • 调试信息==>每日/每周电子邮件,其中包含自上次以来产生的调试信息量的通知。

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.

调试的内容可以以不同的方式写入数据库,但我们需要更好的性能。在“生产模式”下不应将大量数据写入数据库。这应该在每日/每周的基础上进行。最好的方法是生成本地文件(例如XML或纯文本),并在维护时间(晚上)将此文件放入数据库。应该可以启动/停止调试会话,并且仅在调试会话完成时将调试信息写入数据库。

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.

调试组件可以实现为WCF和log2net,并且可以直接访问数据库和/或定期放入数据库的本地文件存储。

One thing is clear...ALL errors/exception should be logged somewhere. Nothing is more irritating than lost error messages :)

有一件事是清楚的......所有错误/异常都应记录在某处。没有什么比失去的错误消息更令人恼火:)

Happy debugging!

快乐的调试!

#7


1  

What kinds of logging should one add to an application that would be useful later?

应该在以后有用的应用程序中添加哪种日志记录?

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.

如果从自己的异常类中抛出异常,甚至更好,所有异常类都派生自基类,在(基本)异常构造函数中添加ERROR级别日志记录;节省你必须记住每次捕获/抛出。如果你有一个很大的代码库,这很有用。

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)

对于CLR或第三方异常,请记录Exception.ToString(),而不仅仅是消息,否则您将错过完整的堆栈跟踪(假设程序员不会吞下异常或重新抛出sans内部异常)

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

在您知道或怀疑您将遇到问题的区域专注于DEBUG详细信息(只需询问QA或技术支持在哪里查看;-)

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.

如果遵循稳健性原则,那么当您忽略或更改输入或预期行为时,您可能需要INFO或WARN日志记录。如果您的WCF服务开始接收意外(但可解析)输入,这可能很有用。

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.

为了确保您的应用程序运行良好,请不要在默认情况下启用DEBUG级别日志记录的情况下发送/安装它,ERROR或WARN可能是最佳选择。

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:

我不同意接受的答案的最后部分,因为log4net具有很棒的过滤功能;条件是您的程序员理解日志记录是有代价的(根据CK的答案),他们(以及QA和技术支持)知道过滤器,并且在DEBUG配置所有内容是一个坏主意。如果您在DEBUG级别记录一个大对象图,xml文档,db结果等等,请将其包装在一些代码中以减少开销:

if (log.IsDebugEnabled)
{
    log.DebugFormat("Loaded in {0} ms {1}", timer.ElapsedMilliseconds, dataSet.GetXml());
}

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.

我建议你遵循推荐的静态logger-per-class方法,因为它必须使日志更有用,当你必须实际使用它并使用过滤器缩小问题时,例如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:

如果您遵循这种方法并且愿意采用(相当小的)性能命中,这里有一种使用堆栈跟踪为任何类创建ILog对象并确保配置文件连接以监视更改的方法:

public static class LogFactory
{
    /// <summary>
    /// Create log whose name is the calling methods class name.
    /// </summary>
    /// <remarks>
    /// <para>
    /// Configures the log repository if it hasn't been configured before.
    /// </para>
    /// <para>
    /// Creates a debug log message right after getting the logger, this follows
    /// the log4net recommendation to log first message as early as possible.
    /// </para>
    /// </remarks>
    /// <returns>Log ready for work.</returns>
    public static log4net.ILog Create()
    {
        var method = new StackTrace().GetFrame(1).GetMethod();
        var log = log4net.LogManager.GetLogger(method.DeclaringType);

        if (log4net.LogManager.GetRepository().Configured == false)
        {
            try
            {
                new FileIOPermission(FileIOPermissionAccess.Read,
                    AppDomain.CurrentDomain.SetupInformation.ConfigurationFile)
                    .Demand();

                var configFile = new FileInfo(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
                log4net.Config.XmlConfigurator.ConfigureAndWatch(configFile);
                log.DebugFormat("Log4net configured and watching {0}", configFile.FullName);
            }
            catch (System.Security.SecurityException e)
            {
                log.DebugFormat("Unable to watch config file due to security permissions. {0}", e.ToString());
            }
        }

        log.DebugFormat("Logging {0}", log.Logger.Name);

        return log;
    }
}

#8


0  

Log events to event viewer.

将事件记录到事件查看器。

Use wisely INFO DEBUG WARNING and ERROR.

明智地使用INFO DEBUG WARNING和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...

我在每个类的乞讨中创建一个记录器,给它typeof(myClass),但这是可选的......

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....

我在DEV中作为控制台应用程序托管WCF - 所以在控制台中也很容易看到服务器日志,但是一旦它成为服务,你必须使用事件查看器....

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“调用时间”(从客户端调用到服务器)的速度非常快,那么它不会真正影响你的时间,除非你有像疯了一样的日志(例如nHibernate))

#9


0  

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.

对于WCF,可能有更好的方法来做这件事;对于WinForms,您可以考虑查看PostSharp。这将允许您记录方法调用而不会使代码混乱。在幕后你仍然会使用优秀的log4net。

Caveat: I haven't used it myself; I've seen a very impressive presentation on it at a code camp.

警告:我自己没有用过;我在代码营看到了一个非常令人印象深刻的演示文稿。