Need a way to periodically log the call stack/stack trace for EVERY method/procedure/function called
Asked Answered
C

5

16

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.

Christos answered 24/2, 2010 at 15:7 Comment(4)
What is wrong with setting a breakpoint at the point you wish to be and use the Call Stack window?Magill
@Lieven - The problem is I want it logged at a customer's site where I'm not running my app in the Delphi IDE :-)Christos
You havn't described what part of your stack is missing. Have you also used the Debug DCU's?Kudos
@Kudos - The part of the stack I'm missing is, as JamesB pointed out earlier, most likely all of the calls that have returned/completed. I did compile with debug DCUs and that did not help. It looks like I have to add manually logging to get the information I need...Christos
N
6

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.

Naturally answered 24/2, 2010 at 15:30 Comment(1)
I think you're right...what you're saying makes sense. I'll check out FastMM (since we already use this for memory leak detection), but I have a feeling it still won't do what I want it to. Thanks!Christos
I
24

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.

Icecap answered 25/2, 2010 at 19:48 Comment(3)
@Robert Love - Thanks Robert! I did actually fiddle around with the JCL stuff, and it appears to work the same as madExcept and all of the other solutions out there. My real problem is the stack trace simply doesn't contain all the information I need.Christos
There are only two things that have caused me to not have expected call stacks with JCLDebug neither of which were bugs in JCLDebug. The first: Procedure/functions where inlined and I did not realize it. The Second: My JDBG Files where out of date, they did not make the associated compiled code.Icecap
I was too not getting all information I wanted. Enabling RAW I got what I wanted... and much more info than I needed. :| If there was a SemiRAW mode...Consonantal
Z
9

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

Zawde answered 24/2, 2010 at 17:37 Comment(1)
Right, I have actually tried madExcept and it works fine, it's just that if what JamesB said is true (which I believe it is), I'm not going to see everything I want/need to see.Christos
S
7

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.

Sexpartite answered 24/2, 2010 at 19:52 Comment(1)
@Sexpartite - I believe you're correct...I really need the log of all the calls. I guess I was hoping the call stack would contain this information but alas, it does not appear to. I checked out SmartInspect but we already have a pretty decent logging system available in our application, so I'll just probably end up using that. Thanks!Christos
N
6

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.

Naturally answered 24/2, 2010 at 15:30 Comment(1)
I think you're right...what you're saying makes sense. I'll check out FastMM (since we already use this for memory leak detection), but I have a feeling it still won't do what I want it to. Thanks!Christos
M
1

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.

Magill answered 25/2, 2010 at 8:1 Comment(2)
I use Codesite, but yes, this is a better way to go. You can document just the parts that really matter, and the parameters. And you can enable/disable as you require.Flirtatious
@Lieven - thanks! Like I commented earlier, I looked at SmartInspect but my application already has a pretty good logging system. I was just trying to avoid adding all of the logging code, but it looks unavoidable at this point.Christos

© 2022 - 2024 — McMap. All rights reserved.