Giannis Grivas
Giannis Grivas

Reputation: 3412

What logging system to use for methods in C#?

There is a webforms application with classes that contain lot of methods. I want to keep logs of the methods that are being called in a flexible and easy way. I want to know which method has finally been called and some other additional info like:

Currently, I am using log4net for filesystem logging like:

using log4net;
private static readonly ILog Log1 = LogManager.GetLogger("Log1");

public int DoSomething(int itemId = 0)
{
    Log1.DebugFormat("[DoSomething] - Doing Something on item {0} Started", itemId );

    try
    {
        //something..
    }
    catch (Exception ex)
    {
        Log1.Debug("[DoSomething] - Something Failed", ex);
    }

    Log1.DebugFormat("[DoSomething] - Doing Something on item {0} Finished", itemId );

    return 0;
}

How is it possible to achieve this without writing every time these pieces of code in every method? Is there a better and automatic way? What about the performance cost in every case?

An alternative approach would be great!

Upvotes: 0

Views: 107

Answers (1)

Evk
Evk

Reputation: 101633

Below code should give you a starting point. It's a sample which uses console instead of log4net, but I think it's trivial to extend it to use whatever you need.

First install PostSharp nuget package. Then define new aspect:

[Serializable]
public sealed class TraceAttribute : OnMethodBoundaryAspect
{        
    private readonly string _argumentsFormat;        
    [NonSerialized]
    private string _methodName;        

    public TraceAttribute() {

    }

    public TraceAttribute(string argumentsFormat) {
        _argumentsFormat = argumentsFormat;
    }

    public override void RuntimeInitialize(MethodBase method) {
        _methodName = method.Name;
    }

    public override void OnEntry(MethodExecutionArgs args) {
        string msg = $"[{_methodName}]: entered";
        if (!String.IsNullOrWhiteSpace(_argumentsFormat)) {
            msg += String.Format(". Arguments:" + _argumentsFormat, args.Arguments.ToArray());
        }
        Console.WriteLine(msg);
    }

    // Invoked at runtime after the target method is invoked (in a finally block).
    public override void OnExit(MethodExecutionArgs args) {
        string msg = $"[{_methodName}]: exited";
        if (!String.IsNullOrWhiteSpace(_argumentsFormat)) {
            msg += String.Format(". Arguments: " + _argumentsFormat, args.Arguments.ToArray());                
        }
        Console.WriteLine(msg);
    }

    public override void OnException(MethodExecutionArgs args) {
        string msg = $"[{_methodName}]: exception";
        if (!String.IsNullOrWhiteSpace(_argumentsFormat))
        {
            msg += String.Format(". Arguments: " + _argumentsFormat, args.Arguments.ToArray());                
        }
        msg += ". Details: " + args.Exception.ToString();
        Console.WriteLine(msg);
    }
}

What we basically do here is inheriting MethodBoundaryAspect and define what code should be executed when target method is entered, exited, and when exception is thrown. Use it like this:

public class Program {
    static void Main(string[] args) {
        TestStuff(1);
        TestStuff(2);
        TestStuff(3);
        Console.ReadKey();
    }

    [Trace("itemId: {0}")]
    static void TestStuff(int itemId) {
        Console.WriteLine("Inside TestStuff: " + itemId);
        if (itemId == 3)
            throw new Exception("Test exception");
    }
}

You can also apply that attribute to whole classes. In this case - all methods inside that class will be traced.

Upvotes: 1

Related Questions