VansFannel
VansFannel

Reputation: 45911

Log all exception information for any kind of exception

I'm developing with C#, ASP.NET MVC Web Api, Entity Framework and .NET Framework 4.0.

I have this code to log an exception:

public void LogCompleteException(
    string controllerName,
    string actionName,
    Exception exception)
{
    string exceptionMessage = string.Empty;

    Exception e = exception;
    if (e.InnerException == null)
        e = null;
    else
        while (e.InnerException != null) e = e.InnerException;

    if (e == null)
        exceptionMessage = exception.Message;
    else
        exceptionMessage = string.Format("{0}\n\rInnerException: {1}", exception.Message, e.Message);

    _logger.ErrorFormat(
        LogTextFormatString,
        ExceptionText,
        controllerName,
        actionName,
        exceptionMessage);
}

But on my log file I have found this:

Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.

When I wrote 'See 'EntityValidationErrors' property for more details.', I'm only showing an example where I haven't log an important property.

There are a lot of kind of exceptions; but with my method I'm not logging all the relevant information because there could be properties like 'EntityValidationErrors' that I don't log.

When I pass the exception to log it I don't know what properties it has, and I don't know how to log each property it has.

Do you know a method to log an exception completely? My code doesn't long exceptions with an EntityValidationErrors property or any other important property.

I'm doing the logging with log4net.

Upvotes: 6

Views: 1731

Answers (2)

Brad C
Brad C

Reputation: 2982

Since the inner exception is an exception itself, perhaps you can just recurse and reuse the method you already have:

if (e.InnerException != null)
{
    LogCompleteException(controllerName, actionName, e.InnerException);
}

If this does work, however, you will still be missing the EntityValidationErrors.

Another method, which I used recently is to just explicitly trap and log the exception where it occurs:

try
{
    db.Add(something);
    db.SaveChanges();
}
catch (DbEntityValidationException ex)
{
    StringBuilder sb = new StringBuilder();

    // collect some extra info about the exception before logging
    foreach (var eve in ex.EntityValidationErrors)
    {
        sb.AppendLine(String.Format("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:", eve.Entry.Entity.GetType().Name, eve.Entry.State));
        foreach (var ve in eve.ValidationErrors)
        {
            sb.AppendLine(String.Format("Property: \"{0}\", Error: \"{1}\"", ve.PropertyName, ve.ErrorMessage));
        }
    }

    logger.Error("There was an error while trying to parse and save something!\n" + sb.ToString(), ex);
}

If you want the Exception.Data dictionary entries, you can add those as well:

foreach (DictionaryEntry entry in ex.Data)
{
    // you will want to use a StringBuilder instead of concatenating strings if you do this
    exceptionMessage = exceptionMessage + string.Format("Exception.Data[{0}]: {1}", entry.Key, entry.Value);
}

As for properties for Custom exception classes just as the EntityValidationErrors, I would just trap and parse those where they occur. Otherwise you would have to override ToString() on every exception type or use some reflection hackery to enumerate all the properties which would significantly clutter the logs with properties you dont care about.

Upvotes: 3

Gelootn
Gelootn

Reputation: 601

you could use elmah and the log4net appender. Elmah logs catches all exceptions and can log them to a log4net instance.

Upvotes: 0

Related Questions