Reporting Events

[Previous] [Next]

Before we submerse ourselves in event reporting, we'll get our feet wet with some discussion about what events your software should report to the event log. Then we'll take the plunge into learning how to write software that reports events.

What Events Should Be Reported?

If you are developing a server application, you will likely want to do some event reporting. Before you do, however, you must really understand the intended use of the event log. Remember that the event log is the system administrator's source of feedback from your service. A service that reports nonsensical events or too many events will be as aggravating to the system administrator as an application that displays too many message boxes to a user.

Most developers find it easy to decide which situations warrant the logging of an error event. And likewise, it is reasonably easy to decide when your software needs to issue a warning event. However, you enter into a gray area with information events. What software activity is significant enough to be worthy of logging an information event? You can usually answer this question if you consider it from the system administrator's point of view.

No administrator wants to wade through hundreds or even dozens of information events at the end of the day, just to find the one or two items that are relevant to her job. So one aspect of the "significance" question you should consider is how common a particular situation is. A Web server most likely won't want to log an event for every connection it receives. It might, on the other hand, want to report an event for every connection that was denied because it was too busy to process the request. But even logging this event might be unnecessary. A compromise might be to log an event once per hour if connections were denied. The log could include in the detailed description the total number of connections denied. One possibility is to make this kind of reporting optional so that the administrator can pick and choose what is reported.

Another use of information events would be to report infrequent changes in the state of your software. For example, you might want to generate an event each time your service is paused or continued. Or suppose your software goes into a standby mode, freeing up certain resources when connection load has been low for a certain period of time—such an occurrence might warrant an information event. State-change information events can be useful because they give the administrator a sense of what activities your software performed before a warning or error event occurred.

However, you need to avoid getting into the habit of thinking about the event log as a repository of trace information for your application. This type of debugging information will overwhelm an administrator and most likely cause her to ignore every event your application makes. Each event takes up disk space on your system as well, so efficient use of storage is also a concern. If your server will be reporting many events, or will be reporting events from multiple event sources, you might want to consider logging your events to a custom log. Ultimately common sense has to rule here; however, you can offer your user the best of all worlds by making the reporting mechanism of your application as user-configurable as possible.

Well, that is enough on what events should be reported. Now let's jump into the how.

How to Report Events

Reporting software events is a simple process, but you need to understand how the puzzle is put together before you can really take advantage of event logging. The easiest way to fit the pieces together is to look at the simplest piece first, which is the reporting process.

If your process wants to begin reporting events to the event log, it needs to register an event source using the following function:

 HANDLE RegisterEventSource(    PCTSTR pszMachineName,    PCTSTR pszSourceName); 

The pszMachineName parameter identifies the system that contains the log files that you want to append event entries to. Passing NULL for this parameter opens the log file on the local machine. Very rarely are events reported to a remote machine's log files.

The pszSourceName parameter is the name of the event source. This name is the text that is shown in the source column in the Event Viewer snap-in; it is not necessarily the name of your executable program (but it usually is).

NOTE
I need to offer a word about security: the Security and System logs are secured. To have your application append events to either of these log files, your process must be running under a privileged security context when it calls RegisterEventSource. Here are the rules: the Security log can be written to only by the LocalSystem account, and the System log can be written to only by the LocalSystem and Administrator accounts.

If RegisterEventSource is successful, it returns a valid handle. Your application now uses this handle to report events. Remember that like all handles, when you are finished with it you should let the system know. You do this with a call to the DeregisterEventSource function:

 BOOL DeregisterEventSource(HANDLE hEventLog); 

So far so good, right? Well, reporting an event is also fairly trivial. You do it with a call to the following function:

 BOOL ReportEvent(    HANDLE  hEventLog,    WORD    wType,    WORD    wCategory,    DWORD   dwEventID,    PSID    psidUser,    WORD    wNumStrings,    DWORD   dwDataSize,    PCTSTR* ppszStrings,    PVOID   pvRawData); 

The hEventLog parameter is the handle returned by RegisterEventSource. The wType parameter is one of the five predefined event types in Table 6-3. The wCategory and dwEventID parameters are values chosen arbitrarily by you. The dwEventID parameter will uniquely identify the event for your source. Event IDs can be any arbitrary value and arranged in any order you like. However, the category of an event, which indicates a source-defined grouping of events, must have values that start with 1 and progress from there. The value 0 is reserved to indicate no category. The psidUser parameter identifies a user; it does not imply security restrictions on the event. Frequently, NULL is passed to indicate an event not related to any user.

The ppszStrings parameter points to an array of text strings to associate with the event, where wNumStrings is the number of strings in the array. (I will discuss the ppszStrings parameter later in the section "Building Message DLLs and EXEs.") Finally, the pvRawData parameter points to a block of binary data to associate with the event. The dwDataSize parameter indicates the size of the data block, in bytes. The data is defined by the reporting application, and can be any data that you feel will be useful to the user or administrator. For example, network drivers place raw packet data in certain events reported by the driver.

According to the documentation, the functions just described are all you need to know to log events to the event log. Technically this is the truth; however, some key points are left out. If you compare the information that we are giving the Event Log service using ReportEvent with the information that the Event Viewer snap-in displays for a typical event, you will find that some data is missing. Specifically, we pass a category number, whereas the Event Viewer snap-in displays a text string. Also, neither RegisterEventSource nor ReportEvent indicate which log we wish to report under (that is, Application, System, or Security). And finally, you might have noticed that ReportEvent lacks a parameter for the detailed description of the event.

By default the approach I explained places your event in the Application log. The log includes generic text for the detailed description of your event and then appends your string data to the end of the text. We could stop here, but your users will thank you if you go the extra mile and implement your own detailed descriptions and categories. To do this, it helps to understand the design goals of event logging.

Message Files

The designers of the Windows event log wanted to create an efficient mechanism that promoted language independence. As a result of this goal, the portions of an event that are human-readable—that is, the category and the detailed description—are abstracted from your application into separate message files. These message files are implemented as DLLs or EXEs, and they contain a custom binary resource containing the text for your messages. I will explain the details surrounding the message DLL later in this chapter; however, at this time there are a couple of things you should know.

Three types of message files can be associated with a given event source: event message files, category message files, and parameter message files. A single message DLL (or EXE) can represent any combination of these, so your application can store your event message file, category message file, or parameter message file in one message DLL. The converse is also true. For example, it is possible to use more than one message DLL to represent the event message file for a single event source.

NOTE
The DLL and EXE files are generally referred to as message DLLs and message EXEs, respectively. For ease of reading, I'll primarily use "message DLL" in the remainder of this chapter, but all the information applies equally to a message EXE.

You associate your message DLL with your event source by creating a handful of registry values under a subkey with the same name as the pszSourceName parameter that you passed to RegisterEventSource. The event log kills two birds with one stone with this new registry key by also using it to designate into which log your source's events will be logged. Typically the software that installs your application adds these entries to the registry, but no rule says that your service can't add them. When the entries are added to the registry, the layout of the registry ends up following this hierarchy:

 HKEY_LOCAL_MACHINE    SYSTEM       CurrentControlSet          Services             EventLog                Application                   Event Source                      ...                Security                   Event Source                      ...                System                   Event Source                      ...                CustomLog                      ... 

Notice that the CustomLog key is under the EventLog key. By default, the only keys under EventLog are Application, Security, and System, but your code can add another key as a peer to the standard log keys to introduce a custom log to the event log. When you call RegisterEventSource, the system searches the keys under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\ Services\EventLog\Log for a key that matches the pszSourceName parameter. Each log is searched in alphabetic order until a matching source subkey is found. So as you can see, the namespace for event sources is shared for all logs, standard or custom. If an event source under System matches an event source under Application, it will be ignored.

To associate your message files with your event source, you create the appropriate registry values under your event source key. The supported registry values are described in Table 6-4.

Table 6-4. Supported registry values for event source subkeys

Registry Value Type Description
TypesSupported REG_DWORD Identifies a set of flags, shown in Table 6-3, indicating the types of events supported by the message DLL.
EventMessageFile REG_EXPAND_SZ Identifies the pathnames (separated by semicolons) to the event message files. The Event Viewer searches this set of files when trying to convert an event ID to a human-readable string.
CategoryMessageFile REG_EXPAND_SZ Identifies the pathnames (separated by semicolons) to category message files. The Event Viewer searches this set of files when trying to convert a category ID to a human-readable string.
ParameterMessageFile REG_EXPAND_SZ Identifies the pathnames (separated by semicolons) to parameter message files. The Event Viewer searches this set of files when trying to convert a replaceable string parameter ID to a human-readable string.
CategoryCount REG_DWORD Indicates the number of categories supported by the event source.

Notice that all the message file values in Table 6-4 are of the REG_EXPAND_SZ data type. This means that the pathname can include system environment variables that will be expanded at run time. The following example pathname set is a legal value for any of the message file registry values:

 "%SystemRoot%\System32\msg.dll;c:\messages\msg2.dll"  

NOTE
Listing the path to a message file in UNC (Universal Naming Convention) format (even if it is on the local machine) is often preferable to using a drive letter and path, because your users might be viewing your logged events from a remote machine. When an event viewing utility (such as the Event Viewer snap-in) looks up the path of a message file DLL and finds it on a network share, the Event Viewer will be able to load the DLL and read the messages. If the Event Viewer snap-in cannot locate the specified message DLL, it cannot convert IDs to human-readable strings. Here is an example of what the Event Viewer snap-in shows when IDs are not converted to strings:

Notice that the Event ID and Category fields are displayed as numbers instead of strings. Also notice that the Description field displays the best information it can under the circumstances.

By the way, containing all the event, category, and parameter messages in a single EXE or DLL file is common. When this is this case, the three message-file registry values are set identically.

Each individual log, such as Application or a custom log, is maintained in its own log file with the extension .evt. Normally the event viewer grabs the registry subkey name, appends the .evt extension, and attempts to open a log file with the resulting filename. However, you can override this behavior and specify a custom pathname for the log file by adding a File registry value under the Log name key. Changing the pathname this way requires rebooting the system for the changes to take affect. Note that the previous log information for a changed log file will not display in the new log.

Two more registry values that affect a log are worth mentioning. The first is MaxSize, which is of type REG_DWORD. This value is the maximum size, in bytes, that the system will allow the log file to grow to. The second value is Retention, which is also a REG_DWORD. This value specifies how old an event should be, in seconds, before it is automatically deleted from the log file. Your code is free to modify these values. If the MaxSize and Retention values do not exist in the registry for a given log, the system defaults to a maximum log file size of 512 KB and a 7-day retention time.

You will unlikely change these values manually in the registry. Rather, you will probably change them using the Event Viewer snap-in by selecting a log and displaying its properties dialog box. Figure 6-2 shows the properties dialog box for a log.

Figure 6-2. The properties dialog box for the Application log

Now that we have discussed logging events and associating message DLLs with your event source, it is time to tie the two topics together with a detailed discussion of the message files.



Programming Server-Side Applications for Microsoft Windows 2000
Programming Server-Side Applications for Microsoft Windows 2000 (Microsoft Programming)
ISBN: 0735607532
EAN: 2147483647
Year: 2000
Pages: 126

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net