Tuesday, April 15, 2008 3:47 PM Marc Jacobi

Trace Context Aspects with PostSharp

In my previous post I wrote about a method context information gathering framework I wrote in an attempt to increase the amount of useful information in trace output and exceptions. In this final post about the framework I will discuss the use of a static aspect weaver PostSharp.

Static Aspect Weaving

I assume that you know what aspects are at least at a conceptual level. The nice thing about static aspects is that their code is injected at compile time, not at runtime. True: static aspects are not configurable, but they are completely transparent (dynamic aspects usually require the client code to create a proxy instead of the actual object).

I use PostSharp, a static aspect weaver, to implement a code attribute that triggers aspect code injection into the assembly. PostSharp works at IL level so it should be usable with any .NET language. While PostSharp provides a generic assembly manipulation framework, it is actually Laos that provides the aspect framework.

When an aspect (a code attribute) is applied to a method, PostSharp (actually Laos) rewrites the IL for that method. It basically relocates the original method IL in a new method with the same name, prefixed by a '~'. Then it inserts custom IL that performs the call sequence on your aspect object. Your aspect can be responsible for calling the actual method -using a delegate- (as it is in this example), although there are also flavors of aspects that do not require this.

So a typical (simplified) call stack would look something like this:

void MyClass.MyMethod(string param1)
void MyAspect.OnInvocation(MethodInvocationEventArgs eventArgs)
void delegate.DynamicInvoke(object[] parameters)

void MyClass.~MyMethod(string param1)

The stubbed MyClass.MyMethod routes execution to the aspect (OnInvocation) applied to the method and the aspect code invokes the delegate that point to the original method (or it doesn't ;-) and the original method (prefixed with ~) executes.

TraceContextAspect

In order to eliminate the custom code you'd have to write to use the TraceContext in our method context information gathering framework, I've created a PostSharp/Laos aspect class that intercepts the method call as described above. So instead of making all the calls to the TraceContext yourself in the method code, you simply apply the aspect to the method:

[TraceContextAspect]
public string PrintName(int numberOfTimes)
{
    // method impl.
}

The TraceContextAspect implements the OnInvocation method like so:

using (AspectTraceContext ctx = new AspectTraceContext(_methodBase))
{
    ctx.Initialize(eventArgs.Delegate.Target);
    AddParameters(ctx, eventArgs.GetArguments());
    ctx.TraceMethodEntry();

    try
    {
        eventArgs.ReturnValue = eventArgs.Delegate.DynamicInvoke(eventArgs.GetArguments());

        ctx.SetReturnValue(eventArgs.ReturnValue);
    }
    catch (Exception e)
    {
        ctx.AddContextTo(e);
        throw;
    }
} // maintains stack and writes method exit and flushes writer.

Note that I've derived a new class from TraceContext for this specific situation (AspectTraceContext) that takes a MethodBase instance as a parameter in its constructor. The MethodBase instance is handed to you by the PostSharp/Laos framework and represent the method the aspect was placed on. The bold text is the actual call to the original method. As you can see, all the custom code needed to setup the TraceContext has now moved to the OnInvocation method implementation.

Conclusion

The use of a static aspect weaver has dramatically simplified the usage of the method context information gathering framework. Tracing useful and rich information from your method has now become a breeze (as it should be ;-).

I hope these last 3 post has shown you how you can leverage existing technology (System.Diagnostics and PostSharp) to make the most out your own tracing framework (in this case). I also hope you will be inspired to find new applications to use static aspects in your own code. I find that static aspects can really make your life easier while at the same time not making your code (execution paths) more complicated than needed.

You can download the source code here.

# re: Trace Context Aspects with PostSharp

Wednesday, April 16, 2008 6:10 PM by Remco

Marc,

What is your experience in regards to stabillity and robustness of this solution? what happens when an aspect is buggy? this is critical behavior, when you sprinkle all these aspects accross your classes ...

# re: Trace Context Aspects with PostSharp

Thursday, April 17, 2008 11:46 AM by Marc Jacobi

Remco,

First of all my *experience* is very limited because I just started using static aspects.

But I think it is safe to say that static aspects are no less-robust or stable than ordanary custom code. This means it is up to the aspect writer to make it stable and robust. If you now use, say, a static helper class to do your tracing, that would be no different. That static helper class would need to be just as stable and robust as the aspect should be.

The nice thing about static aspects is that you can debug them just as you would 'normal' code. Also, static aspects will not change once compiled into your code (as is possible with dynamic aspect weavers). That means you can make unit-test to verify the aspect's behavior, although in some cases -depending on the aspect behavior- this could be a little difficult.

In my opinion static aspects are the most relyable and predictable type of aspects to use and they are completly transparent to the calling code.

# re: Trace Context Aspects with PostSharp

Thursday, April 17, 2008 1:05 PM by Remco

Then, would you advise using them to a customer?

# re: Trace Context Aspects with PostSharp

Sunday, April 20, 2008 9:18 PM by Marc Jacobi

Yes, in a sense that I would advice them to the project team that is working for that customer ;-)

I mean, I would not burdon the customer with these details unless they are very technical and can understand what the hell I'm talking about.

Leave a Comment

(required) 
(required) 
(optional)
(required)