Need a way to periodically log the call stack/stac

2019-01-17 08:22发布

问题:

I'm working on a very large application where periodically I'd like to log the ENTIRE call stack up until the current execution point (not on an exception). The idea here is that I want a map of the exact code path that led me to the point that I am. I have been working with madExcept, tooled around with jclDebug and while I can get some of the call stack, I can't seem to get EVERY method/procedure/function call that is made in the application to show up in the log.

I've got stack frames turned on, debug info, etc enabled on the project. I even tried turning on stack frames on individual methods that weren't getting included in the call stack to no avail.

Is what I'm trying to do even possible? I'm really trying to avoid having to add logging code all over our millions of lines of code in order to log the code path.

回答1:

When you return from a method it is removed from the stack. So presumably your Partial call stack is every method that has not yet returned?

e.g.

DoSomething
begin
    MiniSubMethod
    DomeSomethingMore
    begin
        InnerDoSomething
        begin
            ShowCallStack
        end
    end
end

I would think in this situation the call stack would be

InnerDoSomething  
DoSomethingMore  
DoSomething  

MiniSubMethod is no longer on the stack as it returned before DoSomethingMore was called.

I think FastMM4 includes a Stack Trace so you could try that.

You would definitely need some kind of logging/stack trace instead of just the call stack.



回答2:

I use JCLDebug from the JCL to do just this.

The following will get the call stack for the current location and return it as a string.

function GetCurrentStack: string;
var
   stackList: TJclStackInfoList; //JclDebug.pas
   sl: TStringList;
begin
   stackList := JclCreateStackList(False, 0, Caller(0, False));
   sl := TStringList.Create;
   stackList.AddToStrings(sl, True, True, True, True);
   Result := sl.Text;
   sl.Free;
   stacklist.Free; 
end;

To make this work as expected, you must enable one of supported ways for Debug Information for JCL such as:

  • Turbo Debugger Information
  • JDBG Files (Generated from the MAP Files)
  • JBDG Files Inserted into the EXE.

I recently switched between JDBG files inserted into the EXE to just shipping the external JDBG files as it was easier to maintain.

There are also routines that are useful for tracing such as:

function ProcByLevel(Level : Integer) : String;

This allows you to determine the current method/procedure name looking back in the call stack "N" number of levels.



回答3:

From the responses and comments to other answers it sounds like you need a CALL LOG, not a CALL STACK. The information you want simply isn't present in a call stack.

In which case I suggest you investigate a tool such as SmartInspect or AQ Time. Of the two I think SmartInspect is most likely to be relevant. AQ Time is more of an interactive profiling tool, where-as SmartInspect has facilities specifically for remote inspection.



回答4:

You can use madExcept - it includes a method named GetThreadStackTrace. MadExcept is free for non-commercial use and definitely worth the price otherwise.



回答5:

If it is a complete trace you want, I believe a tool like SmartInspect could take you a long way.

It would require you to add logging to your code but for what you need, that would be unavoidable.

Some of its highlights

Monitor in Real-Time
High-performance live logging via TCP or named-pipes to the Console

Watch and Monitor Resources
Track variable values, session data and other application resources.

Rich Logging & Tracing
Track messages, exceptions, objects, files, database results & more.