Application Insights provides a lot of dependency tracing automatically -- in particular, DependencyTrackingTelemetryModule is in charge of it. Among other dependency telemetry it collects all database calls which were doing using ADO.NET (basically, all which can be done via System.Data.SqlClient.).
I got curious to see how it's implemented inside and opened up IlSpy to review the internals; it was not a big surprise to see code like the below from Microsoft.ApplicationInsights.DependencyCollector.Implementation.ProfilerRuntimeInstrumentation class:
internal static void DecorateProfilerForSqlCommand(ref ProfilerSqlCommandProcessing sqlCallbacks)
{
Functions.Decorate("System.Data", "System.Data.dll", "System.Data.SqlClient.SqlCommand.ExecuteNonQuery", sqlCallbacks.OnBeginForOneParameter, sqlCallbacks.OnEndForOneParameter, sqlCallbacks.OnExceptionForOneParameter, false, true);
Functions.Decorate("System.Data", "System.Data.dll", "System.Data.SqlClient.SqlCommand.ExecuteReader", sqlCallbacks.OnBeginForOneParameter, sqlCallbacks.OnEndForOneParameter, sqlCallbacks.OnExceptionForOneParameter, false, true);
Functions.Decorate("System.Data", "System.Data.dll", "System.Data.SqlClient.SqlCommand.ExecuteReader", sqlCallbacks.OnBeginForThreeParameters, sqlCallbacks.OnEndForThreeParameters, sqlCallbacks.OnExceptionForThreeParameters, false, true);
// and others...
}
However, the deeper I dig the less I understand how it works. If we look into the Functions.Decorate implementation, we will find that it basically delegates the work to
the Microsoft.Diagnostics.Instrumentation.Extensions.Intercept.Decorator.Decorate method which internally calls Microsoft.Diagnostics.Instrumentation.Extensions.Intercept.Internal.DecoratorInternal. It then calls Microsoft.Diagnostics.Instrumentation.Extensions.Intercept.Internal.NativeMethods.Decorate.
Here is punch line. Below is the implementation of the last method that supposed (to my eye) to do the real work.
[MethodImpl(MethodImplOptions.NoInlining)]
internal static int Decorate(int methodId, long assemblyNamePtr, long moduleNamePtr, long typeNamePtr, long methodNamePtr, uint argsCount)
{
return 0;
}
So the question is -- does anyone know how this is really working?