2013-05-09 30 views
5

我想在我的程序上創建一個日誌系統,它將在文本文件上記錄調試消息,並且我想在代碼中保存日誌消息所調用的確切位置,但我不想使用Assert函數,因爲它會創建異常,並且此係統不僅用於記錄異常,還必須編寫一些調試信息。德爾福:如何獲得(當前代碼行,當前單位,當前功能),而不使用斷言?

例如usning斷言:

procedure AnyProcedure(); 
begin 
    try 
    Assert(1=0); 
    except 
    on E: Exception do 
     Log.AddLine('Log occurred is '+E.Message+' : Start');//Log occurred is "c:\progr~..jkdj.pas" at line [29] 
    end; 

    //....some code 
    try 
    Assert(1=0); 
    except 
    on E: Exception do 
     Log.AddLine('Log occurred is '+E.Message+' : Step1 done');//Log occurred is "c:\progr~..jkdj.pas" at line [37] 
    end; 

    //....some code 
    try 
    Assert(1=0); 
    except 
    on E: Exception do 
     Log.AddLine('Log occurred is '+E.Message+' : Step2 done');//Log occurred is "c:\progr~..jkdj.pas" at line [45] 
    end; 

    //....some code 
    try 
    Assert(1=0); 
    except 
    on E: Exception do 
     Log.AddLine('Log occurred is '+E.Message+' : Step3 done');//Log occurred is "c:\progr~..jkdj.pas" at line [53] 
    end; 

    //....some code 
    try 
    Assert(1=0); 
    except 
    on E: Exception do 
     Log.AddLine('Log '+E.Message+' : End');//Log occurred is "c:\progr~..jkdj.pas" at line [61] 
    end; 
end; 

這工作得很好,它拋出一個異常,併成爲太大的代碼的唯一的事情,所以我不能使用的功能 - 請參見下面的例子功能LogMessage-和呼叫它在另一個地方,因爲行會總是相同也文件名稱將是其中的LogMessage函數來實現:

不靈例如:

procedure LogMessage(AMessage: String); 
var AFile, ALine: String; 
begin 
    try 
    Assert(1=0);    //line 29 
    except 
    on E: Exception do 
    begin 
     AFile:= Copy(E.Message, Pos(' (', E.Message)+2, Pos(', line ', E.Message)-Pos(' (', E.Message)-2); 
     ALine:= Copy(E.Message, Pos(', line ', E.Message)+7, Pos(')', E.Message)-Pos(', line ', E.Message)-7); 
     ShowMessage('Log occurred in file "'+AFile+'" at line ['+ALine+'] : '+AMessage); 
    end; 
    end; 
end; 

procedure AnyProcedure(); 
begin 
    LogMessage('Start'); //Log occurred in file "c:\progr~....jkashdj.pas" at line [29] 
//.... 
    LogMessage('step1'); //Log occurred in file "c:\progr~....jkashdj.pas" at line [29] 
//.... 
    LogMessage('step2'); //Log occurred in file "c:\progr~....jkashdj.pas" at line [29] 
//.... 
    LogMessage('step3'); //Log occurred in file "c:\progr~....jkashdj.pas" at line [29] 
//.... 
    LogMessage('end'); 
end 

請幫助,並提前致謝。

+5

順便說一句,1 = 0不是評估爲False的最簡單表達式。那會是假的。 – 2013-05-09 10:59:53

+0

非常感謝False的表達,我很快就寫了代碼,沒有想到它會如何看起來像我記得我從德爾福的幫助中複製它。 – 2013-05-09 13:05:33

回答

10

您可以將自己的TAssertErrorProc程序綁定到AssertErrorProc變量。你可能會寫這樣的事:

procedure OnAssert(const Message, Filename: string; LineNumber: Integer; 
    ErrorAddr: Pointer); 
begin 
    ShowMessage(Format('Assert in file "%s" at line %d.', [Filename, LineNumber])); 
end; 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    AssertErrorProc := OnAssert; 
end; 
+1

我知道這個答案是針對被問的問題(*我不想使用Assert *),但它解決了OP不想使用它的原因(*因爲它會創建異常*)。 – TLama 2013-05-09 11:02:33

+0

我認爲這將解決問題,我只是不知道如何使用斷言功能。 謝謝 – 2013-05-09 11:08:40

+0

不客氣! – TLama 2013-05-09 11:10:27

9

從指令指針到單元名和行號地圖最簡單的方法是使用各種調試庫之一:madExcept,EurekaLog,JclDebug等

這些工具都依賴於鏈接器生成的詳細映射文件。雖然這些庫最擅長於從意外異常中生成錯誤報告,但它們具有您需要的所有功能。

+0

我聽說過這些圖書館,但我真的沒有時間去嘗試,但謝謝你的答案。 – 2013-05-09 11:09:44

+1

好吧,如果你沒有足夠的時間去做正確的事情,那就選擇快速選項。 – 2013-05-09 11:11:10

+0

它需要完整的調試信息,構成逆向工程風險。我一直在Delphi中錯過了像http://www.freepascal.org/docs-html/prog/progsu41.html#x47-460001.1.41。 (在沒有debuginfo的情況下將文件和亞麻布包含在二進制文件中的方法)。它的缺點是每次使用它都必須通過它,因爲它不能通過展開堆棧獲得信息 – 2013-05-09 19:22:09