繁体   English   中英

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

[英]What are the best practices for including logging using log4net?

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

因此,无论如何都要有一套指导,以便获得合理的成本/收益权衡

因此:

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

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

-

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

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

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

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


正确的解决方案是:

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

我发现这篇文章非常有用: http//blog.codinghorror.com/the-problem-with-logging/

特别是我认为极简主义的方法确实是要走的路。 在过去,我试图记录太多,但这会使代码膨胀

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

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

他们关于您的问题的基本观点是,日志记录应该针对运营级别所需的内容。 运营人员最关心的是网站可能出现故障的特殊情况(即连接池已满,与服务器的连接已关闭等)确保消息不言自明,并且非常清楚问题是什么,如果适用,修复是什么。 写下供人食用的信息。

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

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

  1. 功能输入/退出
  2. 函数内部的主要逻辑步骤
  3. 详细记录所有中间计算

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

第二个通常在验收/集成和回归测试期间完成,因为主要逻辑流程和问题区域被识别。 在此阶段添加日志记录也相当少,因为您通常知道在调试和测试时需要添加日志记录。

第三个通常(对我来说无论如何)只在经历回归的代码部分中完成,或者特别重要。

我已经为log4net实现了一个基本的包装器对象,它为我提供了直接的日志记录功能以及一个上下文对象,可以与IDisposable一起使用,将“进入/退出”逻辑包装在一个漂亮的易用包中。

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

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

在代码中使用这些,例如

_log.Info("Updating object.");

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

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

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

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

由于侦听器的类别连接是在配置中完成的,因此您可以在部署后更改日志记录。 如果没有人正在收听,那么记录几乎没有性能损失。


关于伐木的成本与效益,在太多的伐木(没有人会使用的大型原木)和不够的(一条线说“失败”)之间肯定会有一个最佳点。

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

不常见的情况(例如)默认值通常不会转到WARN,异常转到ERROR或FATAL。

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

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

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

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

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

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

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

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

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

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

如果您遵循这种方法并且愿意采用(相当小的)性能命中,这里有一种使用堆栈跟踪为任何类创建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;
    }
}

记录并不是一件容易的事,但我的经验是所有日志都应该可以为负责任的各方搜索。 错误的有用目标是直接发送电子邮件(在某些情况下是短信)。 但最终所有日志记录数据都应该可以在具有可选用户界面的数据库中进行搜索。

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

  • 严重错误:应立即使用电子邮件/短信
  • 未来问题:每日/每周电子邮件
  • 调试信息==>每日/每周电子邮件,其中包含自上次以来产生的调试信息量的通知。

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

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

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

快乐的调试!

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

明智地使用INFO DEBUG WARNING和ERROR。

开发时显示生产中的所有内容(在服务器端使用控制台 - 见下文),仅记录错误(可配置)

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

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

啊 - 如果你将它与WCF“调用时间”(从客户端调用到服务器)的速度非常快,那么它不会真正影响你的时间,除非你有像疯了一样的日志(例如nHibernate))

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM