# 二、Windows 事件日志

Windows 服务与用户没有交互，因此没有界面。无论需要产生什么输出，通常都会写入某种日志，例如数据库。一个很好的登录位置是窗口事件日志。

Windows 事件日志是计算机警报和通知的记录。微软将事件定义为“系统或程序中需要通知用户或在日志中添加条目的任何重大事件。”

Windows 操作系统按类型对事件进行分类。例如，*信息事件*描述任务的成功完成，例如安装应用程序。一个*警告事件*通知管理员潜在的问题，例如磁盘空间不足。*错误信息*描述了可能导致功能丧失的重大问题。一个*成功审核* *事件*表示一个被审核的安全事件完成，比如一个终端用户成功登录。*失败审核事件*描述了未成功完成的审核安全事件，例如最终用户通过输入不正确的密码将自己锁在门外。

日志条目中的每个事件都包含以下信息:

*   **日期:**事件发生的日期
*   **时间:**事件发生的时间
*   **用户:**事件发生时登录的用户的名称
*   **计算机:**计算机的名称
*   **事件标识:**指定事件类型的窗口标识号
*   **来源:**引发事件的程序或组件
*   **类型:**事件的类型(信息、警告、错误、安全成功审核或安全失败审核)

视窗事件检视器

窗口事件查看器是一个显示重要事件详细信息的工具(例如，没有按预期启动的程序或自动下载的更新)。在排除 Windows 和其他程序(如 Windows 服务)的问题和错误时，Windows 事件查看器会很有帮助。可以在控制面板的管理工具部分找到窗口事件查看器。

可以通过窗口事件查看器查看窗口事件日志中的条目。这可用于调试服务代码。事实上，这是唯一的方法，因为窗口服务没有用户界面。下图显示了窗口事件查看器的主窗口。

![](img/image006.jpg)

图 4:窗口事件查看器

## 将服务绑定到窗口事件日志

该服务需要绑定到窗口事件日志，以便在其中写入条目。为此，需要在`OnStart`方法中放置以下代码。

代码示例 5

```cs
          if (!System.Diagnostics.EventLog.SourceExists("MonitorService"))
              System.Diagnostics.EventLog.CreateEventSource("MonitorService", "Application");

```

如图所示，服务首先查询事件日志，询问先前是否已经创建了`MonitorService`的事件源。如果没有，则使用`CreateEventSource`方法创建事件源，该方法指定服务发送的每个日志将被写入`Application`类型的日志中。

`OnStart`方法的代码如下:

代码示例 6

```cs
          protected override void OnStart(string[] args)
          {
              if (!System.Diagnostics.EventLog.SourceExists("MonitorService"))
                  System.Diagnostics.EventLog.CreateEventSource("MonitorService", "Application");

              this.serviceTimer = new System.Timers.Timer(300);
              this.serviceTimer.AutoReset = true;
              this.serviceTimer.Elapsed += new System.Timers.ElapsedEventHandler(this.timer_Elapsed);
              this.serviceTimer.Start();
          }

```

## 将事件写入 Windows 事件日志

该服务需要写入 Windows 事件日志，以便与用户通信。为了简化代码，将在类定义代码中编写记录事件的方法。这个方法将接收两个参数:一个包含将要写入日志的消息的字符串，另一个将指示正在保存的事件类型。

事件类型

如前所述，窗口事件日志允许您指定正在保存的事件类型。`EventLogEntryType`枚举将用于该目的。

允许的类型如下:

*   信息
*   警告
*   错误
*   安全成功审核(成功审核):当用户成功登录到网络或计算机时，会发生此类事件。
*   安全失败审核(failure audit):当用户无法登录到网络或计算机时，会发生这种类型的事件。

LogEvent 方法

下面的示例显示了该方法的代码。

代码示例 7

```cs
          private void LogEvent(string message, EventLogEntryType entryType)
          {
              System.Diagnostics.EventLog eventLog = new System.Diagnostics.EventLog();

              eventLog = new System.Diagnostics.EventLog();
              eventLog.Source = "MonitorService";
              eventLog.Log = "Application";
              eventLog.WriteEntry(message, entryType);

          }

```

如前所示，每次执行该方法时，它都会创建一个`EventLog`实例。要执行日志条目写入，`Source`和`Log`属性需要存储事件源和将在其中写入条目的日志部分。在这种情况下，`MonitorService`将是条目的来源，`Application`是日志部分。一旦这些值存储在它们各自的属性中，`WriteEntry`方法将条目写入窗口事件日志。

到目前为止，类定义代码看起来如何

此时，服务类定义的代码如下所示:

代码示例 8

```cs
          public partial class monitorservice : ServiceBase
          {
              private System.Timers.Timer serviceTimer = null;

              public monitorservice()
              {
                  InitializeComponent();
              }

              protected override void OnStart(string[] args)
              {
                  if (!System.Diagnostics.EventLog.SourceExists("MonitorService"))
                      System.Diagnostics.EventLog.CreateEventSource("MonitorService", "Application");

                  this.LogEvent(String.Format("MonitorService starts on {0} {1}", System.DateTime.Now.ToString("dd-MMM-yyyy"), DateTime.Now.ToString("hh:mm:ss tt")), EventLogEntryType.Information);

                  this.serviceTimer = new System.Timers.Timer(300);
                  this.serviceTimer.AutoReset = true;
                  this.serviceTimer.Elapsed += new System.Timers.ElapsedEventHandler(this.timer_Elapsed);
                  this.serviceTimer.Start();
              }

              private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
              {

              }

              protected override void OnStop()
              {
                  this.serviceTimer.Stop();
                  this.serviceTimer.Dispose();
                  this.serviceTimer = null;

                  this.LogEvent(String.Format("MonitorService stops on {0} {1}", System.DateTime.Now.ToString("dd-MMM-yyyy"), DateTime.Now.ToString("hh:mm:ss tt")), EventLogEntryType.Information);

              }

              private void LogEvent(string message, EventLogEntryType entryType)
              {
                  System.Diagnostics.EventLog eventLog = new System.Diagnostics.EventLog();

                  eventLog = new System.Diagnostics.EventLog();
                  eventLog.Source = "MonitorService";
                  eventLog.Log = "Application";
                  eventLog.WriteEntry(message, entryType);

              }

          }

```

请注意，`OnStart`和`OnStop`方法会写入 Windows 事件日志，通知它们各自被触发的日期和时间。在这种情况下，它被认为是两者的信息日志条目类型。

| ![](img/tip.png) | 提示:每次程序写入 Windows 事件日志时，都应该使用日志条目类型，以便阐明程序写入的原因。 |

## 章节总结

Windows 事件日志是计算机警报和通知的记录。事件可以定义为“系统或程序中需要通知用户或在日志中添加条目的任何重大事件。”Windows 操作系统按类型对事件进行分类。*信息事件*描述任务的成功完成；一个*警告事件*通知管理员潜在的问题；*错误信息*描述了可能导致功能丧失的重大问题；a *成功审核*事件表示已审核安全事件完成，如终端用户成功登录；而*失败审核事件*描述的是未成功完成的审核安全事件，例如终端用户通过输入不正确的密码将自己锁在门外。

可以通过 Windows 事件查看器查看写入 Windows 事件日志的条目，该查看器位于控制面板的管理工具部分。窗口事件查看器是一个工具，它显示计算机上重大事件的详细信息(例如，未按预期启动的程序或自动下载的更新)，在对窗口和其他程序(如窗口服务)的问题和错误进行故障排除时很有帮助。

由于 Windows 服务没有接口，因此在 Windows 事件日志中写入条目是与用户通信的首选方式。为了写入这些条目，服务需要绑定到 Windows 事件日志。这可以使用`System.Diagnostics.EventLog`命名空间的`CreateEventSource()`方法来实现。

建议编写一个单独的方法来处理条目编写活动。必须使用`EventLogEntryType`枚举来阐明为什么每个条目都是由程序编写的。