I use my own threaded debugger which dumps everyting in a file. In my code a make a lot of debug output messages like this :
debug.output('creating Object Myobject',LVL_OBJ);
Myobject:=TMyobject.Create;
....
debug.output('Destroying Object Myobject',LVL_OBJ);
FreeAndNil(TMyobject);
... and so on
I use this thing in ALL my apps and it helped me alot since you're actually forced to think what you're going to output to your debugger.
here's my code, I know there's room for some improvement, but its up to you to use it or not

)
unit u_thrd_debugger;
interface
{
DebugLevel explanation :
All values higher than 0 indates the "level" of debugging. Here are the different levels :
Level 1 : normal functions
Level 2 : internal functions
Level 3 : object creation/destruction
Level 4 : Time critical functions
}
uses
// delphi units
Classes, Sysutils, Windows;
const
{ debug levels}
LVL_NORM = 1;
LVL_INT = 2;
LVL_OBJ = 3;
LVL_TC = 4;
DEBUG_MAX_DEBUGLINES = 1;
DEBUG_DIR = 'debug\';
DEBUG_FILE_MAIN = 'dbg_main.txt';
DEBUG_FILE_CHANNEL = 'dbg_channel_%d.txt';
DEBUG_FILE_DATABASE = 'dbg_database.txt';
DEBUG_PREFIX_COMMS = 'Comms - ';
DEBUG_PREFIX_SYSTEM = 'System - ';
DEBUG_PREFIX_MONITOR = 'SQL monitor - ';
DEBUG_MODE_FILECLEAR = 128;
type
TThreadException = Procedure(Msg : string);
TThread_debugger = class(TThread)
private
{ Private declarations }
DebugException : boolean;
ErrMsg : string;
DebugLines : TStringList;
FEvent : THandle;
FOnException : TThreadException;
FMaxlines : integer;
protected
{ Protected declarations }
procedure Execute; override;
procedure AppendDebugFile;
procedure DoException;
function GetDebugLineCount : integer;
function GetMaxLines : integer;
procedure SetMaxLines(i : integer);
public
{ Public declarations }
DebugFile : string;
DebugLevel: integer;
Owner : string;
ClearFile : boolean;
FormatBytes : boolean;
constructor Create(CreateSuspended: Boolean);
destructor Destroy; override;
procedure FlushDebugLines;
procedure Output(s : string; Level : integer);
property Terminated;
property OnException : TThreadException read FOnException write FOnException;
published
{ Published declarations }
property DebugLineCount : integer read GetDebugLineCount;
property MaxLines : integer read GetMaxLines write SetMaxLines;
end;
implementation
procedure TThread_debugger.SetMaxLines(i : integer);
begin
FMaxLines:=i;
end;
function TThread_debugger.GetMaxLines : integer;
begin
Result:=FMaxLines;
end;
function TThread_debugger.GetDebugLineCount : integer;
begin
Result:=DebugLines.Count;
end;
procedure TThread_debugger.FlushDebugLines;
begin
AppendDebugFile;
end;
procedure TThread_debugger.DoException;
begin
if Assigned(OnException) then OnException(ErrMsg);
end;
procedure TThread_debugger.AppendDebugFile;
var Handle : Text;
begin
{$I+}
AssignFile(Handle,DebugFile);
if Fileexists(DebugFile) then Append(Handle) else Rewrite(Handle);
Write(Handle,DebugLines.Text);
DebugLines.Clear;
Flush(Handle);
CloseFile(Handle);
{$I-}
end;
procedure TThread_debugger.Output(s : string; Level : integer);
var s1 : string;
i : integer;
begin
if Level <= DebugLevel then
begin
if FormatBytes then for i := 1 to Length(s) do
begin
if (Ord(s
) > 31) then s1:=s1+s else s1:=s1+Format('#%x',[Ord(s)]);
end
else s1:=s;
DebugLines.Add(FormatDateTime('dd/mm, hh:nn:ss:zzz - ',Now)+s1);
if DebugLines.Count > DEBUG_MAX_DEBUGLINES then SetEvent(FEvent);
end;
end;
procedure TThread_debugger.Execute;
var Res : dword;
begin
{$IFDEF DEBUGGER}
if ClearFile then SysUtils.DeleteFile(DebugFile);
while not Terminated do
begin
res:=WaitForSingleObject( Fevent, 200);
if (res <> WAIT_TIMEOUT) and (DebugLevel > 0) then
begin
try
AppendDebugFile; // always call this function in an exception block, since the function itself has no errorchecking
except
// this section should normally not be be entered, but we cannot guarantee
// that the file operation will always be successful (disk full, disk errors,etc...)
// so we disable debugging (to prevent further exceptions) and call the exception trap to inform the debugger owner
on E : Exception do
begin
DebugLevel:=0;
DebugException:=True;
// inform debugger owner of Exception
ErrMsg:='A critical debugger message has occurred :'#13#10+E.Message+#13#10'Debugging is now disabled!!!';
Synchronize(DoException);
end;
end;
end;
end;
{$ENDIF}
end;
constructor TThread_debugger.Create(CreateSuspended: Boolean);
begin
DebugLines:=TStringList.Create;
DebugException:=False;
// event resets automatically and starts non-signalled
FEvent:=Windows.CreateEvent( nil, false, false, nil );
inherited Create(CreateSuspended);
end;
destructor TThread_debugger.Destroy;
begin
Terminate;
try
if Debuglines.Count <> 0 then if not DebugException then AppendDebugFile;
Windows.CloseHandle(FEvent);
finally
DebugLines.Free;
end;
inherited;
end;