1、使用 Win32 API OutputDebugString
procedure TForm1.BtnDebugClick(Sender: TObject);
begin
//这里调用OutputDebugString发送调试信息到调试器。在Delphi
//里面,用View - Debug Windows - Event Log 来查看。
OutputDebugString(PChar('测试OutputDebugString'));
end;
很简单。这个函数是Windows提供的,专门用来进行调试。调用后,将把字符串发送给当前的调试器,比如说IDE,调试器(Softice, ollydbg)等。对于Delphi来说,就是Delphi IDE本身。在程序运行的时候,可以通过View - Debug Windows - Event Log 来查看,如图:
2、发送日志到操作系统日志记录。
这个基本上使用在Release版本中,记录一些重要的信息,帮助用户反馈信息给开发人员。
procedure TForm1.BtnEventClick(Sender: TObject);
var
h,b:THandle;
msg:String;
p:Pointer;
i:integer;
size:integer;
q:^byte;
begin
//注册事件源,随便起了个名字。这个名字就是下图事件列表的’来源’一列
//然后判断是否成功。
//注意后面要注销
h:=RegisterEventSource(nil, 'test1');
if h = 0 then
begin
ShowMessage('注册事件源失败!');
Exit;
end;
//这里记录一个字符串
//这个字符串显示在下面第二个图选中的位置。
msg:='记录字符串';
ReportEvent(h,EVENTLOG_INFORMATION_TYPE,0, 0, nil, 1, 0, @msg, nil);
//这里记录一块内存,size大小,里面随便填充一些int
size:=32;
//申请
GetMem(p, size);
q:=p;
//填充这块内存
for i:=0 to size - 1 do
begin
q^:=i;
inc(q);
end;
//这里记录内存的内容。大小为size, 首字节的指针p
//同样也有说明信息msg
msg:='记录某块内存';
ReportEvent(h,EVENTLOG_INFORMATION_TYPE , 0, 0, nil, 1, size, @msg, p);
FreeMem(p);
//注销事件源
DeregisterEventSource(h);
end;
程序运行后,可以通过控制面板 – 管理工具 – 事件查看器来查看。上面的代码运行结果如图:.
双击第一个事件,如图:
双击第二个事件,如图:
3、覆盖Assert
Delphi内置了Assert调试过程,语法是
Assert(cond, msg);
如果cond为false,那么显示错误信息msg,并且触发异常(可在IDE里中断)。
因为这个函数是编译器内置的,里面提供了源代码文件名、行号的信息,所以可以通过重写这个函数,完成日志记录的功能:
1、加入初始化代码,保存旧的Assert函数地址,然后将新的赋入:
initialization
oldAssertErrorProc := AssertErrorProc;
AssertErrorProc:=@OtherAssertProc;
其中,新函数OtherAssertProc如下:
procedure OtherAssertProc(const Message, Filename: string;
LineNumber: Integer; ErrorAddr: Pointer);
Var
runErrMsg:String;
begin
runErrMsg := format('Error: %s, in file(%d): %s, Addr: %p',
[Message, LineNumber, FileName, ErrorAddr]);
if IsConsole then
Writeln(runErrMsg)
else
MessageBox(0, pChar(runErrMsg), 'Error Log by AssertLogs', 0);
end;
2、在程序中,就可以使用
Assert(false, msg);来进行调用了。因为我们使用Assert来记录信息,所以条件一定是false保证函数被调用。运行结果如下图:
这是通过MessageBox函数输出的,当然也可以通过其他方式显示或者记录。
3、最后,将AssertErrorProc恢复初始值:
finalization
AssertErrorProc := oldAssertErrorProc;
4、JCL库
JCL库是著名的开源Delphi库,包括大量的函数、类,基本上分为系统、日期、调试、字符串等等。其中的JCLDebug库可以方便的列出代码的调用情况,也可以做到类似与Java的逐层打印调用栈。运行情况如下图:
代码为:
//这是一个日志函数,拼装日志信息
function log(S:String):String;
var
f, proc:String;
line:Integer;
r:String;
begin
f:=FileByLevel(1); //获得调用它的文件名
line:=LineByLevel(1); //获得调用它的行号
proc:=ProcByLevel(1); //获得调用它的模块名
Result:= f + ':' + IntToStr(line) + ' ' + proc + ' ' + S;
end;