简体   繁体   中英

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

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;

一种简单的方法是定义全局变量,为其分配额外信息,然后在记录异常信息时将其内容添加到日志中。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM