How to Add a Trace() to Every Method Call in C#

How can I add a Trace() to every method call in C#?

Probably your best bet would be to use an AOP (aspect oriented programming) framework to automatically call tracing code before and after a method execution. A popular choice for AOP and .NET is PostSharp.

Trace all method calls in ASP.NET application

You might want to look at ANTS Profiler. It can give you line by line execution time and has an option to do .NET framework code as well as your own.

C#.NET-3.5 - Creating a Custom, Readable Trace Method Which Includes Params and Output

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: }

How to trace all methods in an application

The only practical option to implement this I know of is to use AOP (like postsharp) - for a nice walkthrough see here.

How can I tracing method call following the ordering?

Here is a class provides that functionality:

class Scope : IDisposable
{
Action<string> _logger;
string _memberName;

public Scope(Action<string> logger, [CallerMemberName] string memberName = "N/A")
{
if (logger == null) throw new ArgumentNullException();

_logger = logger;
_memberName = memberName;

_logger(string.Format("Entered {0}", _memberName));
}

public void Dispose()
{
_logger(string.Format("Exited {0}", _memberName));
}
}

And to use it:

static void MyMethod()
{
using (new Scope(s => Console.WriteLine(s)))
{
// boddy
}
}

Note: If you use previous versions of C# that does not support [CallerMemberName] attribute, you have to provide memberName explicitly.

Also you can use this helper class that I use myself in version prior to .NET 4.5:

public static class Here
{
public static string Spot(HereOptions options)
{
return MakeMessageInternals(options, 3);
}

public static string Type
{
get
{
return MakeMessageInternals(HereOptions.Type, 3);
}
}

public static string Member
{
get
{
return MakeMessageInternals(HereOptions.Member, 3);
}
}

public static string FileLine
{
get
{
return MakeMessageInternals(HereOptions.FileLine, 3);
}
}

public static string FileName
{
get
{
return MakeMessageInternals(HereOptions.FileName, 3);
}
}

static StackFrame GetCaller(int index) { return new StackTrace(true).GetFrame(index); }

static string MakeMessageInternals(HereOptions options, int index)
{
StackFrame first = null;
var _FileName = new StringBuilder();
var _FileLine = new StringBuilder();
var _Member = new StringBuilder();
var _Type = new StringBuilder();

if ((options & HereOptions.FileName) == HereOptions.FileName)
{
first = GetCaller(index);
if (first != null)
{
var fn = first.GetFileName();
if (!string.IsNullOrEmpty(fn))
_FileName.Append(" " + Path.GetFileName(fn));
}
}

if ((options & HereOptions.FileLine) == HereOptions.FileLine)
{
if (first == null)
first = GetCaller(index);
if (first != null)
{
var ln = first.GetFileLineNumber();
_FileLine.Append(" #" + ln);
}
}

if ((options & HereOptions.Member) == HereOptions.Member)
{
if (first == null)
first = GetCaller(index);
if (first != null)
{
var mn = first.GetMethod().Name;
_Member.Append(" " + mn);
}
}

if ((options & HereOptions.Type) == HereOptions.Type)
{
if (first == null)
first = GetCaller(index);
if (first != null)
{
var dt = first.GetMethod().DeclaringType;
_Type.Append(string.Format(" ({0})", dt));
}
}

var messageInternal = string.Format("{0}{1}{2}{3}",
_FileName,
_FileLine,
_Member,
_Type).Trim();

return messageInternal;
}
}

[Flags]
public enum HereOptions : byte
{
None = 0,
FileName = 1,
FileLine = 2,
Member = 4,
Type = 8,
All = 15
}

How to get current method call trace? including Filepaths and Code Line Numbers

There are a few special (and not well known) Caller Info Attribute Parameters you can use, as an example I have a wrapper around my Log4Net implementation to get Source Line Numbers:

//I enhance the Log4Net logging by capturing the caller's name and the line of code number
public static void Error(Type source, object message, Exception e = null, [CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
{
ILog logger = getLogger(source);
if (!logger.IsErrorEnabled) return;

if (e == null)
logger.Error(string.Format("MemberName: {0}, SourceLineNumber of {1}, Message: {2}", memberName, sourceLineNumber, message));
else
logger.Error(string.Format("MemberName: {0}, SourceLineNumber of {1}, Message: {2}", memberName, sourceLineNumber, message), e);

}

These attributes on optional Parameters allow us to get the member name, file path and source line number:

[CallerMemberName] string memberName = "",  
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0

Log file output:

ERROR XYZ.Tools.Emailing.Email - MemberName: SendEmail,
SourceLineNumber of 129, Message: Sending email failed via Exchange
server.



Related Topics



Leave a reply



Submit