Delphi:如何在不使用断言的情况下获取(当前代码行、当前单元、当前函数)?
我试图在我的程序上创建一个日志系统,将调试消息记录在文本文件中,我想保存日志消息调用的代码中的确切位置,但我不想使用Assert函数,因为它会创建异常,而且这个系统不仅仅用于记录异常,我还必须编写一些调试信息 示例usning断言:Delphi:如何在不使用断言的情况下获取(当前代码行、当前单元、当前函数)?,delphi,logging,exception-handling,pascal,assertion,Delphi,Logging,Exception Handling,Pascal,Assertion,我试图在我的程序上创建一个日志系统,将调试消息记录在文本文件中,我想保存日志消息调用的代码中的确切位置,但我不想使用Assert函数,因为它会创建异常,而且这个系统不仅仅用于记录异常,我还必须编写一些调试信息 示例usning断言: procedure AnyProcedure(); begin try Assert(1=0); except on E: Exception do Log.AddLine('Log occurred is '+E.Message
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
请提供帮助,并提前感谢。您可以将自己的过程绑定到变量。你可以这样写:
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;
从指令指针映射到单元名称和行号的最简单方法是使用各种调试库之一:madeexcept、EurekaLog、JclDebug等
这些工具都依赖于链接器生成的详细映射文件。尽管这些库以从意外异常生成错误报告而闻名,但它们具有您所需的所有功能。顺便说一句,1=0并不是计算为False的最简单表达式。那将是,嗯,错误的。也感谢这个错误的表达式,我写代码的速度非常快,没有考虑它会是什么样子-我记得我是从Delphi帮助中复制的-。我知道这个答案与问题相反(我不想使用断言),但它解决了OP不想使用它的原因(因为它会创建异常)。我想这将解决我不知道如何使用断言函数的问题。感谢我不使用此函数的原因是:1.我不能再使用
Assert
来编写断言。我喜欢能够调用Assert
以实现其预期用途。2.使用Assert
进行日志记录会导致读取计数器的代码相反。例如:Assert(False,'Program initialized');
问问自己为什么没有看到这样实现的日志框架。@David,到第1点;您可以自己提出EAssertionFailed
(或者调用原始AssertErrorHandler
过程的副本)如果你错过了原始行为,就假装它;-)@TLama你如何区分真实的断言和虚假的日志声明?我听说了这些库,但我真的没有时间尝试它们,但谢谢你的回答。如果你没有时间做对的话,然后选择快速选项。它需要完整的调试信息,这会带来逆向工程风险。我总是错过德尔菲的一些东西。(在没有debuginfo的情况下在二进制文件中包含file和linenr的方法)。但它也有缺点,每次使用它时都必须通过它,因为它无法通过解卷来获取信息stack@Marco你只需要一张行号地图。如果在读取日志而不是写入日志时进行解码,则不需要将其包含在exe中。