Alois Kraus

blog

  Home  |   Contact  |   Syndication    |   Login
  106 Posts | 8 Stories | 293 Comments | 162 Trackbacks

News



Article Categories

Archives

Post Categories

Image Galleries

Programming

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);

        }

    }

}


posted on Thursday, February 16, 2006 9:39 PM

Feedback

# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 2/17/2006 6:14 PM David Hayden
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.

# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 2/17/2006 8:51 PM Alois Kraus
Thanks David. I have looked at your blog. Looks very nice. Perhaps I find my sample there again ;-)

# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 2/17/2006 10:43 PM David Hayden
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

# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 2/18/2006 12:55 PM Alois Kraus
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


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



# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 2/21/2006 11:59 AM Alois Kraus
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


# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 2/21/2006 12:23 PM Mohamed El-Zahaby
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);
}

# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 2/21/2006 12:47 PM Alois Kraus
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


# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 2/21/2006 1:40 PM Mohamed El-Zahaby
yes you are completely true. I will fix my code.

# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 3/21/2006 3:13 AM Mohamed ElZahaby
Thanks very much
I refernced you in this article
http://www.codeproject.com/useritems/Logging_Plug-in_Manager.asp

# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 4/13/2006 5:49 AM rahul
Hi,
I am trying to log the errors in database programatically, can anyone help me out with that.

Thanks,
Rahul.

# Enterprise Library (v2.0) Logging Block 6/30/2006 2:30 PM Brian
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.


# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 6/30/2006 7:38 PM Alois Kraus
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


# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 8/2/2006 4:40 PM Aaron
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

# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 9/28/2006 1:12 PM Will
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?

# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 9/28/2006 1:14 PM Will
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!

# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 11/23/2006 11:38 PM Michael
Hello,

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

Greetings,
Michael

# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 11/23/2006 11:59 PM Alois Kraus
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


# Question on Flat File Trace Listener 2/12/2007 8:46 AM raja
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.

# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 9/16/2007 9:56 PM Ayush
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

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

Yours,
Alois Kraus


# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 10/28/2007 1:26 AM pushpendra
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)?



# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 11/14/2007 2:40 AM Michael Richards
Is it possible to have multiple TextFormatters in this example that you could then select the format from based on a parameter or condition?

# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 11/3/2008 8:16 PM Kaushal patel
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.

# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 11/4/2008 7:11 PM Kaushal
//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

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

# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 11/26/2009 9:11 PM Manthan
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

# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 11/29/2009 9:46 AM Alois Kraus
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


# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 3/28/2011 2:13 AM Rahul
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.

# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 8/19/2011 7:09 AM Dasha
хочу видеоо

# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 6/26/2012 5:01 PM Linh
Hi Alois,
I noticed you mentioned in Erwyn van der Meer Rolling File Trace Listener Extension that you implemented an extension to his code to use the . ProcessID Expansion to support multi process logging. I have been trying to figure out what is required in order to do this. Is this an extension that you can share with me. I need to be able to log multiple processes and the current Rolling File Trace Listener provided by Enterprise Library 5.0 does not provide this capability. Your help would be greatly appreciated.

# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 6/29/2012 6:00 PM Alois Kraus
Hi Linh,
sorry but that was something I did for my day work. This is not something I can publish.

# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 12/23/2013 4:47 PM Srikanth
How does this code even compile? I keep getting the message that LogWriter instance cannot be created as it is abstract. Does it not error out when it sees return new LogWriter??

# re: Programatic Configuraton - Enterprise Library (v2.0) Logging Block 12/23/2013 9:41 PM Alois Kraus
This was for Entlib 2.0. Since then the Logging Application Block has undergone significant changes. MSDN has good examples online now. See http://msdn.microsoft.com/en-us/library/dn440731(v=pandp.60).aspx

Post A Comment
Title:
Name:
Email:
Comment:
Verification: