Reputation: 806
I'm using Delphi 7 and EurekaLog 7 (in compatibility mode) and simply want to get call stack of a handled exception, like
procedure CrossThreadFunc;
begin
try
SomeCode;
except
on E: Exception do
Log(CallStackOf(E));
end;
end;
It's a multi-threaded application so I'd like to see the call stack of the calling thread if possible. Also, since this is a handled exception, do I still need to use EurekaLog's OnExceptionRaise
event? (which I don't want to).
Edit: CrossThreadFunc() is being called many times with some arguments and what I need to know is exactly where I called it that eventually caused SomeCode() to raise an exception.
Upvotes: 1
Views: 420
Reputation: 5668
There are several ways to do this, described in EurekaLog's help:
Option 1
(Delphi 2009+ only)
Assuming you only need a textual representation:
except
on E: Exception do
Memo1.Lines.Text := E.StackTrace;
end;
Option 2
Assuming you have access to RTL's exception object:
uses
EExceptionManager, // for ExceptionManager
EException, // for TEurekaExceptionInfo
ECallStack; // for TEurekaBaseStackList
var
EI: TEurekaExceptionInfo;
CallStack: TEurekaBaseStackList;
// ...
except
on E: Exception do
begin
EI := ExceptionManager.Info(E);
// EI would be nil, if EurekaLog is disabled
// or event handlers instruct EurekaLog to skip this exception
if Assigned(EI) then
CallStack := EI.CallStack;
end;
end;
Note: due to bugs in some older IDEs, you may need to write like this:
EI := ExceptionManager.Info(Pointer(E));
Option 3
Assuming you have access to EurekaLog's exception information object (such as argument in an event handler):
uses
EException, // for TEurekaExceptionInfo
ECallStack; // for TEurekaBaseStackList
{ ... } AExceptionInfo: TEurekaExceptionInfo; { ... }
var
CallStack: TEurekaBaseStackList;
begin
CallStack := AExceptionInfo.CallStack;
end;
Option 4
Assuming you want call stack for last (e.g. most recent) exception in current thread:
uses
EExceptionManager, // for ExceptionManager
EException, // for TEurekaExceptionInfo
ECallStack; // for TEurekaBaseStackList
var
EI: TEurekaExceptionInfo;
CallStack: TEurekaBaseStackList;
begin
EI := ExceptionManager.LastThreadException;
// EI would be nil, if EurekaLog is disabled
// or event handlers instruct EurekaLog to skip this exception
if Assigned(EI) then
CallStack := EI.CallStack;
end;
Notes:
If you need current call stack - use GetCurrentCallStack
function from ECallStack
unit:
uses ECallStack; // for TEurekaBaseStackList and GetCurrentCallStack
procedure TForm1.Button1Click(Sender: TObject); var CallStack: TEurekaBaseStackList; begin CallStack := GetCurrentCallStack; // You can also use other functions from ECallStack unit try Memo1.Lines.Text := CallStack.ToString; // You can also use CallStackToString(s) routines to customize textual formatting finally FreeAndNil(CallStack); end; end;
If you need call stacks from other threads - just set it up in options, call stacks for all enabled threads will be included in the same call stack object. You can distingush between threads by ThreadID
property of call stack entry.
If you need to convert retrieved call stack to text/string representation for logging purposes, see this:
Option 1
Use StackTrace
property of exception object (Delphi 2009+):
except
on E: Exception do
Memo1.Lines.Text := E.StackTrace;
end;
Option 2
Use ToString
method to convert call stack to single string with default formatting:
var
CallStack: TEurekaBaseStackList;
begin
CallStack := { ... somehow retrieve call stack ... };
Memo1.Lines.Text := CallStack.ToString;
end;
Option 3
Use Assign
method to convert call stack to TStrings
object with default formatting:
var
CallStack: TEurekaBaseStackList;
begin
CallStack := { ... somehow retrieve call stack ... };
Memo1.Lines.Assign(CallStack);
end;
Option 4
Use CallStackToString
function from ECallStack
unit:
// (CallStackToString function allows you to override header and formatting)
var
CallStack: TEurekaBaseStackList;
Formatter: TCompactStackFormatter;
begin
CallStack := { ... somehow retrieve call stack ... };
// A): Default formatting and header:
Memo1.Lines.Text := CallStackToString(CallStack);
// B): With custom header:
Memo1.Lines.Text := CallStackToString(CallStack, 'Error Details:');
// C): Custom formatting:
Formatter := TCompactStackFormatter.Create;
try
// <- here you can customize Formatter (for example: alter captions for columns, etc.)
Memo1.Lines.Text := CallStackToString(CallStack, '', Formatter);
finally
FreeAndNil(Formatter);
end;
end;
Option 5
Use CallStackToStrings
function from ECallStack
unit:
// (CallStackToStrings function allows you to override header and formatting)
var
CallStack: TEurekaBaseStackList;
Formatter: TCompactStackFormatter;
begin
CallStack := { ... somehow retrieve call stack ... };
// A): Default formatting and header:
CallStackToStrings(CallStack, Memo1.Lines);
// B): With custom header:
CallStackToStrings(CallStack, Memo1.Lines, 'Error Details:');
// C): Custom formatting:
Formatter := TCompactStackFormatter.Create;
try
// <- here you can customize Formatter (for example: alter captions for columns, etc.)
CallStackToStrings(CallStack, Memo1.Lines, '', Formatter);
finally
FreeAndNil(Formatter);
end;
end;
Available formatters are:
P.S. You may also want to consider EurekaLog's logging procedures.
Upvotes: 1