Logging FaultExceptions to the EventLog

Topics: Exception Handling Application Block, General discussion, Logging Application Block
Oct 9, 2008 at 11:17 AM
Hi

I want to log FaultExceptions to the EventLog but all I got in the EventLog is an FaultContractWrapperException.

Here is my Exception Policy:

exceptionHandling>
<
exceptionPolicies>
<
add name="WCF Exception Shielding">
<
exceptionTypes>
<
add type="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" postHandlingAction="ThrowNewException" name="Exception">
<
exceptionHandlers>
<
add faultContractType="FaultContracts.ServiceFault, FaultContracts" exceptionMessage="Portal Service Exception" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF.FaultContractExceptionHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" name="Fault Contract Exception Handler" />
<
add logCategory="Error" eventId="100" severity="Error" title="Portal Service" formatterType="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.TextExceptionFormatter, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" priority="0" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging.LoggingExceptionHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" name="Logging Handler" />
</
exceptionHandlers>
</
add>
</
exceptionTypes>
</
add>
</
exceptionPolicies>
</
exceptionHandling>

 

 

In my code that throws the FaultException I have the following:

 

catch

 

(Exception e)
{
ServiceFault fault = new ServiceFault();
Exception baseException = e.GetBaseException();
fault.Message = baseException.Message;
fault.Source = baseException.Source;
fault.StackTrace = baseException.StackTrace;
throw new FaultException<ServiceFault>(fault, new FaultReason(e.Message));
}

 

 


As you can see I want to control the content of the FaultException because I want to include the base exception in the EventLog. I'm not sure this is the right way to do it but all I want to achieve is to log BaseExceptions  before the FaultExceptions are sent to the clients.

Also, here is my diagnostic settings in web.config:

 

<

 

system.serviceModel>
<
diagnostics>
<
messageLogging logEntireMessage="true" logMalformedMessages="true" logMessagesAtTransportLevel="true" />
</
diagnostics>
</system.serviceModel>

 

<

 

system.diagnostics>
<
sources>
<
source name="System.ServiceModel" switchValue="All">
<
listeners>
<
add name="traceListener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.EntLibLoggingProxyTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging" />
</
listeners>
</
source>
</
sources>
</
system.diagnostics>

 

Oct 10, 2008 at 12:09 PM

Hi,

With exception handling, order does matter. The FaultContractWrapperException is what the FaultContractExceptionHandler throws to make exception shielding work, but that exception is what the logging handler is being handled to log.

For one thing, you should move the logging handler up in the handler chain so it gets to log the original exception. Secondly, you don't want FaultExceptions to be shielded (they are faults already) so you need to specify a new exception type for FaultException that just logs.

Hope this helps,

Fernando

Oct 13, 2008 at 12:29 PM
Hi

I'm not sure what you mean here. Could you please make this clearer for me if we have this as a base for a discussion:

In my WCF-service implementation class every method has this try-catch-logic:

try
{

}
catch (Exception e)
{
       MyServiceFault fault = new MyServiceFault();
       Exception baseException = e.GetBaseException();
                
        fault.Message = baseException.Message;                
        fault.Source = baseException.Source;
        fault.StackTrace = baseException.StackTrace;

        throw new FaultException<MyServiceFault>(fault, new FaultReason(e.Message));
}

So for every exception on my service-side I throw a FaultException. I have done the work for the Exception Handling Application Block here then?

If I want to log this Exception in the EventLog, I want the base exception to be logged because this is a multitier application/service and I want to know in which module/layer the exception was thrown. I also want to log (in EventLog) the stack trace (again, from the base exception). I only need the Logging Application Block to achieve this right?

How do I configure the web.config so that I log every exception that is thrown as an FaultException? Some, two or three questions there that I need to clearify.

Thanks in advance!!

Oct 13, 2008 at 1:05 PM
Hi,

In general you would use the EHAB directly in from your application as described in http://msdn.microsoft.com/en-us/library/cc511556.aspx. However when you use the WCF exception shielding feature (see http://msdn.microsoft.com/en-us/library/cc511695.aspx), the EHAB is used as an internal implementation detail.

Exception shielding is used to declaratively translate regular exceptions into FaultExceptions, just like you're currently doing explicitly through code. This mechanism relies on a properly configured EHAB policy, which must include the FaultContractExceptionHandler to perform the exception to fault mapping. This handler is not intended to be used elsewhere.

If you perform the exception to fault mapping yourself, then you would use the logging block directly. On the other hand if you rely on the exception shielding support you can configure the LoggingExceptionHandler before the FaultContractExceptionHandler to log the exception details for you.

You can take a look at the EHAB quick starts for code samples.

Hope this helps,
Fernando
Oct 14, 2008 at 9:32 AM
Thanks Fernando,

so if I go for doing the exception shielding explicitly through code. Do I have to call the static class Logger in code too in order to log exception messages and stacktraces etc.?

Or can this be configured some way? And how? An sample would be nice.

As I have said in earlier post: 

I want the base exception to be logged because this is a multitier application/service and I want to know in which module/layer the exception was thrown. I also want to log (in EventLog) the stack trace (again, from the base exception).

Thanks again for being so patient with me.
Oct 16, 2008 at 11:47 AM

Hi,

Sorry about the delay; had an answer set up and lost it, so here's a shorter version.

You could get using EHAB's exception shielding support with a properly configured exception policy (but I haven't tried it). This policy would have an explicit entry for FaultException configured with just the log exception handler, and probably a catch-all entry for Exception with the usual FaultContractExceptionHandler and the log handler. You may want to use a custom exception formatter with the logging handler to expose the information you need in a specific way if the standard one doesn't work for you.

However, I don't think you're supposed to leak information like stack traces in your FaultExceptions in general; in fact the purpose of shielding is to avoid this kind of leak. If you're fine with providing the information, the this solution would work for you; otherwise you should log before shielding, as the fault exception wouldn't have the information you want to log.

Hope this helps,
Fernando

 

 

Nov 4, 2008 at 8:59 AM
Fernando, I'm not able to make this work. I have added the Exception Handling Application Block to the web.config, then created an Exception Policy with System.Exception as the Exception Type. The handler for this Exception is an Logging Handler that logs to the Event Log. But I get nothing in my log yet.

In the method which fails I have this code:

public ClientContract LogIn(string username, string password)
{
    try
    {

    }
    catch(Exception e)
    {
        //I would like to log the base exception here first
        //this should happen by itself if web.config is configured correct, right?

        //then I throw an FaultException
        throw new FaultException<ServiceFault>(fault, new FaultReason(e.Message));
    }
}

I know that services shouldn't give information about exceptions but I owe both Client and Service and the service is not public so thats OK.

So could I ask for a basic setup (that works) for how to log an exception in the event log? I thought this was straight forward so I must be missing something basic here...?
Nov 4, 2008 at 9:51 AM
Edited Nov 4, 2008 at 9:53 AM
Hi,

You would need to :

1. Add a Exception handling application block
2. Add a Exception Policy
3. Add a Exception Type
4. Add a Logging Handler to the Exception type

your config should look similar to this.

<?xml version="1.0" encoding="utf-8"?>

<configuration>

  <configSections>

    <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

    <section name="exceptionHandling" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration.ExceptionHandlingSettings, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

    <section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

  </configSections>

  <loggingConfiguration name="Logging Application Block" tracingEnabled="true"

    defaultCategory="" logWarningsWhenNoCategoriesMatch="true">

    <listeners>

      <add source="Enterprise Library Logging" formatter="Text Formatter"

        log="Application" machineName="" listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FormattedEventLogTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"

        traceOutputOptions="None" filter="All" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FormattedEventLogTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"

        name="Formatted EventLog TraceListener" />

    </listeners>

    <formatters>

      <add template="Timestamp: {timestamp}&#xD;&#xA;Message: {message}&#xD;&#xA;Category: {category}&#xD;&#xA;Priority: {priority}&#xD;&#xA;EventId: {eventid}&#xD;&#xA;Severity: {severity}&#xD;&#xA;Title:{title}&#xD;&#xA;Machine: {machine}&#xD;&#xA;Application Domain: {appDomain}&#xD;&#xA;Process Id: {processId}&#xD;&#xA;Process Name: {processName}&#xD;&#xA;Win32 Thread Id: {win32ThreadId}&#xD;&#xA;Thread Name: {threadName}&#xD;&#xA;Extended Properties: {dictionary({key} - {value}&#xD;&#xA;)}"

        type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"

        name="Text Formatter" />

    </formatters>

    <categorySources>

      <add switchValue="All" name="Exception Category">

        <listeners>

          <add name="Formatted EventLog TraceListener" />

        </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="Formatted EventLog TraceListener" />

        </listeners>

      </errors>

    </specialSources>

  </loggingConfiguration>

  <exceptionHandling>

    <exceptionPolicies>

      <add name="Default">

        <exceptionTypes>

          <add type="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"

            postHandlingAction="ThrowNewException" name="Exception">

            <exceptionHandlers>

              <add logCategory="Exception Category" eventId="100" severity="Error"

                title="Enterprise Library Exception Handling" formatterType="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.TextExceptionFormatter, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"

                priority="0" useDefaultLogger="false" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging.LoggingExceptionHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"

                name="Logging Handler" />

            </exceptionHandlers>

          </add>

        </exceptionTypes>

      </add>

    </exceptionPolicies>

  </exceptionHandling>

</configuration>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

----------------

Here is a sample code:

           try

            {

                throw new OutOfMemoryException();

            }

            catch (Exception ex)

            {

                try

                {

                    bool rethrow = ExceptionPolicy.HandleException(ex, "Default");

                    if (rethrow)

                    {

                        throw;

                    }

                }

                catch (Exception exNew)

                {

                    Console.WriteLine(exNew.ToString());

                    Console.WriteLine("---------------------------------------------------");

                    Console.WriteLine(exNew.InnerException);

                    Console.WriteLine(exNew.GetBaseException().GetType().ToString());

                }

                Console.WriteLine(ex.Message);

            }

 

 

 

Hope this helps.

Valiant Dudan
Global Technology and Solutions
Avanade, Inc.
valiant.a.dudan@avanade.com