Using Extension Methods for Easy Improved Logging

Posted by

Lately I’ve had to deal with legacy code that has been having issues but hasn’t been adequately been logging enough info to accurately fix an underlying issue. In this specific instance, there was a DB Validation issue, but no indication of what data was failing to validate. As a result, I came up with a handy extension method to be consistently providing me information I typically want and need. It takes an object as an input and logs the input object’s data as a JSON representation.

I ended up adding in additional functionality to also log an exception (the top level exception’s message in the log message, and the full exception as well), a note for an explicitly defined note, and a CallerMemberName, which provides the calling function name. I also decided to add in the objects name using reflection, just so I know exactly what the JSON that I am logging represents.

using Newtonsoft.Json;
using System;
using System.Runtime.CompilerServices;
using System.Text;

namespace log4net
{
    public static class ILogExtensions
    {
        public static void ErrorData(this ILog log, object obj, Exception ex = null, string note = "", [CallerMemberName] string memberName = "")
        {
            StringBuilder builder = new StringBuilder();
            if (memberName != "")
                builder.Append($"Error in function {memberName}. ");
            if(note != "")
                builder.Append($"Note: {note}. ");
            if (ex != null)
                builder.Append($"Exception: {ex.Message}, ");

            var json = JsonConvert.SerializeObject(obj,
                    Formatting.Indented,
                    new JsonSerializerSettings()
                    {
                        ReferenceLoopHandling = ReferenceLoopHandling.Ignore
                    });
            var objName = obj.GetType().Name;
            builder.Append($"Object name: {objName}, Data: {json}");
            if(ex != null)
                log.Error(builder.ToString(), ex);
            else
                log.Error(builder.ToString());
        }
    }
}

This allows me to easily log all my relevant data with a simple call:

_log.ErrorData(model, ex, "this is a test"); //Log with exception and note
_log.ErrorData(model); //Or only log the model

An example output looks like this:

Error in function SavePayment. Note: This is a test. Exception: An error occurred while updating the entries. See the inner exception for details., Object name: Payment, Data: { “id”: 25265, “customerFirstName”: “Mitch”, “customerLastName”: “Valenta”, “amount”: 100 }

I did make an extension method for each log level, with the only difference being the actual log call matching the extension method, and the log type in the “in function memberName” text.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.