1

When I use %l or %L in my PatternLayout for debugging, I get the location of my extension static class and the line number in that file and not the location and line of the caller. Any of the standard logging methods produce correct results. Is there a way to get the extension methods to do this?

Part of my Log4NetExtensions.cs

namespace Dashboard
{
    public static partial class Util
    {
        public static void SqlError(this ILog log, SqlException sqle)
        {
             if (log.IsDebugEnabled)
            {
                string[] names = Enum.GetNames(typeof(Dashboard.Models.Response.DashError.StandardErrors));
                int idx = Array.IndexOf(names, sqle.Message);
                if (idx > 0)
                {
                    log.Debug(sqle.Message);
                }
                else
                {
                    log.Error(sqle);
                }
            }
            else
            {
                log.Error(sqle);
            }
        }
    }
}

Edit: Per wageoghe's answer, I changed the log.Error() and log.Debug to this but it still prints Util and not the caller:

log.Logger.Log(typeof(Util), Level.Error, sqle.Message, sqle);
kyle
  • 268
  • 6
  • 18
  • Can you please add the code for your extension method here? – Chris Missal Mar 07 '14 at 17:38
  • I updated my answer to contain an example of an extension method that does maintain the correct call site info. I don't know if it will help you are not since you've gone with a wrapper, but I thought I would pass it along. – wageoghe Mar 07 '14 at 23:12

1 Answers1

1

See this answer to another question here on SO for how to maintain call site information when wrapping log4net.

how to log method name when using wrapper class with Log4net

Even though you are writing an extension method, you are essentially wrapping log4net. The technique described in that answer should work for an extension method as well as it does for a wrapper. The solution for you should be to use the Log method rather than Info, Error, etc inside your wrapper. As the first parameter to the Log method, send the type of your extension method static class.

Your extension method will look something like this (not compiled or tested):

namespace Dashboard
{
    public static partial class Util
    {
        public static void SqlError(this ILog log, SqlException sqle)
        {
             if (log.IsDebugEnabled)
            {
                string[] names = Enum.GetNames(typeof(Dashboard.Models.Response.DashError.StandardErrors));
                int idx = Array.IndexOf(names, sqle.Message);
                if (idx > 0)
                {
                    //Note that I am using the Logger member and then calling the Log method it.
                    log.Logger.Log(typeof(Util), LogLevel.Debug, sqle.Message, null);
                }
                else
                {
                    //Not sure about this call because you want to log only the exception.  Don't
                    //know if log4net will accept null as "message" parameter.
                    log.Logger.Log(typeof(Util), LogLevel.Error, null, sqle);
                }
            }
            else
            {
                //Not sure about this call because you want to log only the exception.  Don't
                //know if log4net will accept null as "message" parameter.
                log.Logger.Log(typeof(Util), LogLevel.Error, null, sqle);
            }
        }
    }
}

If it doesn't work exactly right, I think you will get the idea.

UPDATE

FWIW, I put together this little sample and it logs the desired method (Main) for the call site using an extension method:

  class Program
  {
    static void Main(string[] args)
    {
      var logger = LogManager.GetLogger("abc");
      ILogger ilog = logger.Logger;

      logger.Info("Hello");
      logger.InfoExt("Hello2");
    }
  }

  public static class Extensions
  {
    public static void InfoExt(this ILog logger, string message)
    {
      logger.Logger.Log(typeof(Extensions), Level.Info, message, null);
    }
  }
Community
  • 1
  • 1
wageoghe
  • 27,390
  • 13
  • 88
  • 116
  • That's too bad. I would have expected that to work. Unfortunately, I don't have time to fool around with it right now to try to figure out what is going on. – wageoghe Mar 07 '14 at 19:18
  • The wrapper class does work. I was trying to avoid that much refactoring. – kyle Mar 07 '14 at 19:34
  • Marking as the answer. May be a way to do this with extensions, but I created a wrapper class. Since I was using the extensions almost exclusively, moving them to the wrapper class and removing "this ILog" and static was much easier than I thought it would be. – kyle Mar 07 '14 at 20:31