【问题标题】:How to get call stack of a handled exception using EurekaLog如何使用 EurekaLog 获取已处理异常的调用堆栈
【发布时间】:2017-10-23 03:20:16
【问题描述】:

我正在使用 Delphi 7 和 EurekaLog 7(在兼容模式下),只是想获取已处理异常的调用堆栈,例如

procedure CrossThreadFunc;
begin
  try
    SomeCode;
  except
    on E: Exception do
      Log(CallStackOf(E));
  end;
end;

这是一个多线程应用程序,所以如果可能的话,我想查看调用线程的调用堆栈。另外,既然这是一个已处理的异常,我还需要使用 EurekaLog 的OnExceptionRaise 事件吗? (我不想这样做)。

编辑:CrossThreadFunc() 被多次调用并带有一些参数,而我需要知道的正是我调用它的位置,最终导致 SomeCode() 引发异常。

【问题讨论】:

  • 不清楚您要查找的调用堆栈。工作线程,或主线程。如果是后者,在什么时间点?
  • David,我实际上对查看调用线程的调用堆栈很感兴趣,因为 SomeCode() 正在导致异常,但我需要知道我在哪里调用了导致异常的 CrossThreadFunc()
  • 这可能是调试程序的错误方法。您需要暂停主线程以获取其调用堆栈。不能保证它会是有用的信息,因为您会错过导致原始错误的时刻。
  • 使用 Eurekalog 是绝对必要的吗?如果您碰巧已经在使用 Jedi,您可以使用 Jedi 的堆栈跟踪实用程序来做到这一点。

标签: delphi eurekalog


【解决方案1】:

有几种方法可以做到这一点,在EurekaLog's help中描述:

选项 1

(仅限 Delphi 2009+)

假设您只需要文本表示:

except
  on E: Exception do
    Memo1.Lines.Text := E.StackTrace;
end;

选项 2

假设您可以访问 RTL 的异常对象:

uses
  EExceptionManager, // for ExceptionManager
  EException,        // for TEurekaExceptionInfo 
  ECallStack;        // for TEurekaBaseStackList 

var
  EI: TEurekaExceptionInfo;
  CallStack: TEurekaBaseStackList;
// ...
  except
    on E: Exception do
    begin
      EI := ExceptionManager.Info(E);
      // EI would be nil, if EurekaLog is disabled
      // or event handlers instruct EurekaLog to skip this exception
      if Assigned(EI) then 
        CallStack := EI.CallStack;
    end;
  end;

注意:由于某些旧 IDE 中存在错误,您可能需要这样编写:

EI := ExceptionManager.Info(Pointer(E));

选项 3

假设您可以访问 EurekaLog 的异常信息对象(例如事件处理程序中的参数):

uses
  EException, // for TEurekaExceptionInfo 
  ECallStack; // for TEurekaBaseStackList

{ ... } AExceptionInfo: TEurekaExceptionInfo; { ... }
var
  CallStack: TEurekaBaseStackList;
begin
  CallStack := AExceptionInfo.CallStack;
end;

选项 4

假设您希望当前线程中最后一个(例如最近的)异常的调用堆栈:

uses
  EExceptionManager, // for ExceptionManager
  EException,        // for TEurekaExceptionInfo 
  ECallStack;        // for TEurekaBaseStackList 

var
  EI: TEurekaExceptionInfo;
  CallStack: TEurekaBaseStackList;
begin
  EI := ExceptionManager.LastThreadException;
  // EI would be nil, if EurekaLog is disabled
  // or event handlers instruct EurekaLog to skip this exception
  if Assigned(EI) then 
    CallStack := EI.CallStack;
end;

注意事项:

  • 如果您需要当前调用堆栈 - 使用来自 ECallStack 单元的 GetCurrentCallStack 函数:

    用途 调用堆栈; // 用于 TEurekaBaseStackList 和 GetCurrentCallStack

    过程 TForm1.Button1Click(Sender: TObject); 变量 调用堆栈:TEurekaBaseStackList; 开始 CallStack := GetCurrentCallStack; // 你也可以使用 ECallStack 单元中的其他函数 尝试 Memo1.Lines.Text := CallStack.ToString; // 您还可以使用 CallStackToString(s) 例程来自定义文本格式 最后 FreeAndNil(CallStack); 结尾; 结束;

  • 如果您需要来自其他线程的调用堆栈 - 只需在选项中进行设置,所有启用的线程的调用堆栈都将包含在同一个调用堆栈对象中。您可以通过调用堆栈条目的ThreadID 属性来区分线程。

  • 如果您需要将检索到的调用堆栈转换为文本/字符串表示以进行记录,请参阅this

选项 1

使用异常对象的StackTrace 属性(Delphi 2009+):

except
  on E: Exception do
    Memo1.Lines.Text := E.StackTrace;
end;

选项 2

使用ToString 方法将调用堆栈转换为具有默认格式的单个字符串:

var
  CallStack: TEurekaBaseStackList;
begin
  CallStack := { ... somehow retrieve call stack ... };
  Memo1.Lines.Text := CallStack.ToString;
end;

选项 3

使用Assign 方法将调用堆栈转换为TStrings 具有默认格式的对象:

var
  CallStack: TEurekaBaseStackList;
begin
  CallStack := { ... somehow retrieve call stack ... };
  Memo1.Lines.Assign(CallStack);
end;

选项 4

使用ECallStack单元中的CallStackToString函数:

// (CallStackToString function allows you to override header and formatting)

var
  CallStack: TEurekaBaseStackList;
  Formatter: TCompactStackFormatter;
begin
  CallStack := { ... somehow retrieve call stack ... };

  // A): Default formatting and header:
  Memo1.Lines.Text := CallStackToString(CallStack);

  // B): With custom header:
  Memo1.Lines.Text := CallStackToString(CallStack, 'Error Details:');

  // C): Custom formatting:
  Formatter := TCompactStackFormatter.Create;
  try
    // <- here you can customize Formatter (for example: alter captions for columns, etc.)
    Memo1.Lines.Text := CallStackToString(CallStack, '', Formatter);
  finally
    FreeAndNil(Formatter);
  end;
end;

选项 5

使用ECallStack单元中的CallStackToStrings函数:

// (CallStackToStrings function allows you to override header and formatting)

var
  CallStack: TEurekaBaseStackList;
  Formatter: TCompactStackFormatter;
begin
  CallStack := { ... somehow retrieve call stack ... };

  // A): Default formatting and header:
  CallStackToStrings(CallStack, Memo1.Lines);

  // B): With custom header:
  CallStackToStrings(CallStack, Memo1.Lines, 'Error Details:');

  // C): Custom formatting:
  Formatter := TCompactStackFormatter.Create;
  try
    // <- here you can customize Formatter (for example: alter captions for columns, etc.)
    CallStackToStrings(CallStack, Memo1.Lines, '', Formatter);
  finally
    FreeAndNil(Formatter);
  end;
end;

可用的格式化程序有:

  • TEurekaStackFormatter - EurekaLog 样式调用堆栈的通用格式化程序(即带列的固定宽度表) - 最适合在文本文件中使用
  • TEurekaStackFormatterV6 - 向后兼容的格式化程序,以 EurekaLog V6 格式生成调用堆栈(更少的列)
  • TSimpleStackFormatter - 生成类似列表的调用堆栈视图(无列),适用于可变宽度字体(最好在消息框中使用)
  • TCompactStackFormatter - 类似于 TSimpleStackFormatter,但输出更紧凑,细节更少(适合快速预览)

附:您可能还想考虑EurekaLog's logging procedures

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-28
    • 2011-07-03
    • 1970-01-01
    • 2014-04-23
    • 1970-01-01
    • 2010-10-19
    • 2013-02-16
    • 1970-01-01
    相关资源
    最近更新 更多