Root > How to... > ...mark the exception as expected?

...mark the exception as expected?

Previous pageReturn to chapter overviewNext page   

Some exceptions does not indicate bugs in your code. I.e. are part of normal execution of your application. Such exceptions are called "expected". See this article for more information.

 

Marking exception as expected will disable bug report, sending, while keeps showing dialog to the user (error message).

 

First, you have to identify exception which you want to mark as expected. You can identify exception by:

Exception class name;
Exception module;
Exception location:
oRoutine;
oLine;
oAddress or offset;
Exception message;
Exception thread;
Other information.

 

Once exception is identified - you can instruct EurekaLog to threat this exception as expected. EurekaLog considers exception to be expected when it has non-zero "Expected Context ID" or non-empty "Expected Context URL". Basically, those act like HelpContext and HelpKeyword. You can assign meaningful value to show a Help button which will open corresponding help article or web-page. Or you can simply use -1 as context ID.

 

Optionally, you may want to assign a pre-defined fixed BugID for such exceptions.

 

Note: you may want to ignore exception instead of marking it as expected.

 

There are several available methods. This article covers the following options:

1. Use custom attributes
2. Use filters
3. Use event handlers
4. Use code to explicitly raise exception as expected
5. Use code to explicitly mark exception as expected

 

 

Option 1

Use custom attributes:

 

uses
  EClasses,
  ETypes;
 
type
  // Mark exception as expected
  [EurekaLogExpected()]
  ETestException = class(Exception);
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  // ETestException will be shown by EurekaLog 
  // as if EurekaLog would be disabled.
  // E.g. no bug report will be saved,

  // no send options will be shown,
  // no details (e.g. call stack) will be visible,

  // no restart options will be visible.

  // In other words: it will look like a simple MessageBox
  raise ETestException.Create('Error Message');
end;

 

Another example:

 

uses
  EClasses;
 
type
  // Mark exception as expected, assign help topic ID = 1234, 

  // show "Help" button in dialogs
  [EurekaLogExpected(1234)]
  EMyException2 = class(Exception);
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  // ETestException will be handled by EurekaLog 

  // as in previous example.
  // However, a "Help" button will be present.

  // Clicking on "Help" button will trigger

  // help system with HelpContext = 1234
  raise ETestException.Create('Error Message');
end;

 

Another example:

 

uses
  EClasses;
 
type
  // Mark exception as expected, assign online help topic (URL), 

  // show "Help" button in dialogs
  [EurekaLogExpected(0, 'http://www.example.com/kb/low_memory.asp')]
  ETestException = class(Exception);
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  // Same like before.

  // "Help" button will be visible.

  // Clicking on "Help" button will open

  // http://www.example.com/kb/low_memory.asp web-page.
  raise ETestException.Create('Error Message');
end;

 

Another example:

 

uses
  EClasses;
 
type
  // Mark exception as expected, assign a fixed BugID
  [EurekaLogExpected(-1, '', $00000001)]
  ETestException = class(Exception); 

 
procedure TForm1.Button1Click(Sender: TObject);
begin
  // ETestException will be handled by EurekaLog

  // as in the first example above.

  // However, the exception will always have 

  // the same fixed BugID.
  raise ETestException.Create('Error Message');
end;

 

Read more about this method.

 

 

Option 2

Use exception filters. Typically, you create exception filters at design-time:

 

 

Ignoring ETestException exception

 

However, you can also create exception filters manually from code:

 

uses
  EModules;
 
  CurrentEurekaLogOptions.ExceptionsFilters.AddExpectedException(ETestException);
 
  // ETestException will be handled by EurekaLog.
  // However, it would be considered as expected.
  // "details", "send" and "restart" options will not be shown.
  raise ETestException.Create('Error Message');

 

Another example:

 

uses
  EModules,
  ETypes;
 
// Create custom filter:
var
  Filter: TEurekaExceptionFilter;
begin
  FillChar(Filter, SizeOf(Filter), 0);
 
  Filter.Active := True;
  Filter.ExceptionClassName := ETestException.ClassName;
  Filter.ExceptionType := fetAll;
  Filter.DialogType := edtUnchanged;
  Filter.HandlerType := fhtEurekaLog;
  Filter.ActionType := fatUnchanged;

  Filter.ExpectedContext := -1;

  Filter.ExpectedURL := '';

  Filter.ExpectedBugID := $00000001;
 
  CurrentEurekaLogOptions.ExceptionsFilters.Add(Filter);
 
  // ETestException will be handled by EurekaLog.
  // However, it would be considered as expected.
  // "details", "send" and "restart" options will not be shown.
  raise ETestException.Create('Error Message');
end;

 

Read more about this method here.

 

 

Option 3

Use event handlers.

 

uses
  EEvents; // for RegisterEventExceptionNotify
 
type
  ETestException = class(Exception);
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  // ETestException will be handled by EurekaLog.
  // However, it would be considered as expected.
  // "details", "send" and "restart" options will not be shown.
  raise ETestException.Create('Error Message');
end;
 
procedure ExceptionNotify(const ACustom: Pointer; 

  AExceptionInfo: TEurekaExceptionInfo; 

  var AHandle: Boolean; 

  var ACallNextHandler: Boolean);
begin
  // Mark exception as expected, but allow it to be handled by EurekaLog.

 
  if // this check matches ETestException only, but skips child classes

     AExceptionInfo.ExceptionClass = ETestException.ClassName then 
  begin
    AExceptionInfo.ExpectedContext := -1;
    Exit;
  end;
end;
 
initialization
  RegisterEventExceptionNotify(nil, ExceptionNotify);
end.

 

Another example:

 

uses
  EEvents; // for RegisterEventExceptionNotify
 
type
  ETestException = class(Exception);
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  // ETestException will be handled by EurekaLog.
  // However, it would be considered as expected.
  // "details", "send" and "restart" options will not be shown.

  // Additionally, a "Help" button will be shown.
  raise ETestException.Create('Error Message');
end;
 
procedure ExceptionNotify(const ACustom: Pointer; 

  AExceptionInfo: TEurekaExceptionInfo; 

  var AHandle: Boolean; 

  var ACallNextHandler: Boolean);
begin
  // Mark exception as expected, but allow it to be handled by EurekaLog.
  if (AExceptionInfo.ExceptionObject <> niland
     (AExceptionInfo.ExceptionNative) and

     // this check matches ETestException and any of its child classes
     (Exception(AExceptionInfo.ExceptionObject).InheritsFrom(ETestException)) and 
     (AExceptionInfo.ExceptionMessage = 'Error Message'then
  begin
    AExceptionInfo.ExpectedURL := 'http://www.example.com/kb/low_memory.asp';

    AExceptionInfo.BugID := $00000001;
    Exit;
  end;
end;
 
initialization
  RegisterEventExceptionNotify(nil, ExceptionNotify);
end.

 

Here is an example of how you can check various properties of your exception:

 

procedure ExceptionNotify(const ACustom: Pointer; 

  AExceptionInfo: TEurekaExceptionInfo; 

  var AHandle: Boolean; 

  var ACallNextHandler: Boolean);
begin

  if // check that there is exception object

     (AExceptionInfo.ExceptionObject <> niland 

     // check that it is a Delphi/Builder object
     (AExceptionInfo.ExceptionNative) and 

     // check exception class
     (Exception(AExceptionInfo.ExceptionObject).InheritsFrom(EOSError)) and 

     // check any additional exception properties
     (EOSError(AExceptionInfo.ExceptionObject).ErrorCode = ERROR_ACCESS_DENIED) and 

     // check exception class
     (AExceptionInfo.ExceptionClass = 'EOSError'and 

     // check exception message
     (AExceptionInfo.ExceptionMessage = 'Access Denied'and 

     // check call stack
     (AExceptionInfo.CallStack.Count > 0) and 
     (AExceptionInfo.CallStack[0].Location.UnitName = 'ServiceProvider'and
     (AExceptionInfo.CallStack[0].Location.ProcedureName = 'Connect'and

     // check exception address
     (AExceptionInfo.Address = $00456789) and 

     // check exception module
     (AExceptionInfo.Module = $00400000) and 

     // check exception module name
     SameFileName(ExtractFileName(AExceptionInfo.ModuleName), 'Project1.exe'and 

     // check exception thread
     (AExceptionInfo.ThreadID = MainThreadID) and 

     // check for known BugID
     (AExceptionInfo.BugID = $E36F0000) and 

     // check for handler (what hook has catched the exception)
     (AExceptionInfo.Handler = atVCL) and 

     // check for misc. props
     AExceptionInfo.Handled and 
     AExceptionInfo.SafeCallExpt and
     AExceptionInfo.ThreadException
     AExceptionInfo.InitializationException then
  begin
    // ...
    Exit;
  end;
end;

 

Read more about this method here.

 

 

Option 4

Use explicit code to raise expected exception.

 

uses
  EBase;
 
procedure TDocument.Load;
begin
  FStream := { ... };
  if FStream.Size < SizeOf(THeader) then
    // Use EBase.RaiseExpected to 

    // raise any exception object as expected
    RaiseExpected(ELoadErrorMissingHeader.Create(rsNoHeader));
end;

 

Another example:

 

uses
  EBase;
 
procedure TDocument.Load;
begin
  FStream := { ... };
  if FStream.Size < SizeOf(THeader) then
    // Raise expected exception with the specified context
    RaiseExpected(ELoadErrorMissingHeader.Create(rsNoHeader),

      1234);
end;

 

Another example:

 

uses
  EBase;
 
procedure TDocument.Load;
begin
  FStream := { ... };
  if FStream.Size < SizeOf(THeader) then
    // Raise expected exception with the specified URL
    RaiseExpected(ELoadErrorMissingHeader.Create(rsNoHeader),

      'http://www.example.com/kb/low_memory.asp');
end;

 

Another example:

 

uses
  EBase;
 
procedure TDocument.Load;
begin
  FStream := { ... };
  if FStream.Size < SizeOf(THeader) then
    // Raise expected exception with the fixed BugID
    RaiseExpected(ELoadErrorMissingHeader.Create(rsNoHeader), 

      -1, $00000001);
end;

 

 

Option 5

Use explicit code to mark existing exception as expected.

 

uses
  EBase;
 
procedure TDocument.Load;
begin
  try
    FStream := { ... };
  except
    on E: EStreamError do
    begin
      // Use EBase.MarkExpected to 
      // mark existing exception as expected
      MarkExpected(E);
      raise;
    end;
  end
end;

 

Another example:

 

uses
  EBase;
 
procedure TDocument.Load;
begin
  try
    FStream := { ... };
  except
    on E: EStreamError do
    begin
      // Raise expected exception with the specified context
      MarkExpected(E, 1234);
      raise;
    end;
  end
end;

 

Another example:

 

uses
  EBase;
 
procedure TDocument.Load;
begin
  try
    FStream := { ... };
  except
    on E: EStreamError do
    begin
      // Raise expected exception with the specified URL
      MarkExpected(E, 

        'http://www.example.com/kb/low_memory.asp');

      raise;
    end;
  end
end;

 

Another example:

 

uses
  EBase;
 
procedure TDocument.Load;
begin
  try
    FStream := { ... };
  except
    on E: EStreamError do
    begin
      // Raise expected exception with the fixed BugID
      MarkExpected(E, -1, $00000001);
      raise;
    end;
  end
end;

 

 

See also:




Send feedback... Build date: 2018-11-26
Last edited: 2018-10-29
PRIVACY STATEMENT
The documentation team uses the feedback submitted to improve the EurekaLog documentation. We do not use your e-mail address for any other purpose. We will remove your e-mail address from our system after the issue you are reporting has been resolved. While we are working to resolve this issue, we may send you an e-mail message to request more information about your feedback. After the issues have been addressed, we may send you an email message to let you know that your feedback has been addressed.


Permanent link to this article: https://www.eurekalog.com/help/eurekalog/how_to_mark_exception_as_expected.php