【问题标题】:Need a way to periodically log the call stack/stack trace for EVERY method/procedure/function called需要一种方法来定期记录调用的每个方法/过程/函数的调用堆栈/堆栈跟踪
【发布时间】:2011-01-20 14:00:06
【问题描述】:

我正在开发一个非常大的应用程序,我想定期记录整个调用堆栈,直到当前执行点(而不是异常)。这里的想法是,我想要一张准确的代码路径图,它引导我到达我现在的位置。我一直在使用 madExcept,使用 jclDebug 进行工具化,虽然我可以获得一些调用堆栈,但我似乎无法让应用程序中进行的每个方法/过程/函数调用都显示在日志中。

我已经在项目上启用了堆栈帧、调试信息等。我什至尝试在未包含在调用堆栈中的单个方法上打开堆栈帧,但无济于事。

我正在尝试做的事情是否可能?我真的在努力避免为了记录代码路径而不得不在我们数百万行代码中添加日志代码。

【问题讨论】:

  • 在您希望的位置设置断点并使用Call Stack 窗口有什么问题?
  • @Lieven - 问题是我希望它记录在我没有在 Delphi IDE 中运行我的应用程序的客户站点:-)
  • 你还没有描述你的堆栈的哪一部分丢失了。您是否也使用过 Debug DCU?
  • @BennyBechDk - 正如 JamesB 之前指出的,我缺少的堆栈部分很可能是所有已返回/完成的调用。我确实使用调试 DCU 进行了编译,但这并没有帮助。看来我必须手动添加日志才能获取我需要的信息...

标签: delphi stack-trace callstack madexcept jedi-code-library


【解决方案1】:

当你从一个方法返回时,它会从堆栈中移除。那么大概你的 Partial 调用堆栈是每个尚未返回的方法?

例如

DoSomething
begin
    MiniSubMethod
    DomeSomethingMore
    begin
        InnerDoSomething
        begin
            ShowCallStack
        end
    end
end

我认为在这种情况下调用堆栈会是

InnerDoSomething  
DoSomethingMore  
DoSomething  

MiniSubMethod 不再在堆栈上,因为它在调用 DoSomethingMore 之前返回。

我认为 FastMM4 包含堆栈跟踪,因此您可以尝试一下。

您肯定需要某种日志记录/堆栈跟踪,而不仅仅是调用堆栈。

【讨论】:

  • 我认为你是对的......你说的很有道理。我会检查 FastMM(因为我们已经将它用于内存泄漏检测),但我感觉它仍然无法达到我想要的效果。谢谢!
【解决方案2】:

您可以使用madExcept - 它包含一个名为GetThreadStackTrace 的方法。 MadExcept 可免费用于非商业用途,否则绝对物有所值。

【讨论】:

  • 对,我实际上已经尝试过 madExcept 并且效果很好,只是如果 JamesB 说的是真的(我相信它是真的),我不会看到我想要/需要的一切见。
【解决方案3】:

从响应和 cmets 到其他答案,听起来您需要一个 CALL LOG,而不是 CALL STACK。您想要的信息根本不存在于调用堆栈中。

在这种情况下,我建议您调查SmartInspectAQ Time 之类的工具。在这两者中,我认为 SmartInspect 最有可能是相关的。 AQ Time 更像是一种交互式分析工具,而 SmartInspect 具有专门用于远程检查的设施。

【讨论】:

  • @Deltics - 我相信你是对的......我真的需要所有通话的日志。我想我希望调用堆栈会包含这些信息,但唉,它似乎没有。我检查了 SmartInspect,但我们的应用程序中已经有一个相当不错的日志记录系统,所以我可能最终会使用它。谢谢!
【解决方案4】:

如果是您想要的完整跟踪,我相信像SmartInspect 这样的工具可以带您走很长一段路。

这需要您在代码中添加日志记录,但对于您的需要,这是不可避免的。

它的一些亮点

实时监控
通过 TCP 或命名管道到控制台的高性能实时日志记录

观察和监控资源
跟踪变量值、会话数据和其他应用程序资源。

丰富的日志记录和跟踪
跟踪消息、异常、对象、文件、数据库结果等。

【讨论】:

  • 我使用 Codesite,但是是的,这是一个更好的方法。您可以只记录真正重要的部分和参数。您可以根据需要启用/禁用。
  • @Lieven - 谢谢!就像我之前评论的那样,我查看了 SmartInspect,但我的应用程序已经有一个非常好的日志系统。我只是想避免添加所有的日志记录代码,但在这一点上看起来是不可避免的。
【解决方案5】:

我使用来自 JCL 的 JCLDebug 来执行此操作。

下面会获取当前位置的调用栈,并将其作为字符串返回。

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;

要使这项工作按预期进行,您必须为 JCL 的调试信息启用一种受支持的方式,例如:

  • Turbo 调试器信息
  • JDBG 文件(从 MAP 文件生成)
  • JBDG 文件已插入 EXE。

我最近在插入到 EXE 中的 JDBG 文件之间切换到只发送外部 JDBG 文件,因为它更易于维护。

还有一些对跟踪很有用的例程,例如:

function ProcByLevel(Level : Integer) : String;

这使您可以在调用堆栈“N”个级别中确定当前方法/过程名称。

【讨论】:

  • @Robert Love - 谢谢罗伯特!我确实摆弄了 JCL 的东西,它似乎与 madExcept 和所有其他解决方案一样工作。我真正的问题是堆栈跟踪根本不包含我需要的所有信息。
  • 只有两件事导致我没有预期的 JCLDebug 调用堆栈,这两个都不是 JCLDebug 中的错误。第一个:内联的过程/函数,我没有意识到。第二个:我的 JDBG 文件过时了,他们没有生成相关的编译代码。
  • 我没有得到我想要的所有信息。启用 RAW 我得到了我想要的……以及比我需要的更多的信息。 :|如果有 SemiRAW 模式...
猜你喜欢
  • 2012-06-19
  • 2015-06-18
  • 2011-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-20
相关资源
最近更新 更多