Our application log the source line causing exception with JCL and it works great. I use D2007. I have a TApplicationEvents.OnException event that do the actual logging. Consider this:
function MyFunc: String;
begin
// Codelines that may raise exception.
// Call functions that also may raise exception
end;
procedure ComplexFunc(aVariable: String);
begin
// also here can it be exceptions....
// Code here that is the cause of exception
end;
procedure foo;
var
myVar: String;
begin
myvar := MyFunc;
ComplexFunc(myvar);
end;
procedure TMainForm.ApplicationEvents1Exception(Sender: TObject; E: Exception);
begin
LogLastException(E, 'Unhandled Exception (%s)', [E.Message], 20);
end;
I have 3 methods and my onException event. LogLastException log the callstack when an exception occurs. The problem is that I cannot add information to the E.Message without loose the sourceline that cause exception. Pretend it is the second line in ComplexFunc that raise exception. I also want to log the value of myvar variable. So I change the code to:
function MyFunc: String;
begin
// Codelines that may raise exception.
// Call functions that also may raise exception
end;
procedure ComplexFunc(aVariable: String);
begin
// also here can it be exceptions....
// Code here that is the cause of exception
end;
procedure foo;
var
myVar: String;
begin
try
myvar := MyFunc;
ComplexFunc(myvar);
except
on E: Exception do
raise TException.CreateFmt('myvar = %s', [myvar]);
end;
end;
procedure TMainForm.ApplicationEvents1Exception(Sender: TObject; E: Exception);
begin
LogLastException(E, 'Unhandled Exception (%s)', [E.Message], 20);
end;
Now the value of myvar is logged, BUT at the price of I loose the original sourceline of the exception. Instead the line with raise TException.CreateFmt is logged. Any suggestion of how to do both ?
Regards
In addition to Marjan Vennema's answer (which I would follow), you can raise your new exception and make it look like it came from the address of the old exception.
except
on E: Exception do
raise Exception.CreateFmt('myvar = %s', [myvar]) at ExceptAddr;
end;
You are losing the original source line of the exception, because
except
on E: Exception do
raise TException.CreateFmt('myvar = %s', [myvar]);
end;
effectively handles the original exception (making it go away) and raising a new one. Which, of course then will have its own "source line of exception."
@balazs' solution preserves the source line of the original exception in the message of the new exception. @Stephane's solution comes close to the one I would use. Unfortunately he is replacing the original message with only the value of myvar. What I would do is add a line on top of the original message and then just re-raise the exception:
except
on E: Exception do
begin
E.Message := Format('%s'#13#10'%s', [Format('MyVar: %s', [MyVar]), E.Message]);
raise;
end;
end;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With