Implementing Exception Logging To EventViewer & Flat Text File Within The Same Application Using Enterprise Library 5.0

Topics: Caching Application Block , Exception Handling Application Block, Logging Application Block
Jul 13, 2012 at 10:40 PM
Edited Jul 13, 2012 at 10:43 PM

Greetings;

I'm trying to add support for logging exceptions to both the EventViewer and a Flat Text File within the same application using Enterprise Library 5.0, and programatically control whether or not to write to either the EventViewer or Flat Text File separately or at the same time.

Using Enterprise Library 5.0 and a simple test harness I created as a Windows Forms based application with the .NET 4.0 Framework, I can write or log exceptions to both the EventViewer and Flat Text File in the same call at the same time.  However, I cannot write to each separatly with different policies setup in the app.config file using the Enterprise Library V5 Configuration Tool, EntLibConfig.NET4-32.exe.

With one Exception Handling Settings Policy in place named "Harness UI Policy", I have the following Exception Type and Handlers defined:

Policy
Harness UI Policy   
Name: Harness UI Policy

Exception Type
All Exceptions   
Name: All Exceptions   
Post Handling: None   
Type Name: System.Exception, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e08

In the Logging Settings section of the Enterprise Library Configuration Tool, I have the following two Logging Target Listeners and one Log Message Formatter defined:

Logging Target Listeners   
Event Log Listener   
Name: Event Log Listener   
Formatter Name: Text Formatter   
Template:       
Timestamp: {timestamp}{newline}       
Message: {message}{newline}       
Category: {category}{newline}       
Priority: {priority}{newline}       
EventId: {eventid}{newline}       
Severity: {severity}{newline}       
Title:{title}{newline}       
Machine: {localMachine}{newline}       
App Domain: {localAppDomain}{newline}       
ProcessId: {localProcessId}{newline}       
Process Name: {localProcessName}{newline}       
Thread Name: {threadName}{newline}       
Win32 ThreadId:{win32ThreadId}{newline}       
Extended Properties: {dictionary({key} - {value}{newline})}        
Type Name: TextFormatrter    
Log Name: [Empty]    
Machine Name: .    
Severity Filter: All    
Source Name: Enterprise Library Logging    
Trace Output Options: [All Options are Unchecked]    
Type Name: FormattedEventLogTraceListener        

Flat File Trace Listener   
Name: Flat File Trace Listener    File Name: trace.log    Formatter Name: Text Formatter    Name: Text Formatter    
Template:        
Timestamp: {timestamp}{newline}        
Message: {message}{newline}        
Category: {category}{newline}        
Priority: {priority}{newline}        
EventId: {eventid}{newline}        
Severity: {severity}{newline}        
Title:{title}{newline}        
Machine: {localMachine}{newline}        
App Domain: {localAppDomain}{newline}        
ProcessId: {localProcessId}{newline}        
Process Name: {localProcessName}{newline}        
Thread Name: {threadName}{newline}        
Win32 ThreadId:{win32ThreadId}{newline}        
Extended Properties: {dictionary({key} - {value}{newline})}        
Type Name: TextFormatter   
Message Footer: ------------------------------               
Message Header: ------------------------------               
Severity Filter: All   
Trace Ouput Options: [All Options are Unchecked]   
Type Name: FlatFileTraceListener    

With these definitions in the app.config file, I can log exceptions to both the EventViewer and the trace.log flat text file with one call through the same instance of the ExceptionPolicy using the "Harness UI Policy";

private readonly string ExceptionHandlingUIPolicy = "Harness UI Policy";

//
// ... 
//
private bool LogExceptionToEventViewer(Exception thrownException)
{ bool rethrowException = ExceptionPolicy.HandleException(thrownException, ExceptionHandlingUIPolicy); return rethrowException; }

What I would like to do is have two separate policies to log to two different Trace Listeners for logging Exceptions.  I would like to have one policy named "Harness UI Policy" log exceptions to the Windows EventViewer, and a "Harness Flat File Policy" log exceptions to a Flat Text File.

When I am creating the "Harness Flat File Policy" in the app.config file using EntLibConfig.NET4-32.exe, I'm seeing something in Enterprise Library V5 Configuration Tool that has me confused.  When inside the Exception Handling Settins groupbox, and I add the new Policy named "Harness Flat File Policy", I can add the Policy and define the Exception Types to be handled by this new Policy:

Exception Handling SettingsHarness Flat File Policy   
Name: Harness Flat File Policy   

(Note: The previously defined policy "Harness UI Policy" with the     same definitions listed above is still present in the app.config).

Exception Types
SystemException   
Name: SystemException   
Post Handling: None   
Type Name: System.Exception, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e08   

(Note: The previously defined Exception Type "All Exceptions" with the same definitions listed above is still present in the app.config).

The problem occurs when I create a new Handler specifically for the "Harness Flat File Policy" named "Flat File Exception Handler" inside the Handlers section of the Exception Handling group box.   Even though "Flat File Exception Handler" is linked through the "Harness Flat File Policy" and the "SystemException" Exception Type definition, if I add, change remove or delete either the "Event Log Listener" or "Flat File Trace Listener" in the Listeners section of the Handler definition for the Flat File Exception Handler, the Listener definition in the existing "Logging Exception Handler" linked to the "Harness UI Policy" is changed to use the same Listener automatically.

With this in mind, I would appreciate any clarifications or answers to the following:

1.) Is Enterprise Library 5.0 designed and implemented in such a way to have two or more Exception Handling Policies with the same or different Exception Types handled to separate Handlers?  Am I correct in thinking that the answer to this question is yes?

2.) If I change the Listener in a separate Exception Handler linked through a different Exception Handling Policy in the same app.config file, should only the Listener used in the current Policy being created or updated be changed?  For example, if I add, change, update or delete a Listner from the Listeners section in the "Flat File Exception Handler" to expect that the existing Listeners definitions in the Logging Exception Handler which logs to the EventViewer remain unchanged?

Any clarification, help and insights provided would be greatly appreciated.

Thank you...
ClockEndGooner


My updated app.config file that has the behavior described above is as follows:

<?xml version="1.0"?><configuration>
<configSections>
<section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
<section name="exceptionHandling" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration.ExceptionHandlingSettings, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
</configSections><loggingConfiguration name="" tracingEnabled="true" defaultCategory="General">
<listeners>
<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 name="Flat File Trace Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" fileName="trace.log" header="-----------------------------------------------------------------------------" footer="-----------------------------------------------------------------------------" formatter="Text Formatter" traceOutputOptions="None" />
</listeners>
<formatters>
<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" />
<add name="Flat File Trace Listener" />
</listeners>
</errors>
</specialSources></loggingConfiguration><exceptionHandling>
<exceptionPolicies>
<add name="Harness UI Policy">
<exceptionTypes>
<add name="All Exceptions" type="System.Exception, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" postHandlingAction="None">
<exceptionHandlers>
<add name="Logging Exception Handler" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging.LoggingExceptionHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" logCategory="General" eventId="100" severity="Error" title="MSEntLibLogNTraceHarness" formatterType="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.TextExceptionFormatter, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling" priority="0" />
</exceptionHandlers>
</add>
</exceptionTypes>
</add>
<add name="Harness Flat File Policy">
<exceptionTypes>
<add name="SystemException" type="System.SystemException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" postHandlingAction="None">
<exceptionHandlers>
<add name="Flat File Exception Handler" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging.LoggingExceptionHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" logCategory="General" eventId="1000" severity="Error" title="Enterprise Library Exception Handling" formatterType="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.TextExceptionFormatter, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling" priority="0" />
</exceptionHandlers>
</add>
</exceptionTypes>
</add>
</exceptionPolicies></exceptionHandling><connectionStrings>
<add name="CSGSQL3 Logging Development" connectionString="Data Source=CSGSQL3;Initial Catalog=Logging;Integrated Security=SSPI;" providerName="System.Data.SqlClient" /></connectionStrings><startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
Jul 14, 2012 at 6:56 AM

The answer to your first question is yes.

The connection between the LoggingExceptionHandler and Logging Trace Listeners is the Category.  So if you want one LoggingExceptionHandler to send an entry to a Flat File and another LoggingExceptionHandler to send an entry to the Event Log then you will need to set up 2 categories: one that contains a Flat File Trace Listener and another that has a Formatted Event Log Trace Listener.

With your configuration it might look like:

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
    <section name="exceptionHandling" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration.ExceptionHandlingSettings, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
    <section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
  </configSections>
  <loggingConfiguration name="" tracingEnabled="true" defaultCategory="EventLogException">
    <listeners>
      <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 name="Flat File Trace Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
          listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
          fileName="trace.log" header="-----------------------------------------------------------------------------"
          footer="-----------------------------------------------------------------------------"
          formatter="Text Formatter" traceOutputOptions="None" />
      <add name="Internal Error Flat File Trace Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
          listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
          fileName="errors.log" />
    </listeners>
    <formatters>
      <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="EventLogException">
        <listeners>
          <add name="Event Log Listener" />
        </listeners>
      </add>
      <add switchValue="All" name="FlatFileException">
        <listeners>
          <add name="Flat File Trace 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="Internal Error Flat File Trace Listener" />
        </listeners>
      </errors>
    </specialSources>
  </loggingConfiguration>
  <exceptionHandling>
    <exceptionPolicies>
      <add name="Harness UI Policy">
        <exceptionTypes>
          <add name="All Exceptions" type="System.Exception, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
              postHandlingAction="None">
            <exceptionHandlers>
              <add name="Logging Exception Handler" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging.LoggingExceptionHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                  logCategory="EventLogException" eventId="100" severity="Error"
                  title="MSEntLibLogNTraceHarness" formatterType="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.TextExceptionFormatter, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling"
                  priority="0" />
            </exceptionHandlers>
          </add>
        </exceptionTypes>
      </add>
      <add name="Harness Flat File Policy">
        <exceptionTypes>
          <add name="SystemException" type="System.SystemException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
              postHandlingAction="None">
            <exceptionHandlers>
              <add name="Flat File Exception Handler" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging.LoggingExceptionHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                  logCategory="FlatFileException" eventId="1000" severity="Error"
                  title="Enterprise Library Exception Handling" formatterType="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.TextExceptionFormatter, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling"
                  priority="0" />
            </exceptionHandlers>
          </add>
        </exceptionTypes>
      </add>
    </exceptionPolicies>
  </exceptionHandling>
  <dataConfiguration defaultDatabase="CSGSQL3 Logging Development" />
  <connectionStrings>
    <add name="CSGSQL3 Logging Development" connectionString="Data Source=CSGSQL3;Initial Catalog=Logging;Integrated Security=SSPI;"
        providerName="System.Data.SqlClient" />
  </connectionStrings>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
  </startup>
</configuration>

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com