Click here to Skip to main content
Email Password   helpLost your password?

Note: You will need to follow the steps in Setting Up Your Development Environment before the project will build.

Contents

Introduction

Note: This article is a major re-working of my earlier Getting started with the Logging Application Block article. Whereas that article used Microsoft's Enterprise Instrumentation Framework and the stand-alone Logging Application Block, this article deals with the Logging and Instrumentation Application Block supplied as part of the Enterprise Library.

Have 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 Logging and Instrumentation Application Block (a part of the Microsoft / Avanade Enterprise Library) and show how it could bring some consistency to an application�s logging.

This article is for those who have never encountered the Logging and Instrumentation 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 and Instrumentation 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 new Logging Application and Instrumentation Block provides over the Microsoft Enterprise Instrumentation Framework (EIF) and the original stand-alone Logging Application Block. Nor will it explore the other application blocks provided with the Enterprise Library.

Background

Many 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. In April 2003, Microsoft released the EIF. As part of Microsoft�s Patterns & Practices initiative, the EIF was extended by the original, stand-alone, Logging Application Block.

In January 2005, a new set of application blocks were released together as the Enterprise Library. This library combines many of the preceding stand-alone application blocks (and some new ones) providing a consistent, integrated suite of �best practice� software. The Logging and Instrumentation Application Block is part of that library.

The Logging and Instrumentation Application Block provides a simple way for your code to log information in a consistent manner across your managed application. Powerful configuration files allow the filtering, routing and formatting of those �Log Entries� to be determined at run time (rather than at compile time). Log Entries can be generated as discrete events or as part of a traced process.

Some of the major improvements over the original stand-alone Logging Application Block are:

When I first looked at the original Logging Application Block, I nearly dismissed it as too much effort. I�m glad I persisted. Due to its automated setup and simplified configuration, the Logging and Instrumentation Application Block is far simpler to start working with and use in a real life project.

The Basics

The Logging and Instrumentation Application Block makes use of four basic concepts to provide a logging framework: Log Entries, Tracers, Sinks and Formatters.

Log Entries

A LogEntry is the object that you �write� when your application needs to log some information. For instance, adding the following to your application would write a Log Entry containing the message �Hello World�:

   Logger.Write("Hello World");

It is as simple as that. OK, you do have to put in some using statements and your project must reference the Enterprise Library... but the code can be as basic as that!

The above code implicitly creates a LogEntry object with its Message field set to �Hello World�. Overrides of the Logger.Write method allow you to provide more information, such as:

Another overload takes a LogEntry object, allowing you to set all these fields explicitly. A LogEntry also has a number of additional fields that are automatically populated with details of the system's state at the time it was instantiated (e.g., machine name, timestamp, application domain name, process ID etc.).

Additional, context specific information can be added to a LogEntry through its ExtendedProperties field. This takes a reference to an IDictionary object containing any additional name / value pairs you want to log. Included with the Logging and Instrumentation Application Block are a number of �Extra Information Providers�. These can be used to populate an IDictionary object with some basic information. For example, the ComPlusInformationProvider will populate an IDictionary object with details of the current COM+ context.

Tracers

Whereas a LogEntry allows you to log a discrete event, a Tracer object can be used to indicate that a LogEntry is being written as part of a particular process (or execution path through the application). For instance, you might use it to indicate that a LogEntry has been written as part of a �Create New Customer� process:

   using (new Tracer("Create New Customer"))
   {
      Logger.Write("Hello World again");
   }

When a Tracer is instantiated, you can either supply an activityId (as the second parameter to the constructor) or allow a GUID to be generated for you. A �Start Trace� Log Entry will then be written containing this Activity ID. When the Tracer object is disposed of, an �End Trace� Log Entry containing the elapsed time is written. The using statement in the above code ensures the Tracer object is disposed of correctly.

All Log Entries written between the using statement�s opening and closing brackets will automatically have a TracerActivityId entry added to their ExtendedProperties (populated with the Tracer object's Activity ID). This includes Log Entries written from other methods, classes, or even assemblies.

Tracer objects can be nested. Unless explicitly supplied with an activityId, an inner Tracer object will have the same Activity ID as its parent. Any Log Entries will be written with their TracerActivityId extended property set to the inner most Tracer object's Activity ID. In the following code, the first LogEntry is written with a TracerActivityId set to �Outer�, the second with the value set to �Inner�:

   using (new Tracer("Outer most trace", "Outer"))
   {
      using (new Tracer("A nested trace"))
      {
         Logger.Write("Hello World inside");
      }
      
      using (new Tracer("Another nested trace", "Inner"))
      {
         Logger.Write("Hello World inside again");
      }
   }

A number of static methods on the Tracer class allow you to discover information about the current and outermost (or �Root�) Tracer objects.

Log Sinks

When a LogEntry is �written�, the Logging and Instrumentation Application Block routes it to one or more Log Sinks. A Log Sink receives Log Entries and is responsible for persisting them. The Logging and Instrumentation Application Block provides six Log Sinks:

You can always write your own Custom Log Sink as well.

Formatters

To persist a LogEntry, the Log Sink uses a Formatter to convert the Log Entry's information into a string. The Logging and Instrumentation Application Block provides a single formatter, the TextFormatter.

The TextFormatter is initialised with a template that dictates which properties of the LogEntry are added to the output string. For instance, a template like this:

   The message {message} was logged at {timestamp}

would result in an entry in the Log Sink such as:

   The message Hello World was logged at 08/02/2005 18:08:56

This templated approach means Log Entries can be made user friendly and allows sensitive information to be hidden. The template is read from the configuration files, so can easily be changed.

Linking the Basics Together

Hopefully, the section above gives you an insight into the features provided by the Logging and Instrumentation Application Block. What that section doesn�t describe is how LogEntry, Tracer, LogSink and Formatter objects are made to interact with each other. That �plumbing� is provided by the Logging and Instrumentation Application Block based on settings in your configuration files.

There are two more concepts to understand: Categories and Destinations. These are not defined at compile time, but at run time, when the Logging and Instrumentation Application Block reads the configuration files. Therefore, if you need to change how a LogEntry is distributed, you can simply change a configuration file. It is this flexibility that makes the Logging and Instrumentation Application Block so powerful.

Categories

Log Entries can be grouped together into Categories. Each Category can be independently configured to route and format Log Entries in a particular way. Categories can also be used to filter Log Entries, allowing certain Categories to be ignored.

A LogEntry is assigned to a particular Category by either providing the Category name to the Logger.Write method or by explicitly setting its Category property:

   Logger.Write("Hello World once more", "My Category");

   LogEntry logEntry = new LogEntry();
   logEntry.Category = "My Other Category";
   logEntry.Message  = "Hello World once more again";
   Logger.Write(logEntry);

When a Tracer object is constructed, it writes a �Start Trace� LogEntry. When it is disposed of, it writes an �End Trace� LogEntry. The easiest way to assign these Log Entries to a Category is via the Tracer's constructor:

   using (new Tracer("My Trace Category"))
   {
      Logger.Write("Hello World another time");
   }

If a LogEntry is not explicitly assigned to a Category, or the configuration files don't contain a definition for its Category, it is assigned to the �Default Category�. The name of the Default Category is set in the configuration files.

Destinations

A Destination is used to determine to which Log Sink a LogEntry is routed. It also configures the Formatter that the Log Sink will use to transform the information held in the LogEntry.

Like Categories, Destinations are defined in your application's configuration files. For each Category, you can specify zero or more Destinations. This means all the Log Entries in a particular Category can be sent to no Log Sinks, one Log Sink or simultaneously to several Log Sinks.

Setting Up Your Development Environment

First off, your system must at least meet the following requirements:

Here are the steps I followed to create a development environment:

All in all, this is a far simpler setup than the previous, stand-alone, Logging Application Block!

Instrumenting an Application

Perhaps the best way to get to grips with the Logging and Instrumentation 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 may need to delete and re-add its reference to the various Microsoft.Practices.EnterpriseLibrary assemblies.

Writing Log Entries

The LoggingBlockInvestigator.exe application writes two Log Entries in the Main method, one on start up and one on shutdown:

LogEntry logEntry    = new LogEntry();
logEntry.Message    = "Starting up the application";
Logger.Write(logEntry);

Application.Run(new MainForm());

Logger.Write("Shutting down the application");

This code shows two techniques for writing Log Entries with the Default Category. The first technique explicitly creates a LogEntry object and initializes it with a message. The second, more compact technique creates the LogEntry 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 a list of each of the Log Entries' properties.

Specifying a Category

By default, all Log Entries are marked with the Default Category. For instance, the Windows Event Log details for the two Log Entries created above indicate their Category is �General.� The code in the sample application for the �Log From My Category� button handler uses an explicit Category instead:

private void LogFromMyCategory_Click(object sender, System.EventArgs e)
{
   Logger.Write("Written using My Category", "My Category");
}

Run the sample application and press the �Log From My Category� button, then look in the Windows Event Log. Under the System Log, you will find an entry with a source of "Logging Investigator". Looking at the details will show that the Category is set to "My Category". This Category has a second Destination configured which specifies that Log Entries are also written to a flat file C:\Trace.Log. If you open that file, you will find it contains the same Log Entry except formatted differently, as the second Destination is set to use a different Formatter.

The code above uses a LogEntry. The code behind the �Log With Tracer� button uses two nested Tracer objects:

private void LogWithTracer_Click(object sender, System.EventArgs e)
{
   using (new Tracer("My Trace Category", "My Outer Trace"))
   {
      Logger.Write("My first entry");

      using (new Tracer("My Trace Category", "My Nested Trace"))
      {
         Logger.Write("My second entry [Root = " + Tracer.RootActivityId + "]");
      }
   }
}

If you press the �Log With Tracer� button, the following Log Entries are saved into the Application area of the Windows Event Log:

Specifying a Priority

When a LogEntry is written, it can be given a priority. If not specified, this defaults to the currently configured Minimum Priority. In the case of the �Start Trace� and �End Trace� Log Entries created by a Tracer, the priority is hard coded to 5.

If you press the Log At Priority 10 button, the following code is executed:

private void LogAtPriority10_Click(object sender, System.EventArgs e)
{
   Logger.Write("Written at priority 2",  "General", 2);
   Logger.Write("Written at priority 10", "General", 10);
}

This code actually tries to write two Log Entries. However, if you look in the Windows Event Log, you will find the first one has been filtered out. This is because the configuration files for the LoggingBlockInvestigator.exe application set a Minimum Priority of 5.

Creating a Custom Log Sink

As well as using the provided Log Sinks, you can create your own. For instance, you may wish to send Log Entries by SMS or some proprietary protocol. CustomLogSink.cs in the sample application shows how simple this is. The class is derived from Microsoft.Practices.EnterpriseLibrary.Logging.Sinks.LogSink and overrides the Initialize and SendMessageCore methods. As well as writing a Log Event, the example shows how to read the configuration information for the Log Sink. If you put a break point in the SendMessageCore method, then press the �Log To My Sink� button, your break point should be hit.

Note: The help supplied with the Enterprise library contains a �Walkthrough: Creating a Custom Sink� section. As of 9 February 2005, this is incorrect.

Adding Context Specific Information

You can add additional information to a LogEntry and have it persisted to a Log Sink. The example shows how to add information directly and how to use one of the IExtraInformationProvider objects:

private void LogWithContextInformation_Click(object sender, System.EventArgs e)
{
   IDictionary contextInfo = new Hashtable();

   contextInfo.Add("Additional Info", "Some information I wanted logged");

   DebugInformationProvider provider = new DebugInformationProvider();
   provider.PopulateDictionary(contextInfo);

   LogEntry logEntry           = new LogEntry();
   logEntry.Message            = "Logged with context specific information";
   logEntry.ExtendedProperties = contextInfo;

   Logger.Write(logEntry);
}

If you press the �Log With Context Information� button, a new entry is added to the Windows Event Log. If you look in its details, you will see the Extended Properties contain both the �Additional Info� property and a �Stack Trace� property.

Configuration

The last few sections have introduced the code that you can add to your application to start logging through the Logging and Instrumentation Application Block. There is one more very important task... configuration. Without configuration, your Log Entries will never reach a Log Sink!

One of the major enhancements that comes with the Enterprise Library is the Enterprise Library Configuration Console. This can be found on your Start menu under Program Files > Microsoft patterns & practices > Enterprise Library.

With the console, you can use a fairly user friendly GUI to edit the various configuration files. To open the configuration files for the LoggingBlockInvestigator.exe application:

This should populate the console as below:

In the tree control on the left hand side, you will see all the configuration settings required to get the LoggingBlockInvestigator.exe application working correctly. Here is a quick run down of the highlights (click on each node to see its properties):

Note 1: The console allows you to search for a Custom Log Sink type by loading an assembly. However, it appears that it doesn't use a separate AppDomain to do this, therefore, once your assembly is loaded, it is never unloaded until the console is shut down. This prevents you searching for a type in an assembly, adding a new type to that assembly, and then looking for this new type. Obscure I know, but it caught me out!

Note 2: Once an EventSourceName has been used to write to a particular EventLogName, it cannot be used to write to another without first being removed from the original EventSourceName. If you try, an error is logged.

Adding Logging To Your Application

In order to start using the Logging and Instrumentation Application Block in your own application, there are a few simple steps to follow:

Create the configuration files

In the Enterprise Library Configuration Console, do the following:

Your project directory will now contain two new files: loggingConfiguration.config and loggingDistributorConfiguration.config. These should be put under source control.

Note: Tracing is disabled by default. To enable tracing, highlight Client Settings and change TracingEnabled to true and save.

Set your project to copy the new configuration files

Add the loggingConfiguration.config and loggingDistributorConfiguration.config files to your project. For a Windows application, you can ensure these files are always copied to your project's output directory, by adding the following to its �Post-build Event Command Line� (to do this, edit your project's settings and navigate to Common Properties > Build Events):

copy "$(ProjectDir)loggingConfiguration.config" "$(TargetDir)"
copy "$(ProjectDir)loggingDistributorConfiguration.config" "$(TargetDir)"

Add a reference to the Logging and Instrumentation Application Block

In Visual Studio, highlight your project and select Project > Add Reference. On the .NET tab, use �Browse...� to locate the Microsoft.Practices.EnterpriseLibrary.Logging.dll.

Where to go from Here

By no means have I covered all the features of the Logging and Instrumentation Application Block. So there is plenty more for you to find for yourself. A good place to start is from GotDotNet. By participating in this workspace, you could influence the future direction of the block. You may also find patches, news about future updates, and contributions from other developers... you might even contribute yourself!

Conclusion

Hopefully, this article provides a good introduction to the benefits and features of the Logging and Instrumentation 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 is with Log4Net, NSpring, the EIF, the Logging and Instrumentation Application Block, System.Diagnostics.Trace, or a home grown framework).

Revision History

25 Feb 2005:

28 Sep 2005:

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralReal time log viewer
mijalko
23:22 14 Sep '09  
I made application for looking logs in real time

http://www.mijalko.com/realtimelogviewer[^]

This is working but not final version. I will upgrade it from time to time.
GeneralLog ID
Member 980284
11:50 22 Jul '09  
Has anybody thought about getting LogID of newly generated log entry?
That is, assuming SQL Server database is used, when calling "Logger.Write(logEntry)" new row is added to "Log" table via "WriteLog" stored procedure. The procedure has "@LogID" output parameter
holding row id of the newly added entry. I would like to pass this param to end user as a sort of reference number.
QuestionWhere can I specify the logfile?
Kishore Ramakrishnan
1:56 22 Apr '09  
Where can I specify the log file?
AnswerRe: Where can I specify the logfile?
Magnus Salgo
23:08 29 Apr '09  
A better question please you set the logfile in the Tracelistner...

Magnus Sälgö
Sälgö Consulting AB, Sweden


AnswerRe: Where can I specify the logfile?
Member 6038196
2:24 18 Jun '09  
In application's entlib configuration file in Logging Application Block section(add it if it's missing) change Trace Listeners to (Rolling) Flat File Listener. Update accordingly the reference in Category Sources/General and Special Sources/ Logging Errors & Warnings.
Generalgood article
Donsw
17:51 21 Mar '09  
This is a good article and a good intro to the block,.

cheers,
Donsw
My Recent Article : Organizational Structure within a Company for PMPs

Generallogging errors in diffrent log files for each user ??
vaibhav limaye
21:05 12 Nov '08  
Dear sir,
I want to log the errors as per various users. Each user will have separate log files for errors he get. Is this possible? Please let me know as early as possible.
Waiting for your reply,
Best regards,
Vaibhav
GeneralLogging and Instrumentation Block
trbadami
19:08 2 Sep '08  
Hi,

I can't find that category in May 2007 Enterprise Library Configuration.
It has 2 different categories i.e Logging Application Block and
Instrumentation. Please let me know if I need to install something to see
that category?
GeneralThanks
MarcSchluper
11:09 20 Aug '08  
Thank you for writing this down. It's hard to find proper documentation, while the first version of the application blocks is still used.

Marc Schluper
Beaverton, OR

GeneralWriting to a std.out console?
SteveC-A9
17:31 14 Apr '08  
I got pretty used to using log4j on Linux, being able to write to a console window for real time trace/debug watching. How could that be implemented with the Enterprise Library? Uisng a WMI listener?
GeneralRe: Writing to a std.out console?
Haggis77
9:32 20 Mar '09  
Get Log4net Smile
GeneralRe: Writing to a std.out console?
Kenrae
22:54 24 Aug '09  
I was going to ask the same. Is it possible? I'm already using the Enterprise Library for logging, I don't want to add another library just for this.
AnswerRe: Writing to a std.out console?
Kenrae
0:39 25 Aug '09  
I can reply myself. I've created a custom trace listener (http://msdn.microsoft.com/en-us/library/cc511727.aspx[^]) that calls "AllocConsole" on its static constructor and you just make calls to Console.Write and Console.WriteLine on the Write and WriteLine overrides.
GeneralArticle rewrite with EntLib 3.0?
Fresh Mexican Food Fan
10:15 16 Aug '07  
Do you have plans to update or rewrite this article with respect to the newest version of Enterprise Library? Thanks.
Generalusing Database sink of Enterprise Library
rohans84
5:21 13 Nov '06  
I am searching the internet for finding how to use the database sink. I mean where do i enter parameter names of the stored proc. Plz provide answer to this asap
QuestionExtended Properties display in the email sent by the Email Sink
atomicx6637
9:49 6 Oct '06  
I was wondering if there is a way to get the Text Formatter to include the Extended Properties of the message in the email that is sent out.

Please let me know if you have any suggestions.

Thanks
Troy
GeneralCan't find Microsoft.Practices.EnterpriseLibrary.Logging
CodeSk8Sleep
7:17 23 Jul '06  
Can someone please tell me where the installer puts this file.

Thanks


GeneralEnterprise Library has poor performance
w3Nima
1:36 11 Apr '06  
Microsoft Enterprise Library Logging Block and Log4net comparison

http://weblogs.asp.net/lorenh/archive/2005/02/18/376191.aspx[^]
GeneralVery Good Article
Ricardo Casquete
3:43 22 Feb '06  
Hi I think the Article is just Great...

Ricardo Casquete
Generalevery day a new log file
Alesan
10:18 8 Dec '05  
Is it posible to configurate that every day a new log file is created?
If not, is it posible to archive this with some oveeride methods?
Thanks.

-- modified at 22:31 Thursday 8th December, 2005
AnswerRe: every day a new log file
versat1474
11:26 18 Apr '06  
Sorry nobody gave an answer. I'm not sure how in the ent lib. But you can do this in xqs-logging. You just set the file path to include a parameter...

This example creates a new file every hour...
FilePath="~\log\{Timestamp:yyyyMMdd-HH}-log.txt"

This example creates a new file every day...FilePath="~\log\{Timestamp:yyyyMMdd}-log.txt"

The Timestamp can include any valid datetime format understandable by the DateTime.Format(date, format) method. It uses a regular expression with a capture to get the format and replace the timestamp parameter with a value. So anything between the {Timestamp: and the ending } is the format.

Details and an example of configuration here:
http://www.xquisoft.com/xqsdn/documentation/xquisoft.logging.logconfigurationhandler.html[^]

with full help index:
http://www.xquisoft.com/xqsdn/documentation/index.html[^]

You can download here:
http://sourceforge.net/projects/xqs-logging[^]

Michael Lang

-- modified at 16:28 Tuesday 18th April, 2006
NewsRe: every day a new log file
versat1474
5:07 20 Apr '06  
I finally posted an article with all the details.

XQuiSoft Logging Introduction
http://www.codeproject.com/useritems/XQuiSoftLoggingIntro.asp[^]
GeneralRe: every day a new log file
Esam Salah
6:00 11 Jul '07  
I think that you can use the [Rolling Flat File Trace Listener] it is a new feature in EntLib 3.1

Essam Salah
Senior Software Engineer
ITWorx

Generalmultiple sinks
JVMFX
8:38 1 Nov '05  
when you specify multiple sinks, does it log to all of them or use them in order?

For example, if you wanted to have a database sink as the primary log and then an event log sink for when the database sink fails, then perhaps even 1 more layer of fallback.

Would also be nice to have more fined-tuned configuration capability over what happens when an exception is generated while trying to log an exception.
AnswerRe: multiple sinks
jobelink
6:47 15 Nov '05  
I suggest to use the "Enterprice Library Configuration Utility".

You can specify multiple categories. These categories are used in the Logger command:

Logger.Write("Message", "Category")

When you don't specify a category the "General" category is used as default.

Per category you can define multiple "Destinations" (uses of skins) by right clicking on a "Category" and add a new "Destination". All the defined Destinations are handled when it is called through the "Logger" function.

Per example:
I want error logs written in the Application Event Log and I want en e-mail send to my address. I defined a category "Error" with two Destinations: Email (from E-mail skin) and AppLog (From Application Log Skin.

I hope this is the information you wanted.


Last Updated 5 Oct 2005 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010