开发者

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 i开发者_高级运维s 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; 


I've you tried something like that ?

 try    
    myvar := MyFunc;    
    ComplexFunc(myvar); 
 except
    on E: Exception do
    begin
      e.message := format('myvar = %s', [myvar]);
      raise ;
    end; 
  end;


I don't know what LogLastException do, but if you can redirect it's result into a string rather than your log, you can reraise the exception like this:

  except
    on E: Exception do
    begin
      str := LogLastExceptionToString(E, 'Unhandled Exception (%s)', [E.Message], 20);  
      raise TException.CreateFmt( str + 'myvar = %s message so far:' , [myvar]);
    end; 
  end;


A simple approach would be to define a global variable, assign the extra information to it, and then add its contents to your log when you log the exception information.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜