Custom trace listener and logging

Topics: Logging Application Block
Dec 9, 2011 at 1:52 PM


I wrote a custom trace listener that sends some data over WCF to the server-side. Everything works perfectly fine, but there is one issue with it. Whenever I get any exception during the communication, my requirement is to log the exception to a file. I thought that it would be easiest to use EntLib to take care of that and therefore I used the Logger.Write method, but then I got the following error message: "Recursive read lock acquisitions not allowed in this mode.". I have not investigated the code, but I assume that this has something to do with the internal locking that you implemented to make the Logging block thread-safe. Probably I also should not use the Logger class in the trace listener and therefore my question is: what is the recommended approach to internally log within a custom trace listener? (I thought that I will find an example in the default database trace listener, but obviously there is no code to handle exceptions - does it mean that internally all exceptions thrown in a trace listener are logged? If so, how can I use the configuration to route them to the correct trace listener (which category)?).

I would be very grateful if you could point me in the right direction. Thank you in advance for help.

Kind regards,

Dec 9, 2011 at 10:59 PM
Edited Dec 9, 2011 at 11:57 PM

It sounds like you are hitting a LockRecursionException.  Enterprise Library does not explicitly throw this exception.  It looks like the .NET Framework itself is
throwing the exception (check out the stack trace to see for sure what the source is).

In terms of logging inside an Enterprise Library TraceListener I'm going to talk about logging exceptions.
The correct approach to handling exceptions within your TraceListener is to throw the exception or allow the exception to bubble up (depending on the
scenario).  The exception will be caught by the Logging Block and will then be logged to the errors Special Source which designates where to send the
details of any errors that occur while processing Log Entries.
You just need to specify the TraceListener to log your errors to.  For example, the configuration could look like:
    <loggingConfiguration name="" tracingEnabled="true" defaultCategory="General">
            <add name="Event Log Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FormattedEventLogTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FormattedEventLogTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                source="Enterprise Library Logging" formatter="Text Formatter"
                log="" machineName="." traceOutputOptions="None" />
            <add type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                template="Timestamp: {timestamp}{newline}&#xA;Message: {message}{newline}&#xA;Category: {category}{newline}&#xA;Priority: {priority}{newline}&#xA;EventId: {eventid}{newline}&#xA;Severity: {severity}{newline}&#xA;Title:{title}{newline}&#xA;
Machine: {localMachine}{newline}&#xA;App Domain: {localAppDomain}{newline}&#xA;ProcessId: {localProcessId}{newline}&#xA;Process Name: {localProcessName}{newline}&#xA;Thread Name: {threadName}{newline}&#xA;Win32 ThreadId:{win32ThreadId}{newline}&#xA;Extended Properties: {dictionary({key} - {value}{newline})}
" name="Text Formatter" /> </formatters> <categorySources> <add switchValue="All" name="General"> <listeners> <add name="Event Log Listener" /> </listeners> </add> </categorySources> <specialSources> <allEvents switchValue="All" name="All Events" /> <notProcessed switchValue="All" name="Unprocessed Category" /> <errors switchValue="All" name="Logging Errors &amp; Warnings"> <listeners> <add name="Event Log Listener" /> </listeners> </errors> </specialSources>
Despite my example, I would recommend setting the errors source to it's own file.  This is so if the original TraceListener fails (e.g. permissions)
then the errors source is not trying to log to the same location as what has already failed!

Randy Levy
Enterprise Library support engineer

Dec 12, 2011 at 10:46 AM

That's what I was looking for. Thanks a lot for help.

Kind regards,