1、 目的
应用系统的开发和维护离不开日志系统,选择一个功能强大的日志系统解决方案是应用系统开发过程中很重要的一部分。在.net环境下的日志系统解决方案有许多种,log4net是其中的佼佼者。
在Windows2000及以上操作系统中,有一个Windows日志系统,它包括应用程序(Application)事件日志、系统(System)日志和安全(Security)日志,事件日志也可以是自定义日志。在.net Framework中也提供了相应的类和接口来使用应用程序事件日志或者自定义事件日志。使用Windows日志可以使应用系统与操作系统更好的结合,与单纯使用自定义的日志系统相比,因为有了操作系统的支持,查询和管理日志更方便。在实际应用中,根据实际情况,可以选择一种合适的日志解决方案,也可以自定义日志系统和Windows日志系统两种日志解决方案同时使用。
2、 使用Windows日志的方法
2.1、方法概述
在.net Framework中提供了一个类EventLog,使用EventLog类可以添加新的事件日志条目或从服务器事件日志中获取已有的条目。EventLog类包括一个WriteEntry()方法,可以用它来把一个新的事件写入到事件日志中。在写入一个新的条目到事件日志时,是使用特定的事件源(event source)来把条目写入到特定的事件日志中。
事件源对于事件日志而言是唯一的。在Windows2000及以上操作系统中,包括一个事件日志:应用程序(Application)事件日志,还有系统(System)日志和安全(Security)日志,并且系统允许自定义事件日志。使用EventLog类,可以将日志条目添加到应用程序(Application)事件日志中,也可以添加到自定义事件日志中。事件源相当于事件日志的下一级目录,每一条日志条目都必须对应一个事件源。EventLog类可以创建一个自定义事件日志,也可以创建一个事件源,事件源可以创建在应用程序(Application)事件日志中,也可以创建在自定义事件日志中。Windows日志系统如下图所示:
为了便于不同应用系统之间的日志区分和查看方便,一般将事件源创建在自定义事件日志中,可以创建多个事件日志,一个事件日志也可以创建多个事件源。
2.2、事件日志和事件源创建方法
创建一个新的事件日志或事件源时,其实是在对注册表添加一个条目。由于写注册表要求特殊的权限,所以在Web项目中创建事件日志和事件源就存在权限和安全的问题,Application项目中不存在此问题,本文重点讲述Web项目中Windows日志使用方法,Application项目中的使用方法类似于Web项目,抛弃掉Web项目中的权限和安全处理即可,本文不再赘述。
在Web项目中,当使用asp.net向系统中创建一个事件日志或者一个事件源时,可能会得到如下异常错误消息: System.Security.SecurityException: 不允许所请求的注册表访问权。这是因为运行asp.net进程的默认帐户是ASPNET(在IIS6.0下面是NetworkService),而此账户默认只有读权限,没有写权限,所以不能创建事件日志或事件源。解决此问题的办法有提升ASPNET帐户的权限、不在程序内部创建事件日志或事件源等,主要有以下三种解决方案:
A、 在程序运行之前,定义要使用的事件日志和事件源,打开注册表编辑器,手工将事件日志和事件源添加到注册表中。主要步骤如下:
① 点击“开始”菜单,再点击“运行”。
② 在“运行”的“打开”框中输入“regedit”,然后按OK按钮,打开注册表编辑器。
③ 在注册表编辑器中找到下列子键:
HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/Eventlog
④ 右键单击“Eventlog”,点击“新建”,再点“项”,将在“Eventlog”的下一级创建一个新的项目,将此项目命名为“TDDN”, TDDN项就是事件日志,可以根据实际情况为此项命名,比如可以命名为项目名称。
⑤ 在“TDDN”项上单击右键,点击“新建”,再点“项”,将在“TDDN”的下一级创建一个新的项,将此项命名为“Weblog”, Weblog项就是事件源,此项也可以根据实际情况命名。
⑥ 关闭注册表编辑器。
这样事件日志和事件源就建好了,如果需要多个事件日志或事件源,重复以上过程。这种方法要求对注册表比较熟悉,操作起来可能有一点复杂,可以写一个类来实现配置注册表,只要运行该类便可添加相应的项目,免除了手工添加的繁琐,这是第二种解决方案,方法如下:
B、 在System.Diagnostics命名空间中有一个EventLogInstaller类,它能够创建和配置应用程序在运行时要读写的事件日志和事件源。通过下列步骤,便能够使用EventLogInstaller类来创建一个事件日志和事件源:
① 用C#来创建一个名为EventLogSourceInstaller的“类库”。
② 在此项目中添加对System.Configuration.Install.dll的引用。
③ 将自动产生的Class1.cs更名为MyEventLogInstaller.cs。
④ 在MyEventLogInstaller.cs中的写入以下代码:
using System;
using System.Diagnostics;
using System.ComponentModel;
using System.Configuration.Install;
namespace EventLogSourceInstaller {
[RunInstaller(true)]
public class MyEventLogInstaller: Installer{
public EventLogInstaller myEventLogInstaller;
public MyEventLogInstaller(){
//Create Instance of EventLogInstaller
myEventLogInstaller = new EventLogInstaller();
// Set the Source of Event Log, to be created.
myEventLogInstaller.Source = "WebLog";
// Set the Log that source is created in
myEventLogInstaller.Log = "TDDN";
Installers.Add(myEventLogInstaller);
}
}
}
⑤ 生成此项目,得到EventLogSourceInstaller.dll。
⑥ 打开Visual Studio .NET 命令提示,转到EventLogSourceInstaller.dll所在目录。
⑦ 运行此命令来创建事件日志和事件源,运行方法为:输入命令InstallUtil EventLogSourceInstaller.dll。
这样程序就在系统中创建一个事件日志:TDDN,在事件日志TDDN下创建了一个事件源:WebLog。
以上的这两种解决方案都是在应用系统运行之前,为系统手工添加事件日志和事件源,这样做没有安全权限问题,不存在安全隐患。更方便的方法还可以在应用系统运行时,让程序自动创建事件日志和事件源,这种方法必须提升ASPNET帐户的系统操作权限,或者给asp.net进程一个有更大权限的模拟帐号。模拟帐号的实现比较复杂,而且功能和安全性上和提升ASPNET帐户没有区别,这里采用的方法是提升ASPNET帐户的权限。以下是第三种解决方案:
C、 提升ASPNET帐户的权限可以直接在Windows系统管理中给ASPNET帐户添加对系统的读写权限,但是这样做存在很严重的安全问题,asp.net进程有直接读写操作系统的权限,将给系统带来很大的安全隐患。这里采用的提升ASPNET帐户权限的方法是只将系统日志的操作权限赋给ASPNET帐户,这样虽然还存在一定的安全隐患,但是隐患已经大大降低,并且可以在程序内部自由创建事件日志和事件源,极大的提高了灵活性。ASPNET帐户权限提升方法如下:
① 点击“开始”,“运行”,输入“regedit”,打开注册表编辑器。
② 在注册表编辑器中找到下列子键:
HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/Eventlog
③ 在Eventlog项目上单击右键,在弹出的菜单中选择“访问许可”选项,然后找到本机的ASPNET帐户加进来,并赋予读写权限。
这样,ASPNET帐户就有了读写系统日志的权限,就可以在程序中根据情况自由创建事件日志和事件源了。在程序中创建事件日志和事件源的方法如下:
调用 EventLog类的CreateEventSource 方法并指定数据源字符串和要创建的事件日志名称,如果将事件日志名称指定为空 (""),事件日志名称将默认为Application,这样不会创建新事件日志,但会为应用程序(Application)事件日志创建指定的数据源。如果创建一个新的事件日志,则在确定事件日志名称是否唯一时将只计算指定字符串的前8 个字母。如下代码所示:
System.Diagnostics.EventLog.CreateEventSource("WebLog", "TDDN");
将创建一个事件日志为TDDN,在该事件日志下创建一个事件源WebLog。要在远程计算机上创建自定义事件日志,要将此计算机名指定为第三个参数。以下代码提供了一个示例:
System.Diagnostics.EventLog.CreateEventSource(" WebLog ", " TDDN ", "myserver");
将在远程计算机myserver上创建该事件日志和事件源。
2.3、写入Windows日志的方法
事件日志与事件源创建的问题解决了,接下来就可以在程序中将日志信息写入到Windows系统日志中了。写入方法是,首先创建EventLog类的一个实例,将其Source属性与事件源名称相关联,最后调用WriteEntry方法来往事件日志中添加日志信息。下面是一段写入系统日志的简单示例代码:
EventLog eventLog = null;
if (!(EventLog.SourceExists("WebLog"))){
EventLog.CreateEventSource("WebLog", "TDDN");
}
if (eventLog == null){
eventLog = new EventLog("TDDN");
eventLog.Source = "WebLog";
}
eventLog.WriteEntry("This is error!", EventLogEntryType.Error);
}
上面程序段中首先判断数据源“WebLog”是否存在,如果不存在调用CreateEventSource方法创建该事件源,然后将事件源与EventLog 类的Source属性关联,进行写操作。传递给WriteEntry方法的第一个参数代表要记录的日志消息,可以写入任何消息。第二个参数代表事件日志的类型。
A、 事件日志类型分类
事件日志的类型用于指示事件日志的严重度。每个事件必须具有单一的类型,应用程序在报告事件时将指示该类型。事件查看器使用该类型来确定在日志的列表视图中显示哪一个图标。它分为如下五类:
① Error:错误事件,它指示用户应该知道的严重问题(通常是功能或数据的丢失)。
② FailureAudit:失败审核事件,它指示当审核访问尝试失败(例如打开文件的尝试失败)时发生的安全事件。
③ Information:信息事件,它指示重要、成功的操作。
④ SuccessAudit:成功审核事件,它指示当审核访问尝试成功(例如成功登录)时发生的安全事件。
⑤ Warning:警告事件,它指示并不立即具有重要性的问题,但此问题可能表示将来会导致问题的条件。
在实际应用中,选择合适的事件日志类型,可以使日志记录更清晰明了,帮助开发维护人员对应用系统更好的监控和维护。
B、 针对事件日志的五种类型分类,可以在应用程序中写一个通用的类,为每一个类型写一个方法来写入事件日志。
下面是自定义的通用类的代码片断:
public void Error(string sourceName, string message){
EventLog eventLog = null;
if (!(EventLog.SourceExists(sourceName))){
EventLog.CreateEventSource(sourceName, "TDDN");
}
if (eventLog == null){
eventLog = new EventLog("TDDN");
eventLog.Source = sourceName;
}
eventLog.WriteEntry(message, EventLogEntryType.Error);
}
public void Warning(string sourceName, string message){
EventLog eventLog = null;
if (!(EventLog.SourceExists(sourceName))){
EventLog.CreateEventSource(sourceName, "TDDN");
}
if (eventLog == null){
eventLog = new EventLog("TDDN");
eventLog.Source = sourceName;
}
eventLog.WriteEntry(message,System.Diagnostics.EventLogEntryType.Warning);
}
类似的可以写出其它三种类型的事件日志写入方法。该类方法将事件源(sourceName)和日志消息(message)作为参数传递,这样可以提高事件日志写入的灵活性。
C、 调用通用类事件日志写入的方法
通用类方法的调用非常简单,如下代码片断是调用通用类中Error方法的一个范例:
string strSourceName="WebLog";
CoustomEventLog log=new CoustomEventLog();
log.Error(strSourceName,"This is Error!");
strSourceName是事件源,log是CoustomEventLog类(即通用类)的一个实例,然后调用Error方法将日志消息“This is Error!”写入到事件日志中。
也可以将程序中抛出的异常信息写入事件日志:
string strSourceName="WebLog";
CoustomEventLog log=new CoustomEventLog();
try{
//执行事件<PRE style="TEXT-JUSTIFY: inter-ideograph; BACKGROUND: #dddddd; MARGIN: 12pt 0cm 12pt 17.95pt; LAYOUT-GRID-MODE: char; TEXT-INDENT: 0.05pt; LINE-HEIGHT: 12pt; TEXT-ALIGN: justify; mso-line-height-rule: exactly; mso-layout-grid-align: none; tab-stops: 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt; m