Programatically access "Logging Errors & Warning" TraceListener

Topics: Logging Application Block
Feb 14, 2011 at 1:41 PM

Hi all,

I cant' figure out how to get a reference to an existing CustomTraceListener, if this listener is assigned to any of the 3 special categories (All events, Error, Unprocessed)

From start:

I have created my own Custom trace listener "AppEventListener". This listener sports an event that is fired whenever a LogEntry reaches it.

My EntLib Logging config has one instance of this Listener named "Status" assigned to my Status category and another instance named "LogError" assigned to the special category "Logging Errors & Warnings".

Now my client code needs to get a reference to these 2 instances of my Custom trace Listener to subscribe to the event.

To get the  "Status" instance, i can iterate over all Trace categories and check their listeners (logWriter.TraceSources). That works fine.

BUT: how can i get to the "LogError" instance??? The LogWriter.structureHolder.ErrorsTraceSource would suite me fine but unfortunately the structureholder is not accessible....

Any Ideas?

BR and thanks

 

 

Feb 15, 2011 at 2:42 AM

I'm not sure specifically what are you trying to do here since if the same trace listener is configured in a two different Log Category I'm assuming instance of that TraceListener would be the same or is there something special with your custom trace listener? Anyway to get the specific tracelistener reference to the Error Trace Source here's the approach I'm thinking. Hope this helps.

            Configuration xmlConfiguration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            LoggingSettings setting = (LoggingSettings)xmlConfiguration.GetSection(LoggingSettings.SectionName);

            FlatFileTraceListenerData errorTraceListener = null;
            string errorTraceListenerName = setting.SpecialTraceSources.ErrorsTraceSource.TraceListeners.Get("Error Flat File Listener").Name;

            TraceListenerDataCollection traceListenerColl = setting.TraceListeners;
            foreach (TraceListenerData item in traceListenerColl)
            {
                if (item.Name.Equals(errorTraceListenerName))
                {
                    errorTraceListener = (FlatFileTraceListenerData) item;
                }
            }
            

Gino Terrado
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Feb 15, 2011 at 6:25 AM

Thanks for your response.

To clarify: 
I have two Listeners configured, one named "Status" the other named "LogError", both of type "AppEventListener" (my custom defined listener). 
So at runtime there should be 2 objects of type AppEventListener, right?
The "Status" Listener is connected to my "StatusMsg" category while the "LogError" Listener is connected to the special category "Logging Errors & Warnings".
Now, in my code, I want to subscribe to the "Status" Listeners Event to get all status Logs and display them, and also to the "LogError" Listeners Event to check the log error messages to handle them differently.

Using your snippet i can successfully access all the Listeners configuration data, but how do i get a reference to the object that got created using this configuration data? I think it should be of type System.Diagnostics.TraceListener of derived?

To get a reference to the "Status" Listener (assigned to the "StatusMsg" category) i use the following. But as said, this way i can only access listeners connected to normal categories, Listeners assigned only to any of the 3 special categories, I will not find.

System.Diagnostics.TraceListener ret = null;
LogWriter logWriter = EnterpriseLibraryContainer.Current.GetInstance<LogWriter>();
foreach (KeyValuePair<string, LogSource> ts in logWriter.TraceSources)
{
   List<System.Diagnostics.TraceListener> tll = (List<System.Diagnostics.TraceListener>)ts.Value.Listeners;
   if (tll != null && tll.Count > 0)
   {
     foreach (System.Diagnostics.TraceListener tl in tll)
     {
       if (tl.Name == "Status")
       {
         if (tl is Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.ReconfigurableTraceListenerWrapper)
         {
           ret = ((Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.ReconfigurableTraceListenerWrapper)tl).InnerTraceListener;
           break;
         }
       }
     }
   }
}

Feb 15, 2011 at 8:12 AM

Yes you're correct there should be 2. I initially thought "Status" and "LogError" are your categories.

I'm afraid I'm a little confused regarding what you mean by "how do i get a reference to the object that got created using this configuration data". Could you provide more details about this.

Also, I'm just having some thoughts if what you want to achieve is "I want to subscribe to the "Status" Listeners Event to get all status Logs and display them, and also to the "LogError" Listeners Event to check the log error messages to handle them differently." is this something that cannot be done in your custom trace listener?

Anyway if you may to the option that you would want to fully have your logging setting programmatically I recommend utlizing entlib 5.0 Fluent Configuration API. Hope this helps. 

Gino Terrado
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Feb 15, 2011 at 9:11 AM

The 2 objects (of my custom Listener) offer each a public LogEntryReceived event, and I want to subscribe to these form my client code. To do this, I somehow need to get hold of the two objects (that get created from the logging application block during startup).

To the 2nd point: Some of my logs (those having the "Status" category) I want show to the user in the status bar, some in an error ListBox, in addition to logging them all to a File Listener. So i thought i create my custom listener that simply feeds back the received LogEntry to the client code, and the client code can then add that to the status bar or the error ListBox.

Thanks for the link, i'll have a look.

Maybe I need to create objects of my custom Listener at runtime on my own and add it to the LAB, instead of having the LAB create everything based on the config

 

Feb 15, 2011 at 2:32 PM

In the meantime I've found the solution.

As always it much more elegant than my initial approach. Using the GetInstance() i can directly get the instance by name

System.Diagnostics.TraceListener traceListener = EnterpriseLibraryContainer.Current.GetInstance<System.Diagnostics.TraceListener>(name);
if (traceListener == null)
{
return null;
}
if (traceListener is Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.ReconfigurableTraceListenerWrapper)
{
ret = ((Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.ReconfigurableTraceListenerWrapper)traceListener).InnerTraceListener;
}