Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Howto log source line causing exception and add custom information?

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

like image 381
Roland Bengtsson Avatar asked Dec 21 '22 10:12

Roland Bengtsson


2 Answers

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;
like image 78
The_Fox Avatar answered Dec 24 '22 01:12

The_Fox


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; 
like image 35
Marjan Venema Avatar answered Dec 24 '22 01:12

Marjan Venema