Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get CallerFilePath and CallerLineNumber without using the CallerInfo attributes?

For my log4net solution, I have an API wrapper that uses the CallerInfo attributes, e.g.

    public void Write(string message,
                            [CallerMemberName] string memberName = "",
                            [CallerFilePath] string filePath = "",
                            [CallerLineNumber] int lineNumber = 0)

However, I am also using Unity Interception so that I can perform trace logging of the before/after responses, e.g. using ICallHandler like below in the Invoke method.

public class TraceCallHandler : ICallHandler
{
...

   public IMethodReturn Invoke(IMethodInvocation input, 
                               GetNextHandlerDelegate getNext)
    {
        //---- Trace method inputs
        this.LogInfoBeforeInvoke(input);

        //---- invoking the target method
        InvokeHandlerDelegate next = getNext();
        IMethodReturn methodReturn = next(input, getNext);

        //---- invoking the target method
        this.LogInfoAfterInvoke(methodReturn.ReturnValue); 
    }
}

Note: The above code is in no way complete/correct... but just wanted to show you what I was doing for Unity Interception.

My question / challenge is this: when I eventually call log.Write(...), I want the target's caller info, not my TraceCallHandler info.

e.g. for method name, I can do this:

   string methodName = input.MethodBase.Name;

How do I get the Caller's File Path and Caller's Line Number? Is it even possible to do via reflection?

Thanks!

like image 816
Raymond Avatar asked Oct 23 '14 16:10

Raymond


2 Answers

Yes, you can get these using reflection:

var sf = new System.Diagnostics.StackTrace(1).GetFrame(0);
Console.WriteLine(" File: {0}", sf.GetFileName());
Console.WriteLine(" Line Number: {0}", sf.GetFileLineNumber());
// Note that the column number defaults to zero 
// when not initialized.
Console.WriteLine(" Column Number: {0}", sf.GetFileColumnNumber());

However as it says clearly in the documentation:

StackFrame information will be most informative with Debug build configurations. By default, Debug builds include debug symbols, while Release builds do not. The debug symbols contain most of the file, method name, line number, and column information used in constructing StackFrame objects.

So if all you want this for is debugging, then enable it in debug builds and log away. In Release builds though it will be at best unhelpful and at worst downright misleading as apart from the symbol considerations above the compiler will aggressively inline methods and reorder things and generally mess with your stuff.

like image 65
stuartd Avatar answered Nov 13 '22 20:11

stuartd


I just ran across this issue and thought I would share what I learned. First, when you include [CallerFilePath] in a method argument a side effect is that the full path of the file, including any user identifiable data, will be included in your .exe. I created a simple program with one method. I created an exe. I then added a [CallerFilePath] attribute to the test function. When I compared the results of strings.exe (from sysinternals), the one with the attribute differed in that it included the full path of my source file.

c:\users\<my name>\documents\visual studio 2015\Projects\TestCallerAttribute\TestCallerAttribute\Program.cs

The answer above by stuartd is correct in that you will not be able to get the data you want from the stack trace in a release build.

There is a solution to getting strong data however: Event Tracing for Windows. From msdn: "Event Tracing for Windows (ETW) is an efficient kernel-level tracing facility that lets you log kernel or application-defined events to a log file. You can consume the events in real time or from a log file and use them to debug an application or to determine where performance issues are occurring in the application."

This is not a quick solution. There is work in setting up the events and the listeners to get the provenance you need. The long term payoff is strong.

like image 28
JoeEngineer Avatar answered Nov 13 '22 21:11

JoeEngineer