15

我最近在部署 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方法中检查事件日志状态,还是你有更好的建议?

4

6 回答 6

11

使用 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 的问题,让您的生活更轻松。

于 2008-11-24T10:46:50.700 回答
4
System.Diagnostics.EventLog log = 
    new System.Diagnostics.EventLog("YourLogNameHere");
log.ModifyOverflowPolicy(
    System.Diagnostics.OverflowAction.OverwriteAsNeeded, 0);

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

于 2008-11-24T13:25:04.187 回答
3

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

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

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

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

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

于 2008-11-25T07:12:30.303 回答
2

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

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

于 2008-11-24T10:49:17.153 回答
2

研究使用Logging App Block

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

  • 事件日志
  • 一封电子邮件
  • 一个数据库
  • 消息队列
  • 一个文本文件
  • WMI 事件
  • 使用应用程序块扩展点的自定义位置
于 2008-11-24T10:49:46.840 回答
0

让我们退后一步:

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

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

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

于 2009-06-04T12:17:09.173 回答