2017-05-04 10 views
2

에 대한 스택 트레이스를 얻기 위해 노력 :델파이 - 나는 로그 파일에 모든 예외를 기록 예외 로거가 예외

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.

컴파일 : 내가 프로젝트 옵션에서 다음 옵션 활성화

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. 

디버그 정보, 현지 기호, 기호 참조 정보, 사용 디버그 .dcus은 사용 데이터 참조를

연결 중 수입 : 디버그 정보

그러나 예외를 트리거하면 GetExceptionStackInfoProc이 실행 되더라도 Exception.StackInfo은 항상 빈 문자열입니다. 내가 누락 된 부분에 대한 아이디어가 있습니까?

업데이트 20170504 : 솔루션에 대한 Stefan Glienke에게 감사드립니다. 당신이 할 수있는 인스턴스에

TJclStackInfoList.Create(True, 7, p.ExceptAddr, False, nil, nil); 

: 당신은 스스로 (무료로) 만들 필요가

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; 

답변

0

: 완성도를 들어, 나는 그의 솔루션을 통합 여기에 변경 GetExceptionStackInfoProc 절차에 대한 코드를 포함하고있다 AddToStrings으로 전화하십시오.

자세한 내용은 JclDebug.GetExceptionStackInfo을 참조하십시오. AIgnoreLevels의 값은 거기에서 가져 왔지만 테스트에서 나는 항상 하나의 항목을 너무 많이 가져서 하나씩 증가 시켰습니다.

다음은 RaiseLastOSError를 호출하는 Button1 애플리케이션에서 얻은 코드입니다.

[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") 
+0

감사합니다. @stefanglienke -이 작품! 파일 크기를 최소로 유지하면서 배포 (prod) exe에이 기능을 포함시킬 수있는 방법에 대한 권장 사항이 있습니까 (예 : 동일한 출력을 얻기 위해 프로젝트 옵션에서 설정하는 최소한의 플래그는 무엇입니까?). – Rohit