|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
Note: You will need to follow the steps in Setting Up Your Environment before the project will build. I have completed a major re-write of this article using the Enterprise Library rather than the EIF and the stand-alone Logging Application Block. This is available at Get Logging with the Enterprise Library. Contents
IntroductionHave you ever encountered a system where the logging is a twisted pile of spaghetti? One where it seems to save trace messages to five different files? Or it requires seven different flags in the registry to control its output? All too often, logging is added to a system in an ad-hoc, as the need arises, manner. When this approach is applied to a large system with many sub-systems and layers, it can lead to numerous “home grown” logging mechanisms being implemented; each implementation having its own configuration peculiarities and probably logging in different ways (e.g., one subsystem to the Windows Event Log, one to a file in the root directory, one to a database etc.). This article will introduce you to the Microsoft Logging Application Block, and show how it could bring some consistency to an application’s logging. This article is for those who have never encountered the Logging Application Block, those who are looking to evaluate it, and those who have looked at it and thought it seemed like too much trouble. I will provide an overview of what features the Logging Application Block provides, followed by a description of how to get the basics working in your environment. The article will not explore too deeply the additional features the Logging Application Block provides over the Microsoft Enterprise Instrumentation Framework (EIF). BackgroundMany applications, and especially large-scale systems, could benefit from a consistent approach to logging. To help, there are a number of logging libraries available to the .NET developer, such as Log4Net and NSpring. As of April 2003, there has been another alternative, the Microsoft Enterprise Instrumentation Framework (EIF). The EIF provides a simple way for your code to raise “Events” in a consistent manner across your managed application. A powerful configuration file allows the routing of those Events to be determined at run time (rather than at compile time). The routing to one or more “Event Sinks” can be based on a combination of the type of the Event and the source of the Event. The configuration file also allows you to specify that only certain elements of your application, or particular processes within it, produce logging. As part of Microsoft’s Patterns & Practices initiative, the Logging Application Block has been released. This application block extends the EIF with three new Event Sinks:
It also provides new versions of the Windows Event Log and Windows Management Instrumentation (WMI) Event Sinks, adding facilities such as Log Level. Another new feature is Event Transformation, which allows you to change the contents of an Event before it is stored. For instance, transformations could remove sensitive information or add additional data. By integrating with the Web Services Enhancements (WSE), the Logging Application Block allows log tracing to continue across web service boundaries. When I first looked at the Logging Application Block, I nearly dismissed it as too much effort. I’m glad I persisted. The BasicsThe EIF, and hence the Logging Application Block, make use of three basic concepts to provide a logging framework: Events, Event Sources and Event Sinks. EventsAn Event is the object that you “raise” when your application needs to log some information. For instance, adding the following to your application would raise an Event of type TraceMessageEvent.Raise(“Hello World”);
It is as simple as that. OK, you do have to put in some The EIF defines a number of Events, such as:
These all contain a number of “Fields” that are automatically populated with details of the system at the time the Event was raised (e.g., machine name, timestamp, application domain name, etc.). Through the configuration file, it is possible to request that additional Fields be populated. For example, COM+ properties (including Fields such as the current Transaction ID) or security information can be added to the Event’s contents. Each Event type also adds its own specific Fields. For example, the The Logging Application Block includes new versions of some of the EIF Events. These provide new Fields and some new functionality (e.g., Log Level). It also adds some completely new Events such as the Event SourcesAn Event Source allows you to indicate where an Event was raised from. All Events are raised from an Event Source. If the developer doesn’t specify an Event Source explicitly, a default source is used. The code shown above does not explicitly set the source, therefore, the default “Application” source is used. The code below explicitly defines the source of an Event: EventSource theBusinessLayerSource = new EventSource(“Business Layer”);
TraceMessageEvent.Raise(theBusinessLayerSource, “Hello World Again”);
The There is a second type of Event Source, the “Request Event Source”. This type is used to indicate that an Event is being raised as part of a particular process (or execution path through the application). For instance, you might use it to indicate that an Event has been raised as part of a "Create New Customer" process: RequestEventSource createCustomerSource =
new RequestEventSource(“Create New Customer”);
using (RequestTrace request = new RequestTrace(createCustomerSource)
{
TraceMessageEvent.Raise(“Hello World Once More”);
}
The Software Element Event Sources and Request Event Sources can be used together, i.e., the above could be changed to: using (RequestTrace request = new RequestTrace(createCustomerSource)
{
TraceMessageEvent.Raise(theBusinessLayerSource, “Hello World One Last Time”);
}
This would result in an Event tagged with both the “Business Layer” and the “Create New Customer” Event Sources. One warning about the above examples, creating an Event Source can be slow. Therefore, it is recommended that you create each Event Source only once and hold it in a static reference to be reused. The Logging Application Block improves the functionality of the Request Event Source. It allows the Event SinksWhilst Events originate from Event Sources, they terminate at Event Sinks. An Event Sink receives Events and is responsible for persisting them. The EIF provides three Event Sinks:
As mentioned in the Background section of this article, the Logging Application Block modifies the latter two and adds three more Event Sinks. You can always write your own custom Event Sink as well. Viewing the logged events requires a reader for each particular data store. The Event Viewer can be used for the Windows Event Log. A sample C# project, TraceViewer, is provided with the EIF to open Windows Event Trace log files. The WMI events can be seen through a WMI Event Viewer. Linking the Basics TogetherHopefully, the section above gives you an insight into the features provided by the EIF and the Logging Application Block. What that section doesn’t describe is how Event, Event Source and Event Sink objects are made to interact with each other. That “plumbing” is provided by the EIF based on settings in a configuration file. There are three more concepts to understand: Event Categories, Filters and Filter Bindings. These are not defined at compile time, but at run time, when the EIF reads the configuration file. Therefore, if you need a new Event Category, you can simply change a configuration file. It is this flexibility that makes the EIF so powerful. Event CategoriesEvents can be grouped together into Event Categories. By creating categories, you will be able to independently turn logging on or off for particular groups of Events. Often, one category you will create is an “All Events” category. You may want another category containing only audit events, another that contains trace messages, etc. Note that an event can be a member of more than one category. For instance: <eventCategory name="All Events"
description="A category that contains all events.">
<event type="System.Object" />
</eventCategory>
This fragment defines an Event Category called "All Events". It indicates that all Events of type FiltersA Filter determines which Event Categories are routed to which Event Sinks. For instance, you may want to have all trace messages sent to the To implement this, you would first create two Event Categories, one containing the trace events (see “Trace Events” below) and one containing the audit events (see “Audit Events” below). Secondly, you would create a Filter which specified that events from “Trace Events” category should be directed to the <eventCategories>
<eventCategory name="Trace Events">
<event type="Microsoft.ApplicationBlocks.Logging.Schema.TraceMessageEvent,
... " />
</eventCategory>
<eventCategory name="Audit Events">
<event type="Microsoft.ApplicationBlocks.Logging.Schema.AuditMessageEvent,
... " />
</eventCategory>
</eventCategories>
<filters>
<filter name="filterTraceAndAuditDifferently">
<eventCategoryRef name="Trace Events">
<eventSinkRef name="traceSink"/>
</eventCategoryRef>
<eventCategoryRef name="Audit Events">
<eventSinkRef name="traceSink"/>
<eventSinkRef name="logSink"/>
</eventCategoryRef>
</filter>
</filters>
Filter BindingsA Filter Binding links an Event Source to one or more Filters. This allows you to route Events raised by different parts of your system to different Filters. For instance, if you are having a problem with a single process in your system, you could create a single Filter Binding between the Request Event Source that wraps that process and a Filter that directs Events in the “All Events” Event Category to the <eventSources>
<eventSource name="Create New Customer" type="request"/>
</eventSources>
<filters>
<filter name="Trace All">
<eventCategoryRef name="All Events">
<eventSinkRef name="traceSink"/>
</eventCategoryRef>
</filter>
</filters>
<filterBindings>
<eventSourceRef name="Create New Customer">
<filterRef name="Trace All" />
</eventSourceRef>
</filterBindings>
This fragment will ensure that all events raised as part of the "Create New Customer" process are sent to the Setting Up Your EnvironmentFirst off, your system must at least meet the following requirements:
Here are the steps I followed to create a development environment:
Some notes on this:
Instrumenting an ApplicationPerhaps the best way to get to grips with the Logging Application Block is to try it. The download for this article contains the code for a sample Windows Forms application (LoggingBlockInvestigator.exe) that should allow you to experiment. You will need to edit its EnterpriseInstrumentation.config file to replace the Raising EventsThe LoggingBlockInvestigator.exe application raises two audit events in the AuditMessageEvent auditEvent = new AuditMessageEvent();
auditEvent.Message = "Starting the application";
EventSource.Application.Raise(auditEvent);
Application.Run(new MainForm());
AuditMessageEvent.Raise("Shutting down the application");
This code shows two techniques for raising events from the default “Application” Event Source. The first technique explicitly creates an Event object and initializes it with a message. The second, more compact technique, creates the Event implicitly. If you build and run the LoggingBlockInvestigator.exe application, then close it down, you will find two new entries in your Windows Event Log, in the Application section. If you look at the details, you will see an XML document containing the appropriate messages. With the EIF, Microsoft provides a simple trace log viewer. If you run [EIF]\Samples\Trace Viewer\TraceViewer.exe and open the TraceLog.Log file, you should see the two events listed there as well. Creating Event SourcesBy default, all messages are marked as raised by the “Application” Event Source. The code in the sample application for the “Log From My Source” button handler uses an explicit source instead: private static EventSource eventSource = new EventSource("My Source");
private void LogFromMySource_Click(object sender, System.EventArgs e)
{
TraceMessageEvent.Raise(eventSource, "Traced from my source");
}
Run the sample application and press the “Log From My Source” button, then open the TraceLog.Log file in TraceViewer.exe. The last entry should be a trace message. Looking at the details will show that the The code above is using a Software Element Event Source. The code behind the “Log With Request Trace” button uses two nested Request Event Sources: private RequestEventSource requestEventSource1 =
new RequestEventSource("My Request Source For Tracing");
private RequestEventSource requestEventSource2 =
new RequestEventSource("My Nested Request Source For Tracing");
private void LogWithRequestTrace_Click(object sender, System.EventArgs e)
{
using (RequestTrace request = new RequestTrace(requestEventSource1))
{
TraceMessageEvent.Raise(eventSource, "My first request");
using (RequestTrace requestNested = new RequestTrace(requestEventSource2))
{
TraceMessageEvent.Raise("My second request");
}
}
}
If you press the “Log With Request Trace” button, the following Events are saved into the TraceLog.Log file:
Creating a Custom Event SinkAs well as using the provided Event Sinks, you can create your own. CustomEventSink.cs in the sample application shows how simple this is. The class is derived from Log LevelsA new feature introduced by the Logging Application Block is Log Levels. The If you don’t explicitly set the Log Level for an Event, it defaults to AuditMessageEvent auditErrorEvent = new AuditMessageEvent();
auditErrorEvent.Message = "Logged at error level";
auditErrorEvent.EventPublishLogLevel = (int)LogLevel.Error;
EventSource.Application.Raise(auditErrorEvent);
It should be noted that the Logging Application Block has not changed the functionality of the ConfigurationThe last few sections have introduced the code that you can add to your application to start logging through the Logging Application Block. There is one more very important task... configuration. Without configuring the EIF, your Events will never reach an Event Sink. The EnterpriseInstrumentation.config file details how Events, Event Sources and Event Sinks are linked. A skeleton of this file can be generated for you. You must ensure your project references the [RunInstaller(true)]
public class LoggingBlockInvestigatorInstaller : ProjectInstaller {};
Then, from the command line, run: installutil MyApplication.exe
This will generate a functioning EnterpriseInstrumentation.config file, pre-populated with all the Events, Event Sources and Event Sinks that could be found in your application and its referenced assemblies. It will also contain some default Categories, Filters and Filter Bindings. You can then experiment with creating new Categories, Filters and Filter bindings. If you look at the sample application’s EnterpriseInstrumentation.config file, you will see that it makes use of an <eventSource name="My Source With Debug Info" ... >
<eventSourceParameter name="PopulateDebugInfo" value="true" />
</eventSource>
The
Also, in the file, you will see the Custom Event Sink declared as follows: <eventSink name="customEventSink" ... >
<parameter name="MyParam" value="My own parameter" />
</eventSink>
The “ Event Sink parameters can be used for whatever you like. The Event Sinks provided with the EIF and the Logging Application Block use them for such things as:
The FutureWhat about the future? Microsoft in partnership with Avanade have been developing the next evolution of the Patterns & Practices Application Blocks. Enterprise Library is due for general release sometime early in 2005. This library will bring together a number of the existing Application Blocks, including Logging. You can find more information about the new library at GotDotNet. Looking at the documentation currently available, any experience you gain with the current Logging Application Block will make understanding the new library simpler. However, there will not be a simple upgrade path. Some of the new features include:
Update: The Enterprise Library is now available. ConclusionHopefully, this article provides a good introduction to the benefits and features of the Logging Application Block. If implemented consistently throughout a system, it should provide a robust and powerful tool for both debugging and monitoring. The information given in this article should allow you to start incorporating the block into your code. At the very least, I hope the article has highlighted the benefits of thinking about logging early in a project, and choosing a consistent approach (whether that be with Log4Net, NSpring, the Logging Application Block, Finally, you may want to wait for the new Enterprise Library. In which case, the concepts introduced in this article should help you to get up to speed with it quickly. Revision History05 Jan 2005:
10 Feb 2005:
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||