首页 文章

编写事件日志条目的最佳方法是什么?

提问于
浏览
14

我最近在部署Windows服务时遇到了问题 . 四台计算机没有造成任何问题,但在第五台计算机上由于异常而导致启动服务失败 . 异常堆栈跟踪被写入事件日志,因此我应该很容易确定原因:

protected override void OnStart(string[] args)
{
    EventLog.WriteEntry("Starting service", EventLogEntryType.Information);

    try
    {
        //...
        base.OnStart(args);
    }
    catch (Exception ex)
    {
        EventLog.WriteEntry("Service can not start. Stack trace:" + ex.StackTrace, EventLogEntryType.Error);
        Stop();
        return;
    }

    EventLog.WriteEntry("Service started", EventLogEntryType.Information);           
}

但是,唉,没有任何信息写入日志 . 我终于将它追溯到第一个正在写入的日志条目 . 它引发了一个异常,因为应用程序事件日志已满,包含最近的条目,并且配置为仅覆盖超过7天的条目 .

考虑到我无法更改应用程序事件日志的配置,写入事件日志的最佳做法是什么?

我应该总是将 EventLog.WriteEntry 放在try块中,如果是的话,我应该如何处理异常(将其写入事件日志可能是一个坏主意),我应该检查 OnStart 方法中的事件日志状态,还是你有还有更好的建议吗?

6 回答

  • 11

    我认为记录异常是您最好不要吞下异常的罕见情况之一 . 在大多数情况下,您不希望您的应用在此失败 .

    但是你为什么要自己编写日志代码呢?使用像NLog或Log4Net这样的框架!这些也像我刚刚说的那样吞下异常,但你可以通过配置更改将日志记录输出重定向到不同的位置(文件,消息框等) . 这使得解决这类问题变得更加容易 .

  • 4

    使用log4net

    使用log4net的优点是,您可以检查日志记录并对其进行控制,其灵活性远远超出您在代码中的考虑范围 .

    如果您正在登录事件日志,并且看到问题而没有事件日志条目,您可以随时切换到文件追加器日志并看到它正常工作......然后会告诉您这是与之相关的事情事件日志 .

    log4net也是防御性的,如果它无法写入日志条目,它不会崩溃你的程序 . 所以你不会看到这种情况发生(所以你不会有你的日志文件,但你的程序会运行,你可以再次指定第二个日志记录方法来获取日志文件) .

    log4net文档中的关键位是:

    [log4net]是尽力而为的故障停止日志记录系统 . 通过失败停止,我们的意思是log4net不会在运行时抛出意外异常,从而可能导致应用程序崩溃 . 如果由于任何原因,log4net抛出一个未捕获的异常(可能抛出的ArgumentException和ArgumentNullException除外),请发送电子邮件至log4net-user@logging.apache.org邮件列表 . 未捕获的异常被视为需要立即关注的严重错误 . 此外,当log4net的指定输出流未打开,不可写或变满时,log4net将不会还原为System.Console.Out或System.Console.Error . 这样可以避免因为日志记录失败而淹没用户终端而损坏其他工作程序 . 但是,log4net将向System.Console.Error和System.Diagnostics.Trace输出单个消息,指示无法执行日志记录 .

    (我的重点)

    对于大多数事情,有一个图书馆比你做得更好 . 最好的事情是永远不要重新发明,log4net解决了登录.Net的问题,让你的生活更轻松 .

  • 3
    System.Diagnostics.EventLog log = 
        new System.Diagnostics.EventLog("YourLogNameHere");
    log.ModifyOverflowPolicy(
        System.Diagnostics.OverflowAction.OverwriteAsNeeded, 0);
    

    这应该可以解决您的溢出问题 . 一旦正确配置,事件日志通常非常可靠 . 使用事件日志时,我曾经添加了一个简单写入文本文件的快速紧急备份 Logger (这需要大约5分钟才能写入) . 它永远不会被召唤 .

  • 2

    你不能只使用ServiceBase类已经提供的默认事件日志机制吗?如果您的服务未启动,则会自动在事件日志中写入条目(使用stacktrace) .

    除此之外,关于log4net(或任何其他最好的努力,如日志系统)的评论,我认为这实际上取决于你想要实现的目标 .

    在您的示例中使用log4net(或ServiceBase的事件日志的内置支持)很可能是正常的 .

    但是,在某些情况下,即使出现错误并且无法在某处记录该事实也是一个问题 . 例如,假设一个身份验证或授权系统 . 如果您无法成功且可靠地记录密码认证因密码错误而失败,则可能不允许继续(如果您的密码认证成功,则BTW也是如此) .

    因此,有时您需要知道日志记录尝试何时失败并自行处理 . 这当然是有限的(鸡蛋问题),你做的是特定的应用程序或场景 .

  • 2

    考虑使用Logging App Block .

    企业库日志记录应用程序块简化了常见日志记录功能的实现 . 开发人员可以使用Logging Block进行编写信息到各种位置:事件日志电子邮件消息数据库消息队列文本文件WMI事件使用应用程序块扩展点的自定义位置

  • 0

    我们在这里退后一步:

    系统事件日志用于警告系统管理员系统上出现问题 . 您应该允许服务启动失败 . 这将显示在系统错误日志中,并显示“Service Control Manager”的报告源 . 这意味着sys管理员将知道失败 .

    接下来,如果您需要进行故障排除,则应将异常记录到程序顶层磁盘上的文件中 . 您还应该重新抛出它们,以便服务启动失败 .

    然后,您可以识别系统事件日志中的任何问题,并将失败的时间交叉引用到应用程序日志中 .

相关问题