How to trace every method called

27,303

Solution 1

You can do this with Unity Interception

See this article for a sample. The article uses attributes, but my code sample below use the dependency injection system (coding to an interface) to setup interception.

If you want to log MyClass, it goes something like this:

  1. Make an interface that contains all methods in MyClass => IMyClass
  2. You setup InterfaceInterception (like I've done below) OR there are a few other ways you can set it up. See here for all options.
  3. You'll setup a policy to intercept all methods that matches IMatchingRule.
  4. All calls will now be intercepted by your ICallHandler implementation.

Code:

//You  will use the code like this:
MyContainer container = new MyContainer();
//setup interception for this type..
container.SetupForInteception(typeof(IMyClass));
 //what happens here is you get a proxy class 
 //that intercepts every method call.
IMyClass cls = container.Resolve<IMyClass>();

 //You need the following for it to work:   
public class MyContainer: UnityContainer
{
    public MyContainer()
    {
        this.AddNewExtension<Interception>();
        this.RegisterType(typeof(ICallHandler), 
                    typeof(LogCallHandler), "MyCallHandler");
        this.RegisterType(typeof(IMatchingRule), 
                       typeof(AnyMatchingRule), "AnyMatchingRule");

        this.RegisterType<IMyClass, MyClass>();
    }
    //apparently there is a new way to do this part
    // http://msdn.microsoft.com/en-us/library/ff660911%28PandP.20%29.aspx

    public void SetupForInteception(Type t)
    {
        this.Configure<Interception>()
        .SetInterceptorFor(t, new InterfaceInterceptor())
        .AddPolicy("LoggingPolicy")
        .AddMatchingRule("AnyMatchingRule")
        .AddCallHandler("MyCallHandler");

    }
}
//THIS will match which methods to log.
public class AnyMatchingRule : IMatchingRule
{
    public bool Matches(MethodBase member)
    {
        return true;//this ends up loggin ALL methods.
    }
}
public class LogCallHandler : ICallHandler
{
    public IMethodReturn 
             Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
    {
      //All method calls will result in a call here FIRST.
      //IMethodInvocation has an exception property which will let you know
      //if an exception occurred during the method call.
    }
 }

Solution 2

Use a Profiler in tracing mode. Then you will see how everything does call each other and where the time is spent. Besides commercial profilers there are also free ones. For managed code there is NP Profiler which is quite good.

If you want to go deeper you can use the Windows Performance Toolkit which gives you full information accross all threads and how the interact with each other if you want to know. The only difference is that you get stacks ranging from kernel until your managed frames.

If this is not enough you can instrument your code with a tracing library (either automatically with PostSharp, ....) or manually or with a macro for each source file. I have made a little tracing library which is quite fast and highly configurable. See here. As unique feature it can trace any thrown exception automatically.

private void SomeOtherMethod()
{
  using (Tracer t = new Tracer(myType, "SomeOtherMethod"))
  {
      FaultyMethod();
  }
}

private void FaultyMethod()
{
   throw new NotImplementedException("Hi this a fault");
}

Here comes the output:

    18:57:46.665  03064/05180 <{{         > ApiChange.IntegrationTests.Diagnostics.TracingTests.SomeMethod  
    18:57:46.668  03064/05180 <{{         > ApiChange.IntegrationTests.Diagnostics.TracingTests.SomeOtherMethod  
    18:57:46.670  03064/05180 <         }}< ApiChange.IntegrationTests.Diagnostics.TracingTests.SomeOtherMethod Exception thrown: System.NotImplementedException: Hi this a fault    
at ApiChange.IntegrationTests.Diagnostics.TracingTests.FaultyMethod()  
at ApiChange.IntegrationTests.Diagnostics.TracingTests.SomeOtherMethod()  
at ApiChange.IntegrationTests.Diagnostics.TracingTests.SomeMethod()    
at ApiChange.IntegrationTests.Diagnostics.TracingTests.Demo_Show_Leaving_Trace_With_Exception() 

18:57:46.670  03064/05180 <         }}< ApiChange.IntegrationTests.Diagnostics.TracingTests.SomeOtherMethod Duration 2ms 18:57:46.689  03064/05180 <         }}< ApiChange.IntegrationTests.Diagnostics.TracingTests.SomeMethod Duration 24ms

Solution 3

PostSharp certainly offers a way to apply an aspect to several targets without decorating them with attributes explicitly. See Multicast attributes.

When developing (multicast) aspect you must specify its usage:

[MulticastAttributeUsage(MulticastTargets.Method, TargetMemberAttributes = MulticastAttributes.Instance)]
[AttributeUsage(AttributeTargets.Assembly|AttributeTargets.Class|AttributeTargets.Method, AllowMultiple = true)]
[Serializable]
public class TraceAttribute : MethodInterceptionAspect
{
// Details skipped.
}

And then apply the aspect in a way that covers your use case (eg. all public members in AdventureWorks.BusinessLayer namespace):

[assembly: Trace( AttributeTargetTypes="AdventureWorks.BusinessLayer.*", AttributeTargetMemberAttributes = MulticastAttributes.Public )]
Share:
27,303
ShaQ.Blogs
Author by

ShaQ.Blogs

Updated on February 14, 2020

Comments

  • ShaQ.Blogs
    ShaQ.Blogs over 4 years

    I have an existing project where I would like to find out all calls being made and maybe dump into a log file.

    I had a look at this thread, but didnt help much. I tried PostSharp, and the example shows how to achieve it. But I need to add an attribute to every darn method. Being an existing project, with in-numerous methods that is not a feasible option.

    Is there any other means by which I can quickly trace all calls made?

  • eyossi
    eyossi over 11 years
    I think he is trying to do that without adding an attribute to each method / class (which is different from the sample)
  • Brian Ball
    Brian Ball over 11 years
    Sounds like it requires you to create an interface for each class; that's even more work than attributes, in my opinion.
  • gideon
    gideon over 11 years
    @BrianBall yep that is true. But if you plan on using dependency injection (which is a good thing) then it's a good way to go.
  • ShaQ.Blogs
    ShaQ.Blogs over 11 years
    as wonderful as this technique is, it is of no use for me. I cant modify 1000 or more classes.
  • gideon
    gideon over 11 years
    @ShaQ.Blogs ah too bad!! I posted it because I did some serious research for months and implemented this for my company. In my searching I didn't find any other way (apart from buying one of those fancy libraries that does this for you)
  • abatishchev
    abatishchev over 11 years
    You can use regular class still, interface is not mandatory. Right? Main is condition to do not have class sealed so Unity could inherit it and create a proxy. Like EF does with POCO: no interface used at all.
  • gideon
    gideon over 9 years
    @abatishchev yes precisely.