首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Delphi -尝试获取异常的StackTrace

Delphi -尝试获取异常的StackTrace
EN

Stack Overflow用户
提问于 2017-05-04 05:57:04
回答 2查看 3.3K关注 0票数 5

我有一个异常记录器,它将所有异常记录到日志文件中:

代码语言:javascript
运行
复制
class function TLogger.LogException (ACaller: String; E: Exception): Boolean;
var
  LogFilename, tmp: string;
  LogFile: TextFile;
  appsettings: TApplicationSettings;
begin
  // prepare log file
  appsettings:=TApplicationSettings.Create;
  try
    tmp:=appsettings.ErrorLogsLocation;
  finally
    FreeAndNil(appsettings);
  end;

  if NOT (DirectoryExists(tmp)) then
    CreateDir(tmp);
  //We create a new log file for every day to help with file size issues
  LogFilename:=IncludeTrailingPathDelimiter (tmp) + 'LJErrors_' + FormatDateTime('yyyy-mm-dd', Now) +'.log';

  try
    AssignFile (LogFile, LogFilename);
    if FileExists (LogFilename) then
      Append (LogFile) // open existing file
    else
      Rewrite (LogFile); // create a new one

    // write to the file and show error
    Writeln(LogFile, CRLF+CRLF);
    Writeln (LogFile, 'Application Path: ' + ExtractFilePath(ParamStr (0)));
    Writeln (LogFile, 'Application Version: ' + TUtility.GetAppVersionString);
    Writeln (LogFile, 'Operating System: ' + TUtility.GetOSInfo);
    Writeln (LogFile, 'Error occurred at: ' + FormatDateTime ('dd-mmm-yyyy hh:nn:ss AM/PM', Now));
    Writeln (LogFile, 'Logged By: ' + ACaller);
    Writeln (LogFile, 'Unit Name: ' + E.UnitName);
    Writeln (LogFile, 'Error Message: ' + E.Message);
    Writeln (LogFile, 'Error Class: ' + E.ClassName);
    Writeln (LogFile, 'Base Exception Error: ' + E.BaseException.Message);
    Writeln (LogFile, 'Base Exception Class: ' + E.BaseException.ClassName);
    Writeln (LogFile, 'Stack Trace: ' + E.StackTrace);
    Result:=True;
  finally
    // close the file
    CloseFile (LogFile);
  end;
end;

为了启用Exception.StackTrace,我使用了JCLDebug,如:https://blog.gurock.com/working-with-delphis-new-exception-stacktrace中所概述的那样。

代码语言:javascript
运行
复制
unit StackTrace;

interface

uses
  SysUtils, Classes, JclDebug;

implementation

function GetExceptionStackInfoProc(P: PExceptionRecord): Pointer;
var
  LLines: TStringList;
  LText: String;
  LResult: PChar;
begin
  LLines := TStringList.Create;
  try
    JclLastExceptStackListToStrings(LLines, True, True, True, True);
    LText := LLines.Text;
    LResult := StrAlloc(Length(LText));
    StrCopy(LResult, PChar(LText));
    Result := LResult;
  finally
    LLines.Free;
  end;
end;

function GetStackInfoStringProc(Info: Pointer): string;
begin
  Result := string(PChar(Info));
end;

procedure CleanUpStackInfoProc(Info: Pointer);
begin
  StrDispose(PChar(Info));
end;

initialization
// Start the Jcl exception tracking and register our Exception
// stack trace provider.
if JclStartExceptionTracking then
begin
  Exception.GetExceptionStackInfoProc := GetExceptionStackInfoProc;
  Exception.GetStackInfoStringProc := GetStackInfoStringProc;
  Exception.CleanUpStackInfoProc := CleanUpStackInfoProc;
end;

finalization
// Stop Jcl exception tracking and unregister our provider.
if JclExceptionTrackingActive then
begin
  Exception.GetExceptionStackInfoProc := nil;
  Exception.GetStackInfoStringProc := nil;
  Exception.CleanUpStackInfoProc := nil;
  JclStopExceptionTracking;
end;

end.

我在Project中启用了下列选项:

编译:调试信息,本地符号,符号引用信息,使用调试.dcus,使用导入的数据引用

链接:调试信息

但是,当我触发异常时,即使GetExceptionStackInfoProc被触发,Exception.StackInfo始终是一个空字符串。对我可能错过了什么有什么想法吗?

更新20170504:感谢Stefan的解决方案。为了完整起见,我在这里包含了包含他的解决方案的修改后的GetExceptionStackInfoProc过程的代码:

代码语言:javascript
运行
复制
function GetExceptionStackInfoProc(P: PExceptionRecord): Pointer;
var
  LLines: TStringList;
  LText: String;
  LResult: PChar;
  jcl_sil: TJclStackInfoList;
begin
  LLines := TStringList.Create;
  try
    jcl_sil:=TJclStackInfoList.Create(True, 7, p.ExceptAddr, False, nil, nil);
    try
      jcl_sil.AddToStrings(LLines, true, true, true, true);
    finally
      FreeAndNil(jcl_sil);
    end;
    LText := LLines.Text;
    LResult := StrAlloc(Length(LText));
    StrCopy(LResult, PChar(LText));
    Result := LResult;
  finally
    LLines.Free;
  end;
end;
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-05-04 08:16:37

您需要自己创建它(并释放它):

代码语言:javascript
运行
复制
TJclStackInfoList.Create(True, 7, p.ExceptAddr, False, nil, nil);

在这种情况下,您可以调用AddToStrings

要获得更多信息,请看一下JclDebug.GetExceptionStackInfo。AIgnoreLevels的值是从那里提取的,但是在我的测试中,我总是有一个条目太多,所以我增加了一个条目。

下面是我从Button1应用程序中获得的调用RaiseLastOSError的片段;

代码语言:javascript
运行
复制
[0042BFE5] System.SysUtils.Sysutils.RaiseLastOSError$qqrix20System.UnicodeString (Line 24937, "System.SysUtils.pas")
[0042BF5B] System.SysUtils.Sysutils.RaiseLastOSError$qqrv (Line 24919, "System.SysUtils.pas")
[005CD004] Unit85.TForm85.Button1Click$qqrp14System.TObject (Line 28, "Unit85.pas")
[0051D567] Vcl.Controls.TControl.Click$qqrv (Line 7429, "Vcl.Controls.pas")
[00534CDA] Vcl.StdCtrls.Stdctrls.TCustomButton.Click$qqrv (Line 5434, "Vcl.StdCtrls.pas")
票数 6
EN

Stack Overflow用户

发布于 2018-06-04 06:17:52

如果您实际阅读了JclDebug单元,您将看到初始化和终结部分都有注册和注销代码,因此只需将单元放入uses部分就足够了。(见SetupExceptionProcs)

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43774927

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档