介绍
在程序部署之前,要经历许多软件工程中定义的重要阶段,如需求分析、设计、编码和测试等。 但是,并不是说一旦程序部署并使用之后就脱离软件工程的各个阶段了。 不管一个web程序有多好的设计、多好的编码、多好的测试,它总是会有掉链子的时候。
如数据库服务器掉线,web站点比你凭经验预期的有更大的负载,或者你的web服务器本身的硬件出现问题等。 除非你的程序是很轻量级的或者是上帝给你写的,否则它总是会时不时地蹦出一些问题。
为了发现和诊断这些问题,非常重要的一步就是监视web程序并记录日志。 有很多开源的软件和微软开发的类库可以帮助你记录未处理的异常并通知给开发人员。 如何记录未处理的异常可以参看人性化地响应未处理异常 – 处理未经处理的异常。
ASP.NET 1.x不包括任何内嵌的日志和通知系统,所以需要开发人员写一些代码或者做一些配置。 然而,ASP.NET 2.0提供了内嵌的“健康监测”工具,你可以方便快捷地通过配置来把web站点的一些事件记录到事件日志、数据库、WMI、email或ASP.NET页面跟踪系统。 另外,健康监测系统是使用Provider设计模式(译者注:可以看一下我写的ASP.NET 2.0中实现Provider设计模式的文章)开发的,这样我们就可以实现自己的记录日志的逻辑了。
本文是研究ASP.NET 2.0的健康监测系统的系列文章的第一篇。 我们将在此学一学健康监测系统的基础知识,以及如何建立一个健康监测系统,从而将日志记录到SQL Server数据库。 继续往下看,你会知道得更多!
健康监测系统概述
ASP.NET 2.0的健康监测系统是用来监测运营环境中ASP.NET程序的运行状况的。 它可以记录事件信息到一个指定的日志源中。 例如,它可以记录像程序开始和停止、登录的成功和失败、未处理的异常信息等到一个像Windows事件日志或SQL Server数据库这样的日志源。 配置健康监测系统是非常容易的,只用在Web.config中增加一些配置信息从而指定事件监测者和要发往的日志源即可。
虽然.NET 2.0框架提供了一些内嵌的健康监测事件和日志源,但是当你需要增加自定义事件或换成另一个日志源的时候并不需要更改这些东西。 你可以通过扩展WebBaseEvent类来创建新的事件,通过扩展WebEventProvider类来创建自定义的日志源。 健康监测系统可以在设计模式中使用,并且允许你通过对配置信息的一些改变,从而在程序里添加自定义事件和自定义日志源。
在这个系列文章的未来的内容里,我们将会探讨一下如何创建自定义事件和自定义日志源。 而本文中,我们将只使用内嵌的事件和日志源来做示例。
配置健康监测系统
通过Web.config的<healthMonitoring>元素可以配置健康监测系统,该元素用于指定事件映射、事件订阅规则和日志源。 它们中的每一项都是作为<healthMonitoring>元素的子元素被定义的。 让我们来分别看看这些子元素:
·Event Mappings (<eventMappings>) – 顾名思义,就是一套事件。 它的name会在其它节点中被引用。
·Log Sources (<providers>) - 顾名思义,就是能作为日志源的类型。
·Event Subscription Rules (<rules>) – 与定义在<eventMappings>节点的事件和定义在<providers>节点的日志源相关联。
接下来的这个示例演示了如何将这三个节点结合起来使用。 首先我们定义了一个名为“All Errors”的事件影射,它表示的是所有从WebBaseErrorEvent类继承的事件类。 接下来,定义了一个名为“EventLogProvider”的日志源,它会映射到EventLogWebEventProvider类,其意味着事件信息要被记录到Windows的事件日志中。 最后的名为“All Errors Default”的事件规则描述用来关联“All Errors”事件,并把相关日志记录到“EventLogProvider”日志源中。 像这样定义完Web.config后,如果发生任何未处理异常或明显的错误事件,都将记录到Windows的事件日志中。
<configuration>
<system.web>
<healthMonitoring enabled="true">
<eventMappings>
<clear />
<add name="All Errors" type="System.Web.Management.WebBaseErrorEvent"
startEventCode="0" endEventCode="2147483647" />
</eventMappings>
<providers>
<clear />
<add name="EventLogProvider" type="System.Web.Management.EventLogWebEventProvider" />
</providers>
<rules>
<clear />
<add name="All Errors Default" eventName="All Errors" provider="EventLogProvider"
profile="Default" minInstances="1" maxLimit="Infinite" minInterval="00:00:00" />
</rules>
</healthMonitoring>
</system.web>
</configuration>
本文结束后会有一个web示例程序提供下载,其内有一个网页,网页中有一个按钮,当你单击这个按钮的时候就会触发ApplicationException。 当你访问了这个网页并单击了这个按钮后,就会出现着名的“黄页”,其意味着发生了一个未处理的异常。 之后,该异常信息就会记录到Windows的事件日志中。
发生了未处理异常后所显示的“黄页”
未处理异常的详细信息被记录到了Windows的事件日志中。
默认情况下,ASP.NET 2.0程序已经启用了健康监测系统,并且会记录所有的错误事件和失败的请求到Windows的事件日志中。 所有web程序都需要读取machine级别的Web.config,你可以在该文件中查看或修改健康监测系统的默认功能,此文件的具体位置在“%WINDOWS%\Microsoft.NET\Framework\版本号\CONFIG\”文件夹内。 在上面的示例中,我使用了<clear />,它的作用是在指定我自己的配置之前移除默认设置。
除了指定的“EventLogProvider”日志源外,默认配置中还包括其他两个Provider,如下所示:
·“SqlWebEventProvider” – 使用SqlWebEventProvider类把事件信息记录到SQL Server数据库中。 其默认连接使用的是“LocalSqlServer”所指的连接字符串,它会映射到“App_Data”文件夹内的擜SPNETDB.MDF数据库。 默认情况下,Membership使用的也是这个数据库。 (关于Membership的更多信息请参看Examining ASP.NET 2.0's Membership, Roles, and Profile)
·“WmiWebEventProvider” – 使用WmiWebEventProvider类把事件信息记录到Windows Management Instrumentation(WMI)
虽然在.NET框架中附加了这3个日志源的Provider,但是默认情况下它们并没有包含在<providers>节点内。 如果你想添加这些Provider或是自定义的Provider,那么你需要像我们上面的示例那样在Web.config里添加<prviders>元素。
另外,在<eventMappings>节点下还有一些预定义事件可以让你设置。 我们查看一下machine级别的Web.config文件。
本文接下来的部分将研究一下如何使用“SqlWebEventProvider”日志源,它可以把错误日志记录到SQL Server数据库中。
·配置web程序的健康监测系统,使其记录日志到SQL Server数据库。
·为数据库添加必需的结构信息,使其可以作为日志源而被使用。
如果你给“SqlWebEventProvider”日志源使用的是默认数据存储的话(App_Data文件夹内的ASPNETDB.MDF数据库),那么该数据库会在健康监测系统首次记录事件的时候被自动地创建。 如果你想使用其它数据库,那么就需要用到ASP.NET SQL Server注册工具(aspnet_regsql.exe)了。 你可以在命令行中运行它,如下所示:
aspnet_regsql.exe -E -S serverName -d database -A w
aspnet_regsql.exe -U userID -P password -S serverName -d database -A w
aspnet_regsql.exe程序放置在“%WINDOWS%\Microsoft.NET\Framework\版本号\”文件夹内。 同样在这个文件夹内,你也会发现一个名为“InstallWebEventSqlProvider.sql”的文件,该文件就是创建健康监测系统的数据库结构的T-SQL脚本。
它的结构非常地简单易懂,就是一个表 – aspnet_WebEvent_Events和一个存储过程 – aspnet_WebEvent_LogEvent。 就是这些东西,很简单吧。 当健康监测系统监测到发生了某一事件,并且你已经配置了记录日志到“SqlWebEventProvder”日志源,那么存储过程aspnet_WebEvent_LogEvent将会被执行,从而在aspnet_WebEvent_Events表中添加一条新记录。
当把数据库建完后(如果你使用的是App_Data文件夹内的ASPNETDB.MDF数据库,那么你就不需要做这件事了),你就可以在Web.config中添加<healthMonitoring>节点了。 通过下面示例那样的配置,就可以指示健康监测系统使用“SqlWebEventProvider”日志源记录所有的错误事件和所有的程序事件。 你应该在<providers>节点内重新设置“SqlWebEventProvider”。 我使用的是默认的连接字符串(“LocalSqlServer”),如果你不想使用ASPNETDB.MDF作为你的日志数据库,那么也可以修改这个名字,改为在Web.config的<connectionStrings>节点中注册的连接字符串的名字。
<configuration>
<system.web>
<healthMonitoring enabled="true">
<eventMappings>
<clear />
<!--记录所有错误事件-->
<add name="All Errors" type="System.Web.Management.WebBaseErrorEvent"
startEventCode="0" endEventCode="2147483647" />
<!--记录程序开始和结束事件-->
<add name="Application Events" type="System.Web.Management.WebApplicationLifetimeEvent"
startEventCode="0" endEventCode="2147483647"/>
</eventMappings>
<providers>
<clear />
<add connectionStringName="SqlConnectionString" maxEventDetailsLength="1073741823"
buffer="false" name="SqlWebEventProvider" type="System.Web.Management.SqlWebEventProvider" />
</providers>
<rules>
<clear />
<add name="All Errors Default" eventName="All Errors" provider="SqlWebEventProvider"
profile="Default" minInstances="1" maxLimit="Infinite" minInterval="00:00:00" custom="" />
<add name="Application Events Default" eventName="Application Events"
provider="SqlWebEventProvider" profile="Default" minInstances="1"
maxLimit="Infinite" minInterval="00:00:00" custom="" />
</rules>
</healthMonitoring>
</system.web>
</configuration>
像上面这样配置完后,无论程序的开始或是停止,又或是发生了错误事件,其事件信息都会被记录到App_Data文件夹下的ASPNETDB.MDF数据库。(如果这个数据库不存在,则它会被自动地创建。)
在本文的结尾处你可以下载到一个简单的web站点程序,它演示了这个功能。 该程序包括两个网页,Default.aspx和Log.aspx。Default.aspx内有一个按钮,当点击了这个按钮后就会触发ApplicationException。 Log.aspx中使用的是GridView,DetailsView和两个SqlDataSource控件,用于显示aspnet_WebEvent_Events表中的事件信息。
当把数据库建完后(如果你使用的是App_Data文件夹内的ASPNETDB.MDF数据库,那么你就不需要做这件事了),你就可以在Web.config中添加<healthMonitoring>节点了。
通过下面示例那样的配置,就可以指示健康监测系统使用“SqlWebEventProvider”日志源记录所有的错误事件和所有的程序事件。 你应该在<providers>节点内重新设置“SqlWebEventProvider”。 我使用的是默认的连接字符串(“LocalSqlServer”),如果你不想使用ASPNETDB.MDF作为你的日志数据库,那么也可以修改这个名字,改为在Web.config的<connectionStrings>节点中注册的连接字符串的名字。
<configuration>
<system.web>
<healthMonitoring enabled="true">
<eventMappings>
<clear />
<!--记录所有错误事件-->
<add name="All Errors" type="System.Web.Management.WebBaseErrorEvent"
startEventCode="0" endEventCode="2147483647" />
<!--记录程序开始和结束事件-->
<add name="Application Events" type="System.Web.Management.WebApplicationLifetimeEvent"
startEventCode="0" endEventCode="2147483647"/>
</eventMappings>
<providers>
<clear />
<add connectionStringName="SqlConnectionString" maxEventDetailsLength="1073741823"
buffer="false" name="SqlWebEventProvider" type="System.Web.Management.SqlWebEventProvider" />
</providers>
<rules>
<clear />
<add name="All Errors Default" eventName="All Errors" provider="SqlWebEventProvider"
profile="Default" minInstances="1" maxLimit="Infinite" minInterval="00:00:00" custom="" />
<add name="Application Events Default" eventName="Application Events"
provider="SqlWebEventProvider" profile="Default" minInstances="1"
maxLimit="Infinite" minInterval="00:00:00" custom="" />
</rules>
</healthMonitoring>
</system.web>
</configuration>
像上面这样配置完后,无论程序的开始或是停止,又或是发生了错误事件,其事件信息都会被记录到App_Data文件夹下的ASPNETDB.MDF数据库。(如果这个数据库不存在,则它会被自动地创建。)
注意,每一个事件都有与其相关联的EventCode值。 参考Erik Reitan的BLOG文章 - FAQ - Health Monitoring in ASP.NET 2.0,它里面有一个表格列出了事件代码和事件类型(当然文中还有其它有用的信息)。 (译者注:我把它转载过来,如下表所示)
InvalidEventCode
-1
UndefinedEventCode
0
UndefinedEventDetailCode
0
ApplicationCodeBase
1000
ApplicationStart
1001
ApplicationShutdown
1002
ApplicationCompilationStart
1003
ApplicationCompilationEnd
1004
ApplicationHeartbeat
1005
RequestCodeBase
2000
RequestTransactionComplete
2001
RequestTransactionAbort
2002
ErrorCodeBase
3000
RuntimeErrorRequestAbort
3001
RuntimeErrorViewStateFailure
3002
RuntimeErrorValidationFailure
3003
RuntimeErrorPostTooLarge
3004
RuntimeErrorUnhandledException
3005
WebErrorParserError
3006
WebErrorCompilationError
3007
WebErrorConfigurationError
3008
WebErrorOtherError
3009
WebErrorPropertyDeserializationError
3010
WebErrorObjectStateFormatterDeserializationError
3011
AuditCodeBase
4000
AuditFormsAuthenticationSuccess
4001
AuditMembershipAuthenticationSuccess
4002
AuditUrlAuthorizationSuccess
4003
AuditFileAuthorizationSuccess
4004
AuditFormsAuthenticationFailure
4005
AuditMembershipAuthenticationFailure
4006
AuditUrlAuthorizationFailure
4007
AuditFileAuthorizationFailure
4008
AuditInvalidViewStateFailure
4009
AuditUnhandledSecurityException
4010
AuditUnhandledAccessException
4011
MiscCodeBase
6000
WebEventProviderInformation
6001
ApplicationDetailCodeBase
50000
ApplicationShutdownUnknown
50001
ApplicationShutdownHostingEnvironment
50002
ApplicationShutdownChangeInGlobalAsax
50003
ApplicationShutdownConfigurationChange
50004
ApplicationShutdownUnloadAppDomainCalled
50005
ApplicationShutdownChangeInSecurityPolicyFile
50006
ApplicationShutdownBinDirChangeOrDirectoryRename
50007
ApplicationShutdownBrowsersDirChangeOrDirectoryRename
50008
ApplicationShutdownCodeDirChangeOrDirectoryRename
50009
ApplicationShutdownResourcesDirChangeOrDirectoryRename
50010
ApplicationShutdownIdleTimeout
50011
ApplicationShutdownPhysicalApplicationPathChanged
50012
ApplicationShutdownHttpRuntimeClose
50013
ApplicationShutdownInitializationError
50014
ApplicationShutdownMaxRecompilationsReached
50015
StateServerConnectionError
50016
AuditDetailCodeBase
50200
InvalidTicketFailure
50201
ExpiredTicketFailure
50202
InvalidViewStateMac
50203
InvalidViewState
50204
WebEventDetailCodeBase
50300
SqlProviderEventsDropped
50301
WebExtendedBase
100000
结论
ASP.NET 2.0内置的健康监测系统可以非常容易地使指定的事件自动地记录到指定的日志源。 本文中,我们研究了两种内置日志源:“EventLogProvider”和“SqlWebEventProvider”,它们会分别记录事件信息到Windows的事件日志中和SQL Server数据库的一个表里。 健康监测系统可以捕获自定义事件,也可以使用其它日志源。 在后面的文章中,我们将会看到更多的日志源,甚至是创建我们自己的日志源。 我们也会知道如何创建自己的事件,以及如何自动地触发一个事件。
到这里本文结束。祝编程愉快!
本文作者: