Automatically register input and output methods with parameters?

Is there a way to add a log so that inbound and outbound methods are automatically logged along with tracking parameters? How can I do it?

I am using Log4Net.

+6
logging log4net
source share
7 answers

The best way to achieve this kind of thing is to use interception. There are several ways to do this, although all of them are usually somewhat invasive. It would be possible to derive all your objects from ContextBoundObject. Here is an example of using this approach. Another approach would be to use one of the existing AOP libraries to achieve this. Something like the DynamicProxy from the Castle Project underlies many of them. Here are some links: Spring.Net PostSharp Cecil

There are probably a few others, and I know Castle Windsor , and Ninject both provide AOP features on top of IoC functionality.

Once the AOP is in place, you simply write an interceptor class that will record the method call information in log4net.

I really would not be surprised if one of the AOP frameworks provides you with this functionality out of the box.

+4
source share

Take a look:

How to intercept method call in C #? PostSharp - il weaving - thoughts

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

+4
source share

I'm not sure what your actual needs are, but here is a low rent option. This is not entirely “automatic,” but you can use StackTrace to remove the information you are looking for in such a way as not to require passing arguments - similar to ckramer's suggestion for 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 indicate an action method, and then call the virtual member for the actual 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 is not much “automatic” here, but it will work on a limited basis if you do not require tools for each method call.

Hope this helps.

+4
source share

You can use a post compiler like Postsharp . A sample from the site talks about configuring a tracer to enter / exit a method that is very similar to what you want.

+3
source share
0
source share

You can use the open source CInject framework in CodePlex, which has a LogInjector to mark the input and output of a method call.

Or you can follow the steps mentioned in this article in Intercepting method calls using IL and create your own interceptor using the Reflection.Emit classes in C #.

0
source share

Functions

To extend Jared's answer by avoiding code repetition and including parameters 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); } 

Using

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

Exit

In the console, this will be the output if DoSomething were started with a "blah" like arg1

 Entering Program.DoSomething arguments: [blah] Executing DoSomething Exiting Program.DoSomething 
0
source share

All Articles