Reputation: 45911
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
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
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