I have added custom tracing to my app by doing the following inside methods which I would like information about:
public static void MyMethod(params)
{
pathTrace += "MyMethod(" + params + "){";
// Some method calls and calculations etc ...
pathTrace += INTERESTINGOUTPUT + "}";
}
The pathTrace string is then sent to the database once the user journey has ended, containing all the methods I am interested in along with params and output, in a nice readable format.
This seems ugly, however, as I have to add the pathTrace incrementers to every method ...
Can anyone suggest a way that I can write a method which adds this for me (including params and output and brackets if possible), so that I can perhaps call it like this:
public static void MyMethd(params)
{
pathTrace();
// Some method calls and calculations etc ...
}
I would ideally like the start and end brackets included (I feel like this is the difficult part) ...
Any advice is much appreciated! Thanks
If you called it the way you're asking for, you'd have to examine the stack trace to find the calling method's name and do a lot of reflection to collect runtime argument info, and at substantial cost. You certainly couldn't leave the calls in situ.
You can avoid most of that cost by passing somewhat redundant information (such as the current method name) to your tracing stuff. I've done something similar, so that I can "instrument" the body of a method with a tracing wrapper. Calls might look like:
static void DoSomeMethod( )
{
Tracer.TraceRun( "DoSomeMethod", ( ) =>
{
//--> body of method...
var x = DoSomeFunction( );
} );
}
static int DoSomeFunction( )
{
return Tracer.TraceRun( "DoSomeFunction", ( ) =>
{
//--> body of method...
return 9 - DoSomeFunctionWithArgs( 3 );
} );
}
static int DoSomeFunctionWithArgs( int arg )
{
return Tracer.TraceRun( "DoSomeFunctionWithArgs", ( ) =>
{
//--> body of method...
return 1 + arg;
}, arg );
}
...where the expected output of running DoSomeMethod()
would be:
DoSomeMethod(){
DoSomeFunction(){
DoSomeFunctionWithArgs(3){
4}
5}
}
To make this work, the Tracer.TraceRun
is overloaded, so that I can do methods and functions:
class Tracer
{
[ThreadStatic]
private static int depth = 0;
public static void TraceRun( string name, Action method, params object[ ] args )
{
TraceStartCall( name, args );
depth++;
method( );
TraceEndCall( );
depth--;
}
public static T TraceRun<T>( string name, Func<T> function, params object[ ] args )
{
TraceStartCall( name, args );
depth++;
var results = function( );
TraceEndCall( results );
depth--;
return results;
}
private static void TraceStartCall( string functionName, params object[ ] args )
{
Trace.WriteLine
(
string.Format
(
"{0}: {1}{2}({3}){{",
Thread.CurrentThread.ManagedThreadId,
new string( ' ', depth ),
functionName,
args == null ?
string.Empty :
string.Join( ", ", Array.ConvertAll( args, i => i.ToString( ) ).ToArray( ) )
)
);
}
private static void TraceEndCall( object results = null )
{
Trace.WriteLine
(
string.Format
(
"{0}: {1}{2}}}",
Thread.CurrentThread.ManagedThreadId,
new string( ' ', depth ),
results
)
);
}
}
This code deals with thread-management issues the cheap-and-easy way...by just outputting the threadId so that you can see how your threads interoperate (and marking Tracer's depth with ThreadStatic). The output looked like this when I ran it:
10: DoSomeMethod(){
10: DoSomeFunction(){
10: DoSomeFunctionWithArgs(3){
10: 4}
10: 5}
10: }