【问题标题】:What is the best way to write event log entries?编写事件日志条目的最佳方法是什么?
【发布时间】:2010-09-23 18:03:07
【问题描述】:

我最近在部署 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 块中,如果是,我应该如何处理异常(将其写入事件日志可能是个坏主意),我是否应该检查@987654323 中的事件日志状态@方法,或者你有什么更好的建议?

【问题讨论】:

    标签: .net event-log


    【解决方案1】:

    使用 log4net

    使用 log4net 的优势在于,您可以检查日志记录并对其进行控制,其灵活性比您在代码中考虑的要大得多。

    如果您正在记录到事件日志,并且看到问题并且没有事件日志条目,那么您总是可以切换到文件附加器日志并看到它正在工作......然后会告诉您它是什么与事件日志有关。

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

    log4net 文档中的关键位是这样的:

    [log4net] 是一个尽力而为和故障停止的日志记录系统。

    通过故障停止,我们的意思是 log4net 不会在运行时抛出可能导致您的应用程序崩溃的意外异常。如果由于任何原因,log4net 抛出未捕获的异常(可能抛出的 ArgumentException 和 ArgumentNullException 除外),请发送电子邮件至 log4net-user@logging.apache.org 邮件列表。未捕获的异常被视为需要立即关注的严重错误。

    此外,当指定的输出流未打开、不可写或已满时,log4net 不会恢复为 System.Console.Out 或 System.Console.Error。这避免了由于日志记录失败而导致用户终端泛滥而破坏其他工作程序。但是,log4net 会向 System.Console.Error 和 System.Diagnostics.Trace 输出一条消息,指示无法执行日志记录。

    (我的重点)

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

    【讨论】:

    • 实际上,log4net 确实有能力导致应用程序崩溃(至少是紧凑的框架/Windows 移动应用程序) - 有点。使用 log4net 的 UDP appender 会导致 ActiveSync(将设备连接到 PC)崩溃。我在一次演示中了解到这一点,我们失去了巨大的联系。
    • 我认为在 Windows 服务中使用 log4net 和 Windows 事件日志是完全合理的。非常高级事件的 Windows 事件日志,系统管理员可以快速查看;以及更详细的 log4net 日志,提供有关代码活动的大量详细信息。
    【解决方案2】:

    我认为记录异常是您最好吞下异常的少数情况之一。在大多数情况下,您不希望您的应用因此而失败。

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

    【讨论】:

    • 写入 EventLog 不是“自己编写日志代码”。
    • @MusiGenesis:请解释一下。对我来说,编写特定于日志记录的异常处理就是编写已经被 Log4Net 或 NLog 做得更好的代码。我认为没有理由编写另一个日志框架。
    • System.Diagnostics.EventLog 是用于写入 Windows 事件日志的内置 .NET 类,而不是他们自己编写的。
    • 此外,问题是“编写事件日志条目的最佳方法是什么?”,而不是“最好的日志框架是什么?”
    • 你为什么要写你自己的服务,windows预装了一堆windows服务!您所要做的就是启动其中一个!.. 否则,只需谷歌“服务”,您就会看到数百万,其中之一肯定可以满足您的需求.. 不要重新发明轮子男人
    【解决方案3】:

    考虑使用Logging App Block

    企业库日志记录应用程序块简化了常见日志记录功能的实现。开发人员可以使用 Logging Block 将信息写入各种位置:

    • 事件日志
    • 一封电子邮件
    • 一个数据库
    • 消息队列
    • 一个文本文件
    • WMI 事件
    • 使用应用程序块扩展点的自定义位置

    【讨论】:

      【解决方案4】:
      System.Diagnostics.EventLog log = 
          new System.Diagnostics.EventLog("YourLogNameHere");
      log.ModifyOverflowPolicy(
          System.Diagnostics.OverflowAction.OverwriteAsNeeded, 0);
      

      这应该可以解决您的溢出问题。一旦正确配置,事件日志通常非常可靠。在使用事件日志时,我曾经添加一个快速的紧急备份记录器,它只是写入一个文本文件(这大约需要 5 分钟来写入)。它从来没有被调用过。

      【讨论】:

      • 很遗憾,我不能更改事件日志的配置。
      • 您能否创建一个特定于应用程序的日志并写入该日志而不是一般的“应用程序”日志?
      • 虽然这可能适用于 Windows 服务(通常以提升的权限运行),但普通用户(即非管理员)运行的桌面应用程序在调用 ModifyOverflowPolicy 时可能会失败,因为它需要普通用户默认没有的注册表权限。
      【解决方案5】:

      您不能只使用 ServiceBase 类已经提供的默认事件日志机制吗?如果您的服务没有启动,它将自动在事件日志中写入一个条目,说明这一点(使用堆栈跟踪)。

      除此之外,关于关于 log4net(或任何其他尽力而为,如日志系统)的 cmets,我认为这真的取决于你想要实现的目标。

      在您的示例中,使用 log4net(或对 ServiceBase 的事件记录的内置支持)很可能是可以的。

      但是,在某些情况下,即使发生错误并且无法在某处记录该事实也是一个问题。例如,假设一个身份验证或授权系统。如果您无法成功且可靠地记录密码身份验证由于错误的凭据而失败,则可能不允许您继续(顺便说一句,如果您的密码身份验证成功,则同样如此)。

      因此,有时您需要知道日志记录尝试何时失败并自行处理。 这当然是有限制的(鸡-蛋-问题),并且您所做的事情是高度特定于特定应用程序或场景的。

      【讨论】:

        【解决方案6】:

        让我们退后一步:

        系统事件日志用于提醒系统管理员系统出现问题。您应该允许服务启动失败。这将显示在系统错误日志中,并报告了“服务控制管理器”的来源。这意味着系统管理员将知道失败。

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

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

        【讨论】:

        • 举个具体例子,为什么要让服务启动失败呢?记录服务启动和停止事件是常见的做法,但事件日志已满并不是服务不启动的好理由。运行的服务更重要,事件记录只是“很高兴拥有”。
        • 我不认为我完全理解你的问题。您是否将所有异常记录到事件日志中?还是只是在应用程序崩溃之前在顶层未捕获的异常?
        • 我的问题不是关于异常日志,而是关于写入日志时发生的异常。在服务启动期间发生异常的特定情况下,我正在编写一条日志消息“服务无法启动”,其中还包含有关异常的详细信息,但当前的问题是写入任何日志条目。
        猜你喜欢
        • 2017-12-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-06-23
        • 1970-01-01
        • 2010-10-16
        • 2011-04-25
        相关资源
        最近更新 更多