There are cases when you need to change the message of the exception. For example:
• | You want to hide technical details from user. For example, show "Sorry, there was a problem" instead of technical gibberish like "Access Violation at address 12345678"; |
• | You want to add more details or enhance the description. For example, add a file name to the "File open error". |
EurekaLog offers various ways to change the exception message:
1. | Override. Overriding exception message will show new message to a user in various dialogs. However, the bug report will contain the original exception message. E.g. a user will see "Sorry, the was a problem", while you (as developer) will see (via bug report) "Access Violation at address 12345678". In other words, exception's message will be different in EurekaLog and exception object. |
2. | Replace. Replacing exception message will replace the exception message itself. Both bug report and dialog will show the same changed message. This is typically used if you need to update the exception by adding additional information. In other words, both EurekaLog and exception object will use the same message. |
1. Overriding the message
Overriding exception message will show new message to a user in various dialogs. However, the bug report will contain the original exception message. E.g. a user will see "Sorry, the was a problem", while you (as developer) will see (via bug report) "Access Violation at address 12345678". In other words, exception's message will be different in EurekaLog and exception object.
Override message for all exceptions
If you want to hide all exception messages and show something like "Sorry, there was an error in the application" instead - you can use exception filters. Simply add a new filter to override message for all exceptions:
1. | Open Project / EurekaLog options; |
2. | Go to Advanced / Exception filters tab; |
3. | Click on the "Add" button; |
4. | Enter "Exception" (without quotes) as "Exception Class" and make sure that "Include child classes" option is checked; |
5. | Switch to "Altering behaviour" tab and set "Override Exception Message" option to whatever text you like. |
6. | Don't change anything else and save the new filter. |
You can also do the same with the following code at run-time:
uses
EModules, // for CurrentEurekaLogOptions
ETypes; // for TEurekaExceptionFilter
procedure AddFilters;
var
Filter: TEurekaExceptionFilter;
begin
FillChar(Filter, SizeOf(Filter), 0);
// Matching:
Filter.Active := True;
Filter.ExceptionClassName := 'Exception';
Filter.IncludeChildClasses := True;
// Altering behaviour:
Filter.HandlerType := fhtEurekaLog;
Filter.ExceptionMessage := 'Sorry, there was a problem.';
Filter.DialogType := edtUnchanged;
Filter.ActionType := fatUnchanged;
CurrentEurekaLogOptions.ExceptionsFilters.Add(Filter);
Finalize(Filter);
end;
initialization
AddFilters;
end.
Notes:
• | If you are going to add more filters later - make sure that this filter (for the "Exception" class) is the last one to be added; |
• | If you are going to use any other filter - don't forget to also specify the "Override Exception Message" option for each filter. |
Override message only for a specific exception
There are several ways to override message of a particular exception. You need to be able to identify the desired exception - either via its class/other properties or via throwing location.
Option1: use exception filters
If you can identify the exception by using the exception filters - you can do the same as above, but replacing "Exception" class with any other info that can identify your exceptions.
Option2: use custom attributes
If you need to replace exception message only for exceptions of the specific class - you can use custom attributes (available in modern IDEs).
uses
EClasses; // for EurekaLogMessage
type
[EurekaLogMessage('Sorry, there was a problem.')]
EMyException = class(Exception);
procedure TForm1.Button1Click(Sender: TObject);
begin
raise EMyException.Create('Error Message');
end;
Option 3: use event handlers
If you need complete control over properties of the exception - you can use event handlers:
uses
EEvents, // for RegisterEventExceptionNotify
EException; // for TEurekaExceptionInfo
procedure OverrideMessage(const ACustom: Pointer;
AExceptionInfo: TEurekaExceptionInfo;
var AHandle: Boolean;
var ACallNextHandler: Boolean);
begin
// Find our exception
// This is only an example
// You can add more checks
if AExceptionInfo.ExceptionClass = 'EMyException' then
begin
// Override exception message
AExceptionInfo.AdditionalInfo := 'Sorry, there was a problem.';
// Tells EurekaLog to use the .AdditionalInfo property instead of real message
AExceptionInfo.Options.UseExceptionComments := True;
end;
end;
initialization
RegisterEventExceptionNotify(nil, OverrideMessage);
end.
Here is an example of how you can check various properties of your exception (we recommend to specify as much as you can):
procedure OverrideMessage(const ACustom: Pointer;
AExceptionInfo: TEurekaExceptionInfo;
var AHandle: Boolean;
var ACallNextHandler: Boolean);
begin
if // check exception class name
(AExceptionInfo.ExceptionClass = 'EOSError') and
// check exception message
(AExceptionInfo.ExceptionMessage = 'Access Denied') and
// check that there is exception object
(AExceptionInfo.ExceptionObject <> nil) and
// check that it is a Delphi/Builder object
(AExceptionInfo.ExceptionNative) and
// check exception class
// (only for .ExceptionNative = True and .ExceptionObject <> nil)
(TObject(AExceptionInfo.ExceptionObject).InheritsFrom(EOSError)) and
// IMPORTANT NOTE: Please note that the .ExceptionObject may be unavailable even for Delphi exceptions!
// For example, if the exception object was already deleted:
//
// try
// raise Exception.Create('Inner Exception'); // - will be deleted
// except
// on E: Exception do
// raise Exception.Create('Outer Exception');
// end;
//
// See also.
// That is why we check for NIL in the example above.
// For this reason we highly recommend to use properties of AExceptionInfo when possible,
// Such as .ExceptionClass and .ExceptionMessage
// check any additional exception properties
(EOSError(AExceptionInfo.ExceptionObject).ErrorCode = ERROR_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 = Pointer($00456789)) and
// check exception module
(AExceptionInfo.Module = $00400000) and
(AExceptionInfo.Module = HInstance) 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
(not AExceptionInfo.Handled) and
AExceptionInfo.SafeCallExpt and
AExceptionInfo.ThreadException
AExceptionInfo.InitializationException then
begin
// ...
Exit;
end;
end;
Option 4: if you need to override message for a specific location rather than exception itself - then you can wrap the target code in a construct like this:
uses
EExceptionManager, // for ExceptionManager
EException, // TEurekaExceptionInfo
var
EI: TEurekaExceptionInfo;
begin
try
// ... your actual code here ...
except
on E: Exception do
begin
// Obtain EurekaLog's exception info
EI := ExceptionManager.Info(E);
// It could be nil if EurekaLog is disabled
// or when EurekaLog is instructed to ignore this exception
if Assigned(EI) then
begin
// Override exception message
EI.AdditionalInfo := 'Sorry, there was a problem';
// Tells EurekaLog to use the .AdditionalInfo property instead of real message
EI.Options.UseExceptionComments := True;
end;
// Continue unwinding
raise;
end;
end;
end;
See also: how to get exception info?
2. Replacing the message
Replacing exception message will replace the exception message itself. Both bug report and dialog will show the same changed message. This is typically used if you need to update the exception by adding additional information. In other words, both EurekaLog and exception object will use the same message.
Replace exception message for a specific exception
You can use the SetExceptionMessage function:
uses
EBase; // for SetExceptionMessage
try
// ... your actual code here ...
except
on E: Exception do
begin
// Changes both E.Message and EurekaLog's exception info
SetExceptionMessage(E,
Format('Error Opening File "%s": %s',
[AFileName, E.Message]));
// Continue unwinding
raise;
end;
end;
See also:
Send feedback...
|
Build date: 2024-09-30
Last edited: 2023-08-09
|
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_override_exception_message.php
|
|