4

I created a c# wrapper for log4net.

It has Debug() and Error() methods.

I want to log the method name which logs the record, but If I try to use the %method conversion pattern, it just prints Debug, which is the wrapper method name.

Is there a way to print the full method stack?

E.g.

Instead of Debug --> SomeLoggingActionInSomeClass.Debug?

Wrapper class code:

public static class Logger
{
    private static ILog _log;

    static Logger()
    {
        log4net.Config.XmlConfigurator.Configure();

        _log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
    }

    public static void Init()
    {
    }

    public static void Debug(string message)
    {
        _log.Debug(message);
    }

Calling Class Code:

W6CustomizationLogger.Logger.Debug("Backup(): START");
Y.S
  • 1,860
  • 3
  • 17
  • 30
  • Where do you declare your log4net logger ? in you calling class or in your wrapper ? Also please include snippet of your code, to show how you want to use it :) – Dietz Aug 12 '15 at 06:19
  • I declare it in my wrapper, will add code snippet – Y.S Aug 12 '15 at 06:43
  • I removed my answer after you edited the question as I now see it was irrelevant. It's not an exact duplicate, but this might help: http://stackoverflow.com/q/157232/3887516 – Amit Aug 12 '15 at 07:21
  • Seems like your wrapper is hiding the information. Your problem might be related to: http://stackoverflow.com/questions/2049992/when-using-wrapper-how-to-preserve-class-and-method-name-for-log4net-to-log?rq=1 – Dietz Aug 12 '15 at 07:23

2 Answers2

6

Scrap that wrapper.

Configuration

To initialize logging you can instead configure it quite easily in your startup project.

  1. Click on the arrow next to your "Properties" on your startup project in Solution explorer
  2. Double click on assembly info

enter image description here

3 Add the following:
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]

Screenshot:

enter image description here

Usage

Now in your classes simply add:

public class YourClass
{
    private ILog _logger = LogManager.GetLogger(typeof(YourClass));

    // [....]
}

And in your log4net.config you can now use the logger property in the output:

<layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date %-7level %-40logger %message%newline" />
</layout>

Which will print the namespace and type name on every log line (-7 and -40 pads the names so that I get straight columns).

The other great thing is that you can also use a filter on the namespace (to make all database classes log to "databases.log" etc).

<appender name="DatabaseAppender" type="log4net.Appender.RollingFileAppender">
  <file value="C:\Logs\MyApp\Database.log" />
  <rollingStyle value="Composite" />
  <datePattern value=".yyyy-MM-dd'.log'" />
  <appendToFile value="true" />
  <maximumFileSize value="50MB" />
  <maxSizeRollBackups value="5" />
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date %level@%thread [%logger] %message%newline" />
  </layout>

  <!-- Namespace/Type filter -->
  <filter type="log4net.Filter.LoggerMatchFilter">
    <loggerToMatch value="CompanyName.DatabaseNamespace"/>
  </filter>
  <filter type="log4net.Filter.DenyAllFilter" />
</appender>

You can also use %type{1} instead if %logger to get only the class name.

Aage
  • 5,932
  • 2
  • 32
  • 57
jgauffin
  • 99,844
  • 45
  • 235
  • 372
  • Thanks a lot for the detailed explanation! I will try it and let you know if it resolves my issue. – Y.S Aug 12 '15 at 11:36
2

If you really must use a wrapper class, then the best way is to get the calling method in the wrapper and then store that as a property:

var stackFrames = new StackTrace().GetFrames();
var callingframe = stackFrames.ElementAt(1);
var method = callingframe .GetMethod().Name;

// Store in log4net ThreadContext:
ThreadContext.Properties["method"] = method;

Then in the layout reference the property:

<conversionPattern value = ""Method: %property{method}"" />

There is also a way to resolve this just using the layout, you would use %stacktrace in your layout to get the call stack, specifically %stacktrace{2} to get the calling method.

Note that when you use this, the whole stack is logged, including the wrapper method.

Example output:

log4net.Tests.Stacktrace_Tests.StackTrace_In_PatternLayout > log4net.Tests.Wrapper.Debug

stuartd
  • 70,509
  • 14
  • 132
  • 163