Monday, August 21, 2017

Easy Plug-in Logging Using IL-Weaving

So what is IL-weaving or Aspect Oriented Programming (AOP)? At a high level, it’s the process of "magically" injecting additional code into what you’ve written at some point during the assembly’s life cycle. But why the need? Using an automated and repeatable process to examine the code that’s written and add to it can be beneficial because it’s less code the developer has to write in the first place (so less potential mistakes) and can also address things the developer forgot (like disposing of objects). For the purposes of this post I’m not going to get into the specifics on how any of the techniques work under the hood, but if you’re interested in more detail on these processes you can read more about approaches in .NET, run-time weaving and compile-time weaving.

The example I’m going to run through stems from something that happened a few months ago and how injecting code would have made dealing with the situation easier.

Scenario, things are processing slower than the client would like. There are plug-ins, lots of plug-ins. Those plug-ins fire other plug-ins which fire other plug-ins. Also everything is running synchronously. When reviewing the code the plug-ins are quite complex. It’s fairly clear there are extra executions happening that shouldn’t be but based on the amount, complexity, and state of the code it’s hard to tell where to begin looking. My colleagues I was working with decide to add some timers to the methods that are most likely the ones that are the root of the problem to see where the bottlenecks are. The result was adding Stopwatch code to the beginning and end of methods all over the place. Not terribly difficult, just time consuming and messy when done in mass.

Well after the fact I ran across this notion of AOP and saw an example of dynamically injecting this Stopwatch code without having to actually write it. To demonstrate I’m using the open source library Fody (specially MethodTimer) which uses compile-time weaving to inject the Stopwatch code.

Walking through the example:

ManualTimer method: This might be what your code would look like when you add Stopwatches to each method’s execution today. While I'm sure you could probably simplify this some, there are still many extra lines of code.

IlWeavngTimer method: This produces the same result only by adding an attribute to the method. There is some code to support this. Toward the end there are 2 internal classes, one for the attribute and one for the actual logger. In the Execute method of the plug-in I’ve created a static instance of the logger and gave it the CRM Tracing Service to write to.

IlWeavngTimerCompiled method: If you decompile the assembly, this is what actually ended up being compiled. As you can see it added the Stopwatch code around my existing code.

The process of adding code is done during the build process and doesn’t take any dependencies on any third-party libraries – so it’s safe for CRM/D365 Online. The 2 internal support classes are also removed in the compiled assembly – assuming you’ve designated them internal.

Now for every method you want to time execution on you can simply add the [Time] attribute (including Execute) and it will write the execution time to the plug-in trace log.

You can see the full solution here: