Evjen c32.tex V2 - 01/28/2008 4:05pm Page 1485 Chapter 32: Instrumentation <providers> <add name="EventLogProvider" type="System.Web.Management.EventLogWebEventProvider,System.Web, Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" /> </providers> The three attributes discussed so far are required attributes. The rest are considered optional attributes. The minInstances attribute defines the minimum number of times this Web event must occur before it is logged. The maxLimit attribute defines the maximum number of instances of the defined Web event that can be recorded. If instances are likely to occur because of some continuous loop, you might want to add a value here. The minInterval attribute denotes the minimum time allowed between log entries. This means that if the minInterval is set to 00:01:00 and two Web events being monitored occur within 15 seconds of each other, the first one is recorded but the second instance is discarded because it falls within the 1-minute setting. Within the <rules> section, you can also see a profile attribute defined in the <add /> elements of the rules defined. The value of this attribute comes from a definition that is supplied from the <profiles> section of the <healthMonitoring> section. This section is discussed next. < profiles > The <profiles> section enables you to define some of the behaviors for Web event monitoring. These definitions are utilized by any number of rule definitions within the <rules> section. An example use of the <profiles> section is illustrated in Listing 32-7. Listing 32-7: Using the <profiles> section <configuration> <system.web> <healthMonitoring enabled="true"> <eventMappings> <! Code removed for clarity > </eventMappings> <providers> <! Code removed for clarity > </providers> <rules> <! Code removed for clarity > </rules> <profiles> <clear /> <add name="Default" minInstances="1" maxLimit="Infinite" minInterval="00:01:00" custom="" /> Continued 1485 Evjen c32.tex V2 - 01/28/2008 4:05pm Page 1486 Chapter 32: Instrumentation <add name="Critical" minInstances="1" maxLimit="Infinite" minInterval="00:00:00" custom="" /> </profiles> </healthMonitoring> </system.web> </configuration> As with the other sections, you add a profile definition by using the <add /> element within the <profiles> section. The name attribute allows you to provide a friendly name that is then utilized from the definitions placed within the <rules> section, as illustrated here: <rules> <add name="All Errors Default" eventName="All Errors" provider="EventLogProvider" profile="Default" minInstances="1" maxLimit="Infinite" minInterval="00:01:00" custom="" /> </rules> The definitions in the <profiles> section also use the attributes minInstances , maxLimit ,and min- Interval . These have the same meanings as if they were used directly in the <rules> section (see the explanation in the previous section). The idea here, however, is that you can more centrally define these values and use them across multiple rule definitions. Writing Events via Configuration: Running the Example Using the sample <healthMonitoring> section (illustrated in the previous listings in this chapter), you can now write all errors as well as audits that fail (failed logins) to the event log automatically. To test this construction in the <healthMonitoring> section, create a simple ASP.NET page that allows you to divide two numbers and then show the result of the division on the screen. An example ASP.NET page is presented in Figure 32-11. Figure 32-11 1486 Evjen c32.tex V2 - 01/28/2008 4:05pm Page 1487 Chapter 32: Instrumentation As you can see from this page, you can enter a single number in the first text box and another in the second text box and press the calculate button. This allows the two numbers to be divided. The result appears in a Label control on the page. In this example, the code intentionally does not use any exception handling. Therefore, if the end user tried to divide 5 by 0 (zero), an exception is thrown. This event, in turn, causes the exception to be written to the event log. In fact, if you run a similar example and look in the event log, you find that the error has indeed been written as you have specified it should be within the web.config file. The report from the event log is presented in Figure 32-12. Figure 32-12 Routing Events to SQL Server Pushing Web events to the event log is something most Web applications do and is also something you should consider if you have overridden these built-in (and default) features. Even more powerful than writing them to the event log, however, is being able to write them to a database. Writing them to a database allows you to actually create a larger history, makes them more secure, and allows you to more easily retrieve the values and use them in any type of administration application that you might create. This capability was briefly introduced in Chapter 1 and is not that difficult to work with. If you work from the same <healthMonitoring> section created earlier in this chapter, writing the events to SQL Server is as simple as adding some <add /> elements to the various sections. 1487 Evjen c32.tex V2 - 01/28/2008 4:05pm Page 1488 Chapter 32: Instrumentation Asshownintheprevious <providers> section, a declaration actually exists for recording events into SQL Server. It is presented here again: <providers> <clear /> <add name="EventLogProvider" type="System.Web.Management.EventLogWebEventProvider,System.Web, Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" /> <add name="SqlWebEventProvider" connectionStringName="LocalSqlServer" maxEventDetailsLength="1073741823" buffer="false" bufferMode="Notification" type="System.Web.Management.SqlWebEventProvider,System.Web, Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" /> <add name="WmiWebEventProvider" type="System.Web.Management.WmiWebEventP rovi der,System.Web, Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" /> </providers> If you look over this bit of code, you see the definition to record events into SQL Server is presented in the bold section within the <providers> section. The section in bold shows a connection to the SQL Server instance that is defined by the LocalSqlServer connection string name. You can find this connection string in the machine.config file, and you see that it points to an auto-generated SQL Server Express file that ASP.NET can work with. <connectionStrings> <add name="LocalSqlServer" connectionString="data source=. \ SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true" providerName="System.Data.SqlClient" /> </connectionStrings> To work with Microsoft’s SQL Server 2005, you simply create a new connection string within y our ASP.NET application’s web.config file and reference the friendly name provided to this connection from the <add /> element of the <providers> section. Although this SQL Server instance is declared and defined, it is not utilized by any of the rules that you have established. Looking at the previous sections, you can see that within the <rules> section of the health monitoring section of t he web.config , only two rules exist: a rule to write all errors to the event log and another rule to write failure audits to the event log. To add a new rule to write errors (all errors again) to SQL Server, you use the construction shown in Listing 32-8. Listing 32-8: Creating a rule to write events to SQL Server <configuration> <system.web> <healthMonitoring enabled="true"> 1488 Evjen c32.tex V2 - 01/28/2008 4:05pm Page 1489 Chapter 32: Instrumentation <eventMappings> <! Code removed for clarity > </eventMappings> <providers> <! Code removed for clarity > </providers> <rules> <clear /> <add name="All Errors Default" eventName="All Errors" provider="EventLogProvider" profile="Default" minInstances="1" maxLimit="Infinite" minInterval="00:01:00" custom="" /> <add name="Failure Audits Default" eventName="Failure Audits" provider="EventLogProvider" profile="Default" minInstances="1" maxLimit="Infinite" minInterval="00:01:00" custom="" /> <add name="All Errors SQL Server" eventName="All Errors" provider="SqlWebEventProvider" profile="Default" minInstances="1" maxLimit="Infinite" minInterval="00:01:00" custom="" /> </rules> </healthMonitoring> </system.web> </configuration> To be able to write to SQL Server, you must create a new <add /> element within the <rules> section of the document. The friendly name provided via the name attribute must be unique in the list of defined rules or you encounter an error. In this case, the name of the rule is All Errors SQL Server and like the All Errors Default rule, it points to the event mapping of All Errors as shown via the event- Name attribute. The provider attribute then points to the SQL Server definition contained within the <providers> section. In this case, it is SqlWebEventProvider . With all this in place, run the ASP.NET pa ge (shown earlier) that allows you to throw an error by dividing by zero. If you run this page a couple of times, you see that ASP.NET has automatically created an ASPNETDB.MDF file in your project (if you didn’t already have one). You can then open the SQL Server Express Edition database and expand the Tables node in the Server Explorer of Visual Studio. In this list of available tables, you find a new table called aspnet_WebEvent_ Events . Right-click this table and select Show Table Data from the menu. This gives you something similar to what is illustrated in Figure 32-13. As you can see from this figure, the entire event is now stored within SQL Server (it is the first and only event at the moment). One of the nice things about this example is that not only is this event recorded to the database, but it is also written to the event log because you can use more than a single provider for each event. You can just as easily use a provider that comes from MailWebEventProvider andsendthe error out as an e-mail message. 1489 Evjen c32.tex V2 - 01/28/2008 4:05pm Page 1490 Chapter 32: Instrumentation Figure 32-13 Buffering Web Events When you start working with Web events that you want to write to a database (such as SQL Server) or sent via an e-mail, you soon realize that doing so can really lock up your database or result in a huge amount of e-mail (especially if your application is sent into some perpetual loop of errors). For this reason, you can see why these providers inherit from BufferedWebEventProvider . BufferedWebEventProvider does exactly what it says — it buffers (or queues) your collected Web events before performing the specified action upon them. The reason you might want to buffer is to eliminate the possibility of your database being pounded or your e-mail box being flooded. Definitions of how the buffering should occur are located in the <bufferModes> section within the <healthMonitoring> section of the web.config file. An example of the <bufferModes> section is pre- sented in Listing 32-9. Listing 32-9: Using the <bufferModes> section <configuration> <system.web> <healthMonitoring enabled="true"> 1490 Evjen c32.tex V2 - 01/28/2008 4:05pm Page 1491 Chapter 32: Instrumentation <bufferModes> <clear /> <add name="Critical Notification" maxBufferSize="100" maxFlushSize="20" urgentFlushThreshold="1" regularFlushInterval="Infinite" urgentFlushInterval="00:01:00" maxBufferThreads="1" /> <add name="Notification" maxBufferSize="300" maxFlushSize="20" urgentFlushThreshold="1" regularFlushInterval="Infinite" urgentFlushInterval="00:01:00" maxBufferThreads="1" /> <add name="Analysis" maxBufferSize="1000" maxFlushSize="100" urgentFlushThreshold="100" regularFlushInterval="00:05:00" urgentFlushInterval="00:01:00" maxBufferThreads="1" /> <add name="Logging" maxBufferSize="1000" maxFlushSize="200" urgentFlushThreshold="800" regularFlushInterval="00:30:00" urgentFlushInterval="00:05:00" maxBufferThreads="1" /> </bufferModes> <eventMappings> <! Code removed for clarity > </eventMappings> <providers> <! Code removed for clarity > </providers> <rules> <! Code removed for clarity > </rules> <profiles> <! Code removed for clarity > </profiles> </healthMonitoring> </system.web> </configuration> In this code, you can see four buffer modes defined. Each mode has a friendly name defined using the name attribute. For each mode, a number of different attribute can be applied. To examine these attributes, take a closer look at the Logging buffer mode. <add name="Logging" maxBufferSize="1000" maxFlushSize="200" urgentFlushThreshold="800" regularFlushInterval="00:30:00" urgentFlushInterval="00:05:00" maxBufferThreads="1" /> 1491 Evjen c32.tex V2 - 01/28/2008 4:05pm Page 1492 Chapter 32: Instrumentation This buffer mode is called Logging and, based on the values assigned to its attributes, any provider using this buffer mode sends the messages to the database or via e-mail every 30 minutes. This is also referred to as flushing the Web events. The time period of 30 minutes is defined using the regularFlushInterval attribute. Therefore, every 30 minutes, ASP.NET sends 200 messages to the database (or via e-mail). It will not send more than 200 messages at a time because of what is specified in the maxFlushSize attribute. Well, what happens if more than 200 messages are waiting within that 30-minute time period? ASP.NET still sends only 200 messages every 30 minutes and holds additional messages when the number exceeds 200. The maximum number of message held in the queue cannot exceed 1,000 messages. This number is set through the maxBufferSize attribute. However, after the total in the queue hits 800 messages, ASP.NET starts flushing the messages every 5 minutes instead of every 30 minutes. The change in fre- quency of messages is determined by the urgentFlushThreshold attribute, and the time interval used to send messages when the urgentFlushThreshold is hit is determined by the urgentFlushInterval attribute. After you have defined the buffering modes you want to use, the next step is to apply them. To analyze the process, look back on how the SqlWebEventProvider is declared. <providers> <clear /> <add name="EventLogProvider" type="System.Web.Management.EventLogWebEventProvider,System.Web, Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" /> <add name="SqlWebEventProvider" connectionStringName="LocalSqlServer" maxEventDetailsLength="1073741823" buffer="false" bufferMode="Notification" type="System.Web.Management.SqlWebEventProvider,System.Web, Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" /> <add name="WmiWebEventProvider" type="System.Web.Management.WmiWebEventP rovi der,System.Web, Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" /> </providers> Again, this event is shown in bold. First, the most important attribute is the buffer attribute. By default, bufferingofmessagesisturnedoff.Thisisdonebysettingthe buffer attribute to false .The bufferMode attribute allows you to assign one of the defined buffer modes created within the <bufferModes> section. In this case, the Notification buffer mode is referenced. Changing the buffer attribute to true enables the events to be sent only to SQL Server according to the time intervals defined by the Notification buffer mode. E-mailing Web Events When monitoring a server for Web events, you are not always going to be networked into a server or actively monitoring it every second. This doesn’t mean that you won’t want to know immediately if something is going very wrong with your ASP.NET application. For this reason, you will find the Sim- pleMailWebEventProvider and the TemplatedMailWebEventProvider objects quite beneficial. 1492 Evjen c32.tex V2 - 01/28/2008 4:05pm Page 1493 Chapter 32: Instrumentation Using the SimpleMailProvider The SimpleMailWebEventProvider sends Web events as a simple text e-mail, as shown in Figure 32-14. Figure 32-14 To set up this provider, you place an additional <add /> element within the <providers> section, as illustrated in Listing 32-10. Listing 32-10: Adding a SimpleMailWebEventProvider instance <add name="SimpleMailProvider" type="System.Web.Management.SimpleMailWebEventProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" from="website@company.com" to="admin@company.com" cc="adminLevel2@company.com" bcc="director@company.com" bodyHeader="Warning!" bodyFooter="Please investigate ASAP." subjectPrefix="Action required." buffer="false" maxEventLength="4096" maxMessagesPerNotification="1" /> 1493 Evjen c32.tex V2 - 01/28/2008 4:05pm Page 1494 Chapter 32: Instrumentation After the provider is added, you also add a rule that uses this provider in some fashion (as you do with all the other providers). This is done by referencing the SimpleMailWebEventProvider name within the provider attribute of the <add /> element contained in the <rules> section. For this to work, be sure that you set up the SMTP capabilities correctly in your web.config file. An example is presented in Listing 32-11. Listing 32-11: Setting up SMTP in the web.config file <configuration> <system.web> <! Code removed for clarity > </system.web> <system.net> <mailSettings> <smtp deliveryMethod="Network"> <network host="localhost" port="25" defaultCredentials="true" /> </smtp> </mailSettings> </system.net> </configuration> If you do not have a quick way of setting up SMTP and still want to test this, you can also have ASP.NET create e-mail messages and store them to disk by setting up the <smtp> section as illustrated in Listing 32-12. Listing 32-12: Another option for setting up the SMTP section <configuration> <system.web> <! Code removed for clarity > </system.web> <system.net> <mailSettings> <smtp deliveryMethod="SpecifiedPickupDirectory"> <specifiedPickupDirectory pickupDirectoryLocation ="C: \ "/> </smtp> </mailSettings> </system.net> </configuration> In this scenario, the e-mails will be just placed within the C: \ root directory. 1494 . minInstances="1" maxLimit="Infinite" minInterval="00:01:00" custom="" /> Continued 14 85 Evjen c32.tex V2 - 01/28/2008 4:05pm Page 1486 Chapter 32 : Instrumentation <add. example ASP. NET page is presented in Figure 32 -11. Figure 32 -11 1486 Evjen c32.tex V2 - 01/28/2008 4:05pm Page 1487 Chapter 32 : Instrumentation As you can see from this page, you can enter a single. specified in the maxFlushSize attribute. Well, what happens if more than 200 messages are waiting within that 30 -minute time period? ASP. NET still sends only 200 messages every 30 minutes and holds