5

I typically declare the following in every class:

private static readonly log4net.ILog log = log4net.LogManager.GetLogger(
            System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

and use the static member within each class to log at different levels (info, debug, etc.)

I saw that somewhere and have been using it somewhat mindlessly, reasoning that the setup is flexible enough to help me filter by namespace and log individual types if I wanted to in troubleshooting production issues and what not.

But I've rarely had to use that "level" of fine logging. So, I would like to see what others are using. Do you use the above, as I have a feeling many are using just that, or do you create named loggers such as "debug", "trace", "error", "moduleA", etc. and share the logger among different types, assemblies?

mmmmmm
  • 32,227
  • 27
  • 88
  • 117
Jiho Han
  • 1,610
  • 1
  • 19
  • 41

4 Answers4

11

I basically use

public class MyClass
{
    private static readonly ILog log = Log.Get<MyClass>();
}

where Log.Get is a class that basically does this internally

return LogManager.GetLogger(typeof(T));

The startup cost is even smaller than the reflection way as well as cleaner imo.

Update: given my experience in later years with dependency injection, unit testing and fakes, I can no longer say that I condone the approach outlined above. The problem with the approach (both mine and that of the OP) is that the code have explicit knowledge about how the log instance is created.

One one side, this increased coupling makes it harder to test: there is no easy way of replacing the ILog instance with a fake one. On another side, changes made to my Log class will cause changes to ripple throughout all classes that uses it.

I therefore go the route of injecting the ILog instance, usually via constructor injection, and outsource the how to construct a logger to my DI framework of choice:

public class MyClass
{
    readonly ILog _log;

    public class MyClass(ILog log)
    {
        _log = log;
    }
}

This allows for proper decoupling. The code no longer need to know how loggers are constructed. Most dependency injection frameworks have means of looking at the type being injected and then using that to construct the log instance. Here's an approach for log4net and Autofac.

Community
  • 1
  • 1
Peter Lillevold
  • 33,668
  • 7
  • 97
  • 131
  • what benefit does this give over using `LogManager.GetLogger(typeof(MyClass))` when getting the `ILog` instance? – MarioVW Feb 01 '13 at 23:58
  • 1
    Shorter, cleaner code. But I should revise this answer because nowadays, I use dependency injection and let the DI framework construct the logger. – Peter Lillevold Feb 02 '13 at 16:09
2

The cost of doing it your original way is an instance of the ILog implementation and the time it takes to run "System.Reflection.MethodBase.GetCurrentMethod().DeclaringType" at startup.

I remember looking into it a few years back, and our startup cost was on the order of 1 second per 10000 classes, and less than a megabyte per 10k classes.

Given such a low cost, I've never looked back given the incredibe flexibility log4net provides.

Note: I can't comment on the other solution here as I'm new.. but this line:

method = new System.Diagnostics.StackTrace().GetFrame(1).GetMethod();

Is expensive, especially if called for every log message.

Peter Drier
  • 1,327
  • 1
  • 11
  • 11
0

A tool you can use with logging is PostSharp (http://www.postsharp.org/). There is a paid and a free (Express) version. I have only used it to log method boundaries, but I know you can also use it for error-handling. Between the two, that would take care of most of your logging needs without writing code in each class.

Xavier Poinas
  • 19,377
  • 14
  • 63
  • 95
Les
  • 3,150
  • 4
  • 29
  • 41
-1

Lately, i created something like this:

public static class Logger
{
    private static bool isLoaded = false;       

    public static ILog Log
    {
        get
        {
            System.Reflection.MethodBase method;
            method = new System.Diagnostics.StackTrace().GetFrame(1).GetMethod();
            StringBuilder loggerName = new StringBuilder();
            loggerName.AppendFormat("{0}.{1}(", method.ReflectedType.FullName, method.Name);

            ParameterInfo[] parameters = method.GetParameters();
            string[] parametersStr = new string[parameters.Length];

            if (parameters.Length > 0)
            {
                for (int i = 0; i < parameters.Length; i++)
                {
                    parametersStr[i] = parameters[i].ToString();
                }
                loggerName.Append(String.Join(", ", parametersStr));
            }

            loggerName.Append(")");

            return GetLogger(loggerName.ToString());
        }
    }


    private static ILog GetLogger(string loggerName)
    {
        if (!isLoaded)
        {
            log4net.Config.XmlConfigurator.Configure();
        }
        return LogManager.GetLogger(loggerName);
    }
}

it lets me use log4net without creating its instance in every class i need to use it, and i still get class name and method where i logged the action.

Sample usage:

Logger.Log.DebugFormat("Response [{0}]", xmlResponse);
empi
  • 15,755
  • 8
  • 62
  • 78
  • 2
    Have you run a profiler on this? The execution speed of this beast is huge. And even if you wanted to turn of the DEBUG logging level in production you will incur the same cost. I can somewhat see the point if you really need the method name in the logger but then again, when e.g. exceptions occur you would get that name in the exception stacktrace anyway... – Peter Lillevold May 19 '09 at 16:28
  • 1
    Pretty sure this is superseded by the newish CallerName attribute - see http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.callermembernameattribute%28v=vs.110%29.aspx – keithl8041 May 13 '14 at 20:00