Enterprise Library 2.0 Logging Application Block Part IV - Conclusion
by David Hayden ( Florida .NET Developer and MVP in C# )
The Logging Application Block in Enterprise Library 2.0 ( Download ) is probably as popular as the Data Access Application Block. The Logging Application Block allows one to monitor the health of one's winform and web applications by logging various tracing information to a datastore that can later be massaged and analyzed.
TraceListeners
The heart of the Enterprise Library 2.0 Logging Application Block is its TraceListeners, which are essentially the conduit for which event messages get to their intended destinations. Enterprise Library 2.0 provides the following TraceListeners:
- Database TraceListener
- Email TraceListener
- Flat File TraceListener
- Formatter Event Log TraceListener
- Msmq TraceListener
- System Diagnostics TraceListener
- WMI Trace Listener
The usefulness of each TraceListener is fairly obvious. You would use the Database TraceListener to log trace messages to a database. The Email TraceListener is for sending trace messages via email. And so on.
All of the Enterprise Library 2.0 TraceListeners derive from the base TraceListener Class that is a part of the .NET 2.0 Framework.
Working With The Logging Application Block
Just as with the Data Access Application Block, there are essentially 3 ways to work with it:
- Static Factories
- Instance Provider Factories
- Objects Directly
Static Factories - Facade
The easiest way to work with the Logging Application Block is to use the Logger Facade Class. As an example, one can simply use the Enterprise Library Configuration Tool to add logging configuration data to your app.config or web.config that tells the Logging Application Block to save all events to a single log file using a FlatFile TraceListener as shown below.

You can then log all unhandled ASP.NET web application exceptions in your log file, for example, using the facade class in your Global.asax file:
<%@ Application Language="C#" %>
<%@ Import Namespace="Microsoft.Practices.
EnterpriseLibrary.Logging" %>
<script runat="server">
void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError().GetBaseException();
string message = ex.Message +
"\nSOURCE: " + ex.Source +
"\nFORM: " + Request.Form.ToString() +
"\nQUERYSTRING: " +
Request.QueryString.ToString() +
"\nTARGETSITE: " + ex.TargetSite +
"\nSTACKTRACE: " + ex.StackTrace;
Logger.Write(message);
}
< SPAN>script>
The Logging Application Block uses the information placed in the web.config file to know how to log the message via the Logger.Write(message) statement above.
<configuration>
<configSections>
<section name="loggingConfiguration"
type="Microsoft.Practices.EnterpriseLibrary.
Logging.Configuration.LoggingSettings,
Microsoft.Practices.EnterpriseLibrary.Logging,
Version=2.0.0.0, Culture=neutral,
PublicKeyToken=null" />
< SPAN>configSections>
<loggingConfiguration name="Logging Application Block"
tracingEnabled="true"
defaultCategory="" logWarningsWhenNoCategoriesMatch="true">
<listeners>
<add fileName="trace.log"
header="----------------------------------------"
footer="----------------------------------------"
formatter="Text Formatter"
listenerDataType="Microsoft.Practices.EnterpriseLibrary
.Logging.Configuration.FlatFileTraceListenerData,
Microsoft.Practices.EnterpriseLibrary.Logging,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"
traceOutputOptions="None" type="Microsoft.Practices.
EnterpriseLibrary.Logging.TraceListeners.
FlatFileTraceListener, Microsoft.Practices.
EnterpriseLibrary.Logging,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"
name="FlatFile TraceListener" />
< SPAN>listeners>
<formatters>
<add template="Timestamp: {timestamp}
Message:
{message}
Category: {category}
Priority: {priority}"
type="Microsoft.Practices.EnterpriseLibrary.Logging.
Formatters.TextFormatter,
Microsoft.Practices.EnterpriseLibrary.Logging,
Version=2.0.0.0,
Culture=neutral, PublicKeyToken=null"
name="Text Formatter" />
< SPAN>formatters>
<specialSources>
<allEvents switchValue="All" name="All Events">
<listeners>
<add name="FlatFile TraceListener" />
< SPAN>listeners>
< SPAN>allEvents>
<notProcessed switchValue="All"
name="Unprocessed Category" />
<errors switchValue="All"
name="Logging Errors & Warnings" />
< SPAN>specialSources>
< SPAN>loggingConfiguration>
< SPAN>configuration>
Instance Provider Factories
The Logging Application Block contains a class called a LogWriter. This is the class that is responsible for making sure your event messages get to their intended destinations. The facade class above makes sure that the proper LogWriter Class is created for you. However, if you want a bit more flexibility in terms of how the LogWriter Class gets created, you can do something like below:
IConfigurationSource source = new SystemConfigurationSource();
LogWriterFactory factory = new LogWriterFactory(source);
LogWriter logWriter = factory.Create();
logWriter.Write("Log This Message.");
The code above essentially says we want to use the app.config or web.config as the source of our configuration information and we want to create an instance of LogWriter using that information. For more information on understanding IConfigurationSource, see Enterprise Library 2.0 IConfigurationSource.
Objects Directly
To bypass all that configuration mumbo jumbo you can work with the objects in the Logging Application Block directly. First, however, you need to understand the players a bit more.
- LogFormatter - typically a TextFormatter or BinaryFormatter. The role of formatters in the Logging Application Block is to specify the way you want your log messages to look in the intended datastore ( file, database, email, etc. ). Most of the time you will use the TextFormatter, which has a Template Property that specifies the “template“ of the message. Inside this template you can have a number of tokens ( e.g. {timestamp} ) that the Logging Application Block will fill for you.
- TraceListener - TraceListeners provide the logging services. They are the conduit for which messages make it to their intended destinations ( database, email, flat file, event log ). The Logging Application Block comes with several trace listeners such as: Database TraceListener, Email TraceListener, Flat File TraceListener, Formatter Event Log TraceListener , etc. The TraceListener requires a Formatter to specify the message format.
- LogSource - LogSource is a collection of TraceListeners that work as a unit.
- LogWriter - This is The Man. The LogWriter is the focal point of the Logging Application Block. It is the glue that binds all the tracelisteners, filters, and everything else together to make sure the messages that you log and pass through the filters get to the respective tracelisteners. It is the LogWriter.Write(LogEntry log) method that makes it all happen.
- LogEntry - This is the class that holds your message. You will set the Message, Category, Priority, EventId, Severity, and other properties on this class for logging. You may not knowingly use the class directly, because often classes in the Logging Application Block may fill it out for you. However, this is the class that ultimately gets passed to the LogWriter that pushes the message through to the intended LogSource and its TraceListeners.
- ILogFilter - It is a collection of objects implementing the ILogFilter Interface that determine if a message actually gets logged by the LogWriter. It could be a CategoryFilter, LogEnabledFilter, PriorityFilter, or a custom filter you built yourself.
Here is some heavily commented code showing you a simple example of how to work with the Logging Application Block objects directly. Alois Kraus utltimately gets credit for the code as he came out with an example while I was learning this myself that answered all the questions for which I was struggling at the time. You can follow the two posts by him and I on this:
Here is a general MyLogger Class that is responsible for logging information to a flat file. You can easily add or replace TraceListeners at will.
///
/// MyLogger logs messages in the application.
///
public static class MyLogger
{
static readonly LogWriter _writer;
static MyLogger()
{
// The formatter is responsible for the
// look of the message. Notice the tokens:
// {timestamp}, {newline}, {message}, {category}
TextFormatter formatter = new TextFormatter
("Timestamp: {timestamp}{newline}" +
"Message: {message}{newline}" +
"Category: {category}{newline}");
// Log messages to a log file.
// Use the formatter mentioned above
// as well as the header and footer
// specified.
FlatFileTraceListener logFileListener =
new FlatFileTraceListener("c:\\messages.log",
"----------",
"----------",
formatter);
// My collection of TraceListeners.
// I am only using one. Could add more.
LogSource mainLogSource =
new LogSource("MainLogSource", SourceLevels.All);
mainLogSource.Listeners.Add(logFileListener);
// Assigning a non-existant LogSource
// for Logging Application Block
// Specials Sources I don't care about.
// Used to say "don't log".
LogSource nonExistantLogSource = new LogSource("Empty");
// I want all messages with a category of
// "Error" or "Debug" to get distributed
// to all TraceListeners in my mainLogSource.
IDictionary<string, LogSource> traceSources =
new Dictionary<string, LogSource>();
traceSources.Add("Error", mainLogSource);
traceSources.Add("Debug", mainLogSource);
// Let's glue it all together.
// No filters at this time.
// I won't log a couple of the Special
// Sources: All Events and Events not
// using "Error" or "Debug" categories.
_writer = new LogWriter(new ILogFilter[0],
traceSources,
nonExistantLogSource,
nonExistantLogSource,
mainLogSource,
"Error",
false,
true);
}
///
/// Writes an Error to the log.
///
/// Error Message
public static void Write(string message)
{
Write(message, "Error");
}
///
/// Writes a message to the log using the specified
/// category.
///
///
///
public static void Write(string message, string category)
{
LogEntry entry = new LogEntry();
entry.Categories.Add(category);
entry.Message = message;
_writer.Write(entry);
}
}
I put together a quick web application to test out the new class. Here is the extent of the code:
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
MyLogger.Write("My Error");
MyLogger.Write("My Debug", "Debug");
}
}
for which you can see the output:
----------
Timestamp: 2/18/2006 6:24:49 PM
Message: My Error
Category: Error
----------
----------
Timestamp: 2/18/2006 6:24:49 PM
Message: My Debug
Category: Debug
----------
Conclusion
Hopefully this article shed some light on the Enterprise Library 2.0 Logging Application Block.
Source: David Hayden ( Florida .NET Developer and MVP in C# )
Enterprise Library 2.0 Tutorials and Resources