2013-05-09 69 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