Logging entry and exit of methods along with param

2019-02-09 05:39发布

Is there a way for me to add logging so that entering and exiting methods gets logged along with parameters automatically somehow for tracing purposes? How would I do so?

I am using Log4Net.

7条回答
老娘就宠你
2楼-- · 2019-02-09 06:01

Functions

To expand on Jared's answer, avoiding code repetition and including options for arguments:

private static void LogEnterExit(bool isEnter = true, params object[] args)
{
    StackTrace trace = new StackTrace(true);  // need `true` for getting file and line info
    if (trace.FrameCount > 2)
    {
        string ns = trace.GetFrame(2).GetMethod().DeclaringType.Namespace;
        string typeName = trace.GetFrame(2).GetMethod().DeclaringType.Name;
        string args_string = args.Length == 0 ? "" : "\narguments: [" + args.Aggregate((current, next) => string.Format("{0},{1};", current, next))+"]";
        Console.WriteLine("{0} {1}.{2}.{3}{4}", isEnter ? "Entering" : "Exiting", ns, typeName, trace.GetFrame(2).GetMethod().Name, args_string );
    }
}

static void LogEnter(params object[] args)
{
    LogEnterExit(true, args);
}

static void LogExit(params object[] args)
{
    LogEnterExit(false, args);
}

Usage

static void DoSomething(string arg1)
{
    LogEnter(arg1);
    Console.WriteLine("Executing DoSomething");
    LogExit();
}

Output

In the console, this would be the output if DoSomething were run with "blah" as arg1

Entering Program.DoSomething
arguments: [blah]
Executing DoSomething
Exiting Program.DoSomething
查看更多
趁早两清
3楼-- · 2019-02-09 06:08
Viruses.
4楼-- · 2019-02-09 06:09

You could use a post-compiler like Postsharp. The sample from the website talks about setting up a tracer for entering/exiting a method, which is very similar to what you want.

查看更多
Melony?
5楼-- · 2019-02-09 06:14

I'm not sure what your actual needs are, but here's a low-rent option. It's not exactly "automatic", but you could use StackTrace to peel off the information you're looking for in a manner that wouldn't demand passing arguments - similar to ckramer's suggestion regarding interception:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Diagnostics;

namespace TracingSample
{
    class Program
    {
        static void Main(string[] args)
        {
            DoSomething();
        }

        static void DoSomething()
        {
            LogEnter();

            Console.WriteLine("Executing DoSomething");

            LogExit();
        }

        static void LogEnter()
        {
            StackTrace trace = new StackTrace();
            if (trace.FrameCount > 1)
            {
                string ns = trace.GetFrame(1).GetMethod().DeclaringType.Namespace;
                string typeName = trace.GetFrame(1).GetMethod().DeclaringType.Name;
                Console.WriteLine("Entering {0}.{1}.{2}", ns, typeName, trace.GetFrame(1).GetMethod().Name);
            }
        }

        static void LogExit()
        {
            StackTrace trace = new StackTrace();
            if (trace.FrameCount > 1)
            {
                string ns = trace.GetFrame(1).GetMethod().DeclaringType.Namespace;
                string typeName = trace.GetFrame(1).GetMethod().DeclaringType.Name;
                Console.WriteLine("Exiting {0}.{1}.{2}", ns, typeName, trace.GetFrame(1).GetMethod().Name);
            }
        }
    }
}

You could combine something like the above example with inheritance, using a non-virtual public member in the base type to signify the action method, then calling a virtual member to actually do the work:

public abstract class BaseType
{
    public void SomeFunction()
    {

        LogEnter();
        DoSomeFunction();
        LogExit();
    }

    public abstract void DoSomeFunction();
}

public class SubType : BaseType
{
    public override void DoSomeFunction()
    {
        // Implementation of SomeFunction logic here...
    }
}

Again - there's not much "automatic" about this, but it would work on a limited basis if you didn't require instrumentation on every single method invocation.

Hope this helps.

查看更多
放我归山
6楼-- · 2019-02-09 06:22

The best way to achieve this sort of thing is by using interception, There are a couple of ways to do this, though they all tend to be somewhat invasive. One would be to derive all your objects from ContextBoundObject. Here is an example of using this sort of approach. The other approach would be to use one of the existing AOP libraries to achieve this. Something like DynamicProxy from the Castle Project is at the core of many of these. Here are a few links: Spring.Net PostSharp Cecil

There are probably several others, and I know Castle Windsor, and Ninject both provide AOP capabilities on top of the IoC functionality.

Once AOP is in place you would simply write an interceptor class that would write the information about the method calls out to log4net.

I actually wouldn't be surprised if one of the AOP frameworks would give you that sort of functionality out of the box.

查看更多
ゆ 、 Hurt°
7楼-- · 2019-02-09 06:26

Have a look at:

How do I intercept a method call in C#? PostSharp - il weaving - thoughts

Also search SO for 'AOP' or 'Aspect Oriented Programming' and PostSharp...you get some interesting results.

查看更多
登录 后发表回答