Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Log method entry and exit in .NET using NLog

Tags:

c#

asp.net

nlog

I want to log method entry and exit using NLog. I found two approaches. First one, using PostSharp,but it needs to be purchased. Second approach,using unity,But we can implement it only on methods having interfaces.

For example, I have one controller called,SampleController

SampleController.cs

 public string Get()
        {
            BusinessLayerClass businessLayer = new BusinessLayerClass();
            return businessLayer.BusinessLayerMethod();
        }

BusinessLayerClass.cs

public class BusinessLayerClass
    {
        public string BusinessLayerMethod()
        {
            DataLayerClass dataLayerClass = new DataLayerClass();
           return  dataLayerClass.DataLayerMethod();
        }
    }

DataLayerClass.cs

public class DataLayerClass
    {
        public string DataLayerMethod()
        {
            return "Hi";
        }
    }

I have two classes BusinessLayerClass and DataLayerClass.Get method in the sample controller calls BusinessLayerMethod in the BusinessLayerClass and from which DataLayerMethod was called. I have a NLogging class for logging purpose

NLogging.cs

public static class NLogging
    {
        public static bool Enabled
        {
            get { return LogManager.IsLoggingEnabled(); }
            set
            {
                if (value)
                {
                    while (!Enabled) LogManager.EnableLogging();
                }
                else
                {
                    while (Enabled) LogManager.DisableLogging();
                }
            }
        }

        public static void Fatal(string message, Exception exception = null, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMember = "", [CallerLineNumber] int callerLine = 0)
        {
            Log(LogLevel.Fatal, message, exception, callerPath, callerMember, callerLine);
        }
        public static void Trace(string message, Exception exception = null, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMember = "", [CallerLineNumber] int callerLine = 0)
        {
            Log(LogLevel.Trace, message, exception, callerPath, callerMember, callerLine);
        }

        public static void Debug(string message, Exception exception = null, [CallerFilePathAttribute] string callerPath = "", [CallerMemberName] string callerMember = "", [CallerLineNumber] int callerLine = 0)
        {
            Log(LogLevel.Debug, message, exception, callerPath, callerMember, callerLine);
        }

        public static void Info(string message, Exception exception = null, [CallerFilePathAttribute] string callerPath = "", [CallerMemberName] string callerMember = "", [CallerLineNumber] int callerLine = 0)
        {
            Log(LogLevel.Info, message, exception, callerPath, callerMember, callerLine);
        }

        public static void Warn(string message, Exception exception = null, [CallerFilePathAttribute] string callerPath = "", [CallerMemberName] string callerMember = "", [CallerLineNumber] int callerLine = 0)
        {
            Log(LogLevel.Warn, message, exception, callerPath, callerMember, callerLine);
        }

        public static void Error(string message, Exception exception = null, [CallerFilePathAttribute] string callerPath = "", [CallerMemberName] string callerMember = "", [CallerLineNumber] int callerLine = 0)
        {
            Log(LogLevel.Error, message, exception, callerPath, callerMember, callerLine);
        }

        private static void Log(LogLevel level, string message, Exception exception = null, string callerPath = "", string callerMember = "", int callerLine = 0)
        {
            LogManager.ThrowExceptions = true;
            var logger = LogManager.GetLogger(callerPath);

            if (!logger.IsEnabled(level)) return;

            var logEvent = new LogEventInfo(level, callerPath, message) { Exception = exception };
            logEvent.Properties.Add("callerpath", callerPath);
            logEvent.Properties.Add("callermember", callerMember);
            logEvent.Properties.Add("callerline", callerLine);

            logger.Log(logEvent);
        }
    }

I cannot use Unity here, since BusinessLayerClass and DataLayerClass don't implement interfaces.

Calling NLogging.Trace(methodname) in every method will be inconvenient. For example If I change my method name, I need to change the logging code also, like NLogging.Trace("Entered into ModifiedBusinessLayerMethod").

Is there any other way to log method entry and exit without using these two approaches?

like image 381
Kesiya Abraham Avatar asked Jul 12 '16 10:07

Kesiya Abraham


2 Answers

You could use a Fody and the MethodDecorator.Fody add-in. Fody is an free open-source code weaving library.

How to set-up:

1. Install package

PM> Install-Package MethodDecorator.Fody

2. Decorate the method

public class BusinessLayerClass
    {
        [LogMethod] 
        public string BusinessLayerMethod()
        {
            DataLayerClass dataLayerClass = new DataLayerClass();
           return  dataLayerClass.DataLayerMethod();
        }
    }

3. Write the interceptor

 using System;
 using System.Reflection;

[module: LogMethod] // Atribute should be "registered" by adding as module or assembly custom attribute

// Any attribute which provides OnEntry/OnExit/OnException with proper args
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Assembly | AttributeTargets.Module)]
public class LogMethodAttribute : Attribute, IMethodDecorator
{
    private MethodBase _method;
    // instance, method and args can be captured here and stored in attribute instance fields
    // for future usage in OnEntry/OnExit/OnException
    public void Init(object instance, MethodBase method, object[] args)
    {
        _method = method;
    }
    public void OnEntry()
    {
        NLogging.Trace("Entering into {0}", _method.Name);
    }

    public void OnExit()
    {
        NLogging.Trace("Exiting into {0}", _method.Name);
    }

    public void OnException(Exception exception)
    {
        NLogging.Trace(exception, "Exception {0}", _method.Name);
    }
}
like image 52
Julian Avatar answered Oct 18 '22 10:10

Julian


Use Tracer for Fody

It is highly configurable and gives you immediate results without forcing you to decorate your code. You can auto-log every single method call or exercise fine-grained control with explicit inclusion and exclusion of particular classes and methods.

https://github.com/csnemes/tracer

For most situations, the other suggested answers are too complicated and time-consuming compared to the elegance afforded by Tracer.

like image 44
JamesHoux Avatar answered Oct 18 '22 09:10

JamesHoux