Posts
69
Comments
233
Trackbacks
162
Programatic Configuraton - Enterprise Library (v2.0) Logging Block

The following code sample shows how to configure the Enterprise Library Logging Block programatically without the help of ObjectBuilder. To create a working LogWriter instance with your own settings you need to create the following objects:
  • A Formatter which contains a valid message template
  • A LogSource which has a name (Category) contains a colleciton of Listeners (Sinks) along with the Formatter.
  • A collection LogSources with the category as key and the LogSource object as value
To use this logger you can call

  ConfigLessLogger.Error("Hello world of config by code.");
The error is written to the Windows Event Application Event Log:

Timestamp: 16.02.2006 23:33:41
Message: Hello World of dynamic object creation
Category: Errors

I have improved my original ConfigLessLogger sample with the very helpful comments from David Hayden who blogs about the Enterprise Library (mainly IConfigurationSource and Logging Block).

ConfigLessLoger.cs

using System;

using System.Collections.Generic;

using Microsoft.Practices.EnterpriseLibrary.Logging;

using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;

using Microsoft.Practices.EnterpriseLibrary.Logging.Filters;

using Microsoft.Practices.EnterpriseLibrary.Logging.Formatters;

using Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners;

 

namespace MyApp.Logging

{

    public class ConfigLessLogger

    {

        private static LogWriter writer;              // Instance is created in static ctor which is thread safe

        const string EventLogSource = "Code Source"// Event Log Source name

        const string ErrorCategory = "Errors";        // We have only one message category: Errors

 

        static ConfigLessLogger()

        {

            writer = CreateLogWriterFromCode();  // static ctor is thread safe according to ECMA standard section 9.5.3

        }

 

        static private LogWriter CreateLogWriterFromCode()

        {

            // This is our message template for any Sink you add below in our case the Windows Event Log

            TextFormatter formatter = new TextFormatter("Timestamp: {timestamp}{newline}" +

                                                        "Message: {message}{newline}"    +

                                                        "Category: {category}{newline}"    );

 

            LogSource emptyTraceSource = new LogSource("none");

 

            LogSource errorsTraceSource = new LogSource(ErrorCategory, System.Diagnostics.SourceLevels.All);

            // Create for all Errors a Listener which writes the messages to the Windows Event Log

            // with the Event Log Source Property "Code Source". The message format is specified by

            // the TextFormatter which is in our case the template above.

            errorsTraceSource.Listeners.Add(new FormattedEventLogTraceListener(EventLogSource, formatter));

 

            IDictionary<string, LogSource> traceSources = new Dictionary<string, LogSource>();

            // Add to Category "Error" our EventLog Listener with the corresponding category in it.

            traceSources.Add(errorsTraceSource.Name, errorsTraceSource);

 

            return new LogWriter(new ILogFilter[0], // ICollection<ILogFilter> filters

                              traceSources,        // IDictionary<string, LogSource> traceSources

                              emptyTraceSource,    // LogSource allEventsTraceSource

                              emptyTraceSource,    // LogSource notProcessedTraceSource

                              errorsTraceSource,    // LogSource errorsTraceSource

                              ErrorCategory,        // string defaultCategory

                              false,                // bool tracingEnabled

                              true);                // bool logWarningsWhenNoCategoriesMatch

        }

 

        /// <summary>

        /// Write an Error message to the Windows Event Log with an message template specifed in code

        /// </summary>

        /// <param name="message">Error message to log</param>

        public static void Error(string message)

        {

            LogEntry ent = new LogEntry();

            ent.Categories.Add(ErrorCategory);  // To use another category use traceSources.Add("OtherCat", Listener);

            ent.Message = message;

            ent.Severity = System.Diagnostics.TraceEventType.Error;

            writer.Write(ent);

        }

    }

}


  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati
posted on Thursday, February 16, 2006 9:39 PM Print
Comments
Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
David Hayden
2/17/2006 6:14 PM
Thanks so much for this great example!

I have a presentation on Enterprise Library 2.0 coming up and was in the process of figuring this out on my own.
Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
Alois Kraus
2/17/2006 8:51 PM
Thanks David. I have looked at your blog. Looks very nice. Perhaps I find my sample there again ;-)
Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
David Hayden
2/17/2006 10:43 PM
Alois,

You will :) A version I just finished writing after 2+ hours of struggling to understand what indeed is happening in your code :)

I didn't realize that in this statement:

traceSources.Add(errorsTraceSource.Name, errorsTraceSource);

the first parameter is actually a category name and designates that all messages sent with that category go to the specified LogSource. The way you have it coded made me think it was the name of the LogSource, since they are one and the same.

So, I can easily add another category of "Debug" and have it go to the same LogSource:

traceSources.Add("Debug", errorsTraceSource);

Your example finally made me understand the inner-workings of the Logging Application Block.


The only other thing I did in my code for kicks was associated with threading.

I put my code, which is similar to your code in CreateLogWriterFromCode() method, in a static constructor and removed the Writer property and CreateLogWriterFromCode() method altogether. It looks something like this:

public static class MyLogger
{
static LogWriter _writer;

static MyLogger()
{
// Create _writer here...
}

public static void Write(string message)
{
Write(message, "Error");
}

public static void Write(string message, string category)
{
LogEntry entry = new LogEntry();

entry.Categories.Add(category);
entry.Message = message;

_writer.Write(entry);
}
}


Can you think of any negative drawback about using the static constructor approach versus your approach?

Once again, thanks for the artice and congratulations on being awarded a P&P Champion. Well deserved I am sure.

Regards,

Dave
Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
Alois Kraus
2/18/2006 12:55 PM
Thanks David. I have looked into the some mailing lists to check if static ctors are thread safe. According to the ECMA standard section 9.5.3
http://jilc.sourceforge.net/ecma_p2_cil.shtml#_Toc524940486 the static ctor is called only once for the type before any other method or property is accessed. Your approach should work well and looks easier to me. There is always room for improvement ;-)

Yours,
Alois Kraus
Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
Mohamed El-Zahaby
2/21/2006 7:21 AM
but how can the static constructor work correctly incase I have many trace Listeners ?

Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
Alois Kraus
2/21/2006 11:59 AM
Hi Mohammed,
could you provide more info what race condition deadlock you expect when I create one or many listeners in the static ctor?

Yours,
Alois Kraus
Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
Mohamed El-Zahaby
2/21/2006 12:23 PM
Incase if you I have a parameter to decide which logging target will be used ; file or windows event

this is the way I implemeneted it :
I added a new switch case in the write function

public static void Write(string message)
{
errorsTraceSource = new LogSource("Errors", SourceLevels.All);

LogEntry entry = new LogEntry();
entry.Categories.Add("Errors");
entry.Message = message;

switch (oLogTarget)
{
#region Logging into file
// Logging into FILE
case LogTarget.File:
try
{
errorsTraceSource.Listeners.Add(new FormattedTextWriterTraceListener(FileName, formatter));
LogSource emptyTraceSource = new LogSource("none");
IDictionary<string, LogSource> traceSources = new Dictionary<string, LogSource>();
traceSources.Add(errorsTraceSource.Name, errorsTraceSource);
writer = new LogWriter(new ILogFilter[0], // ICollection filters,
traceSources, // IDictionary traceSources,
emptyTraceSource, // LogSource allEventsTraceSource,
emptyTraceSource, // LogSource notProcessedTraceSource,
errorsTraceSource, // LogSource errorsTraceSource,
"Errors", // string defaultCategory,
false, // bool tracingEnabled,
true); // bool logWarningsWhenNoCategoriesMatch)
}
catch { }
break;
case LogTarget.EventViewer:
try
{
errorsTraceSource.Listeners.Add(new FormattedEventLogTraceListener(Source, formatter));
LogSource emptyTraceSource = new LogSource("none");
IDictionary<string, LogSource> traceSources = new Dictionary<string, LogSource>();
traceSources.Add(errorsTraceSource.Name, errorsTraceSource);
writer = new LogWriter(new ILogFilter[0], // ICollection filters,
traceSources, // IDictionary traceSources,
emptyTraceSource, // LogSource allEventsTraceSource,
emptyTraceSource, // LogSource notProcessedTraceSource,
errorsTraceSource, // LogSource errorsTraceSource,
"Errors", // string defaultCategory,
false, // bool tracingEnabled,
true); // bool logWarningsWhenNoCategoriesMatch)

entry.Severity = System.Diagnostics.TraceEventType.Error;
}
catch
{ }
break;
#endregion
}


writer.Write(entry);
}
Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
Alois Kraus
2/21/2006 12:47 PM
Hmm,
I do not recommend to do it this way you have shown here. You should access the LogWriter instance which configuration determines via Category where the information is logged (you will need only one LogWriter instance not many). Your new parameter defeats the intention of the Logging block to make the log destination configurable. You can configure an arbitrary amount of log categories which contain one or many the Listeners. Your sample will result in bad performance and run time (locking) errors because the LogWriter object created in the previous log call will very likely not be disposed yet and hold files, databases, etc. open. If you need to hard code everything I am not sure if Entlib is the right choice for you. The programatic configuration was meant to supply a builtin default configuration if no external configuration is present. If you do not want to configure anything I would not use Entlib at all.

Yours,
Alois Kraus
Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
Mohamed El-Zahaby
2/21/2006 1:40 PM
yes you are completely true. I will fix my code.
Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
Mohamed ElZahaby
3/21/2006 3:13 AM
Thanks very much
I refernced you in this article
http://www.codeproject.com/useritems/Logging_Plug-in_Manager.asp
Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
rahul
4/13/2006 5:49 AM
Hi,
I am trying to log the errors in database programatically, can anyone help me out with that.

Thanks,
Rahul.
Gravatar
# Enterprise Library (v2.0) Logging Block
Brian
6/30/2006 2:30 PM
Greetings - I am working on a C#.NET console app. I am using EL 2.0, and using the config tool, I cannot set it up to create and write to a new custom Windows event log. Writing to the "Application" event log works fine. When I execute, I am getting an event log entry that says my .exe is not listed as a source, when indeed it is. Has anyone come across this and found a solution - thank you.
Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
Alois Kraus
6/30/2006 7:38 PM
Hi Brian,

you should create the Event log sources via the EventLog.CreateEventSource API by yourself during the installation of your software package since you cannot be sure to have the required privileges to do this when you run under a low privileged account such as the aspnet user when you host then Enteprise Library inside IIS.

Yours,
Alois Kraus
Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
Aaron
8/2/2006 4:40 PM
Hi - I am logging fine, but I have trouble with email sending. I want to send logs by mail and I can't find any documentation or examples about it. I have configured an EmailTraceListener but can't figure out how to use this configuration with the EmailMessage class. Do anyone has links of code samples, tutorials or knows how to do this? ... thanks
Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
Will
9/28/2006 1:12 PM
Hi,

This may be a newbie question, but how would I read the config parts of the app.config that refer to logging/application blocks? In the manner that you would use an appsettings reader to read the <appSettings> section of the config file?

What I want to do, is use the logging and exception blocks, but I also want to read bits of the config in other sections of my code.

I was looking for something like appblockConfig Reader.GetPolicySection.getkeyvalue(strkey) or somesuch.

Any thoughts?
Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
Will
9/28/2006 1:14 PM
In response to Aaron ...

Look at Davids blog.. http://davidhayden.com/blog/dave/archive/2006/02/15/2802.aspx

I used this, but where he mentions flat files - you set up an email trace listener. Use the config tool that ships with the framework!
Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
Michael
11/23/2006 11:38 PM
Hello,

is it possible to configure the Excepetion Handling Block programmatically as well? Maybe in additon with your example above?

Greetings,
Michael
Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
Alois Kraus
11/23/2006 11:59 PM
Hi Michael,

sort of:
http://www.agileprogrammer.com/oneagilecoder/archive/2006/02/20/11628.aspx

But you have to modify the source of the Exception handling block to make it work. And it is quite complicated to set up as you can see.

Yours,
Alois
Gravatar
# Question on Flat File Trace Listener
raja
2/12/2007 8:46 AM
Have a query regarding Flat File Trace Listener.
To log data,i am currently picking up file name from the (App.config)config file.
is there any way that i can change the name of
the config @ runtime.
any pointers would be great.
Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
Ayush
9/16/2007 9:56 PM
Thanks a lot for this wonderful article.

Is there any way we can configure the exception hadling dynamically?
i don't want to put any of my configurations on web.config but on database.

Plz help
Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
Alois Kraus
9/17/2007 10:56 AM
It is possible to use the SqlConfigurationSource which is part of Entlib 3.1 and 2.0 in the QuickStarts folder.

Yours,
Alois Kraus
Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
pushpendra
10/28/2007 1:26 AM
Hi Alois,

The code is works great but it logs the message into the event log as information(information icon seen in windows event log), what should i do to make it log the messages as errors(with the red error icon in the event log)?

Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
Michael Richards
11/14/2007 2:40 AM
Is it possible to have multiple TextFormatters in this example that you could then select the format from based on a parameter or condition?
Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
Kaushal patel
11/3/2008 8:16 PM
Hi,
I could log the errors using flat file & email trace listneres programatically.

How can i log the errors in database programatically, can anyone help me out with that.

Thanks,
Kaushal.
Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
Kaushal
11/4/2008 7:11 PM
//Create TextFormatrer with diffrent Tokens

string template="Timestamp: {timestamp}{newline}" +
"Message: {message}{newline} " +
"Category: {category}{newline}" +
"Priority: {priority}{newline}" +
"EventId: {eventid}{newline}" +
"Severity: {severity}{newline}" +
"Title:{title}{newline}" +
"Machine: {machine}{newline}" +
"Application Domain: {appDomain}{newline}" +
"Process Id: {processId}{newline}" +
"Process Name: {processName}{newline}" +
"Win32 Thread Id: {win32ThreadId}{newline}" +
"Thread Name: {threadName}{newline}";



TextFormatter formatter = new TextFormatter(template);

//Create DatabaseTraceListener using TextFormatter created above.
string strConn - "...";
SqlDatabase sqlDB = new SqlDatabase(strConn);
FormattedDatabaseTraceListener databaseTraceListener = new FormattedDatabaseTraceListener(sqlDB, "WriteLog", "AddCategory", formatter);



//Collection of TraceListeners
LogSource errorsTraceSource = new LogSource("ErrorsTraceSource", SourceLevels.All);
errorsTraceSource.Listeners.Add(databaseTraceListener);


// Assigning a non-existant LogSource
// for Logging Application Block
// Used to say "don't log".
LogSource emptyTraceSource = new LogSource("Empty");


//Below will log all messages with a category of "Error" or "Debug" to all TraceListeners in errorsTraceSource.
IDictionary<string, LogSource> traceSources = new Dictionary<string, LogSource>();
traceSources.Add("Error", errorsTraceSource);
traceSources.Add("Debug", errorsTraceSource);



LogEntry logEntry = new LogEntry();
logEntry.EventId = 100;
logEntry.Priority = 2;
logEntry.Message = "Informational message generated using Logging Application Block.";
logEntry.Categories.Add("Error");
logEntry.Categories.Add("Debug");
logEntry.Categories.Add("Trace");
logEntry.Categories.Add("UI Events");
logEntry.TimeStamp = DateTime.Now;
logEntry.Severity = TraceEventType.Error;


LogWriter writer = new LogWriter(new ILogFilter[0], // ICollection<ILogFilter> filters
traceSources, // IDictionary<string, LogSource> traceSources
emptyTraceSource, // LogSource allEventsTraceSource
emptyTraceSource, // LogSource notProcessedTraceSource
errorsTraceSource, // LogSource errorsTraceSource
ErrorCategory, // string defaultCategory
false, // bool tracingEnabled
true); // bool logWarningsWhenNoCategoriesMatch


writer.Write(logEntry);
writer.Dispose();


Cheers,
Kaushal
Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
Brandon
7/10/2009 1:25 AM
Thank you! I've been looking for a good example (database programatically). (btw I was using entlib 4.1 and it worked perfectly)
Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
Manthan
11/26/2009 9:11 PM
Hello Alois,

Thanks for the interesting blog. I had a question in the TextFormatter you have the following pattern:

TextFormatter formatter = new TextFormatter("Timestamp: {timestamp}{newline}" +
"Message: {message}{newline}" +
"Category: {category}{newline}" );

Is there a way where I can show the timestamp in the following format dd/mm/yyyy hh:mm:ss.fff

as i am using the log file for both debug and error. and for debug want to find out how long did it take to process each request.

Any help would be highly appreciated.

Cheers,

Manthan
Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
Alois Kraus
11/29/2009 9:46 AM
Hi Manthan,

sure you can do this. Simply type: {timestamp(dd/mm/yyy hh:mm:ss.fff)} into your text template to use the formatting options of DateTime.ToString.

http://www.geekzilla.co.uk/View00FF7904-B510-468C-A2C8-F859AA20581F.htm

Yours,
Alois Kraus
Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
Rahul
3/28/2011 2:13 AM
Hi David,
I am using Ent Lib 5.0 and IBM DB2 database. I want to use the Logging Application Block to log to the IBM DB2 Database. Could you please provide me a sample code which I can use to do that. I am fine with both Configuration Based Code or Programatic one as shown in above examples.
Gravatar
# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block
Dasha
8/19/2011 7:09 AM
хочу видеоо

Post Comment

Title *
Name *
Email
Url
Comment *