// See also: http://pastebin.com/9P0PJcyc - "how to ignore particular exception"
// You may want to log catched exceptions from your "except" blocks.
// The best way to do it - is to insert a manual call to logging to each "except" block which you want to log.
// This approach is illustrated here: http://pastebin.com/ACtr0r6S or http://pastebin.com/XWpyDuw6
// Please, use this approach when possible.
// Sometimes you may want to log all exceptions in your application.
// For example, if you have too many already written code,
// or if you are using 3rd party code which is not under your control.
// Then you can use "Catch handled exceptions" option to globally trap all exceptions, including handled exceptions.
// -= Important Note =-
// Use "Catch handled exceptions" option with caution.
// Never enable this option for production WITHOUT altering processing for handled exceptions.
// Consider this code:
for File in Files do
try
// ... try to read "File" file ...
except
on E: EStreamError do // <- E is catched by your code, thus it is called "handled" exception
CorruptedFiles.Add(File);
// <- other exceptions classes are not handled by your code, thus it is called "unhandled" exceptions
end;
if CorruptedFiles.Count > 0 then
Application.MessageBox('The following files are corrupted: ' + CorruptedFiles.Text, 'Error.', MB_OK or MB_ICONSTOP);
// The above code EXPECTS exceptions coming from guarded code block.
// The code establish a recovery strategy for a certain class of exceptions (EStreamError).
// If you enable "Catch handled exceptions" option - such exceptions will be processes by EurekaLog.
// The code in question DOES NOT expecting that.
// It certainly does not expect error dialogs, long delays (UI, sending, etc.).
// Therefore, you must either enable "Catch handled exceptions" option only for debugging purposes
// OR alter processing of handled exceptions.
// -= end of note =-
// You must perform the following 3 steps to log all handled exceptions.
// 1. Enable "Catch handled exceptions" option.
// 2. Use the following event handler:
procedure LogHandledExceptions(const ACustom: Pointer; AExceptionInfo: TEurekaExceptionInfo; var AHandle, ACallNextHandler: Boolean);
begin
// If exception is handled - change processing logic
if AExceptionInfo.Handled then
begin
LogException(AExceptionInfo, AHandled); // <- see below: option 3a or 3b
Exit;
end;
// Unhandled exceptions remains unaltered
end;
initialization
// Note that LogHandledExceptions will not be called for handled exceptions WITHOUT checked "Catch handled exceptions" option
RegisterEventExceptionNotify(nil, LogHandledExceptions);
end.
// 3a. Use the following logging code:
procedure LogException(AExceptionInfo: TEurekaExceptionInfo; var AHandle: Boolean);
var
LogBuilder: TBaseLogBuilder;
LogFileName: String;
begin
// Create a generator for log content.
// You may use default class for your application (LogBuilderClass)
// Or a specific class (TLogBuilder, TXMLLogBuilder or your own descendant)
LogBuilder := LogBuilderClass.Create(AEI);
try
// File name to save bug report to.
// You may use AEI.BugIDStr, if you want to save each report into individual file.
LogFileName := ExpandEnvVars(AEI.Options.OutputLogFile(''));
// Generate and save bug report. File will be overwritten.
LogBuilder.SaveToFile(LogFileName);
finally
FreeAndNil(LogBuilder);
end;
// Disable EurekaLog for this exception
AHandle := False;
end;
// 3b. Or you can use the following logging code:
procedure LogException(AExceptionInfo: TEurekaExceptionInfo; var AHandle: Boolean);
begin
// Set options for "silent" exception
AExceptionInfo.Options.ExceptionDialogType := edtNone; // no dialog
AExceptionInfo.Options.SenderClasses := ''; // no sending
AExceptionInfo.Options.AutoCrashOperation := tbNone; // no autocrash counting
AExceptionInfo.Options.SaveLogFile := True; // save bug report to disk
AExceptionInfo.Options.ExceptionsFilters.Clear; // ignore exception filters
// Log each exception to individual files
if ExtractFileExt(AExceptionInfo.Options.OutputPath) <> '' then // if report path contains file name - delete it
AExceptionInfo.Options.OutputPath := ExtractFilePath(AEI.Options.OutputPath);
AExceptionInfo.Options.loAddBugIDInLogFileName := True;
AExceptionInfo.Options.loAddComputerNameInLogFileName := False;
AExceptionInfo.Options.loAddDateInLogFileName := False;
AExceptionInfo.Options.soExcCount := True;
AExceptionInfo.Options.ErrorsNumberToSave := 1;
AExceptionInfo.Options.loNoDuplicateErrors := True;
AExceptionInfo.Options.soAppVersionNumber := True; // <- this assumes that you are using version info; comment this otherwise
AExceptionInfo.Options.loDeleteLogAtVersionChange := True; // <- this assumes that you are using version info; comment this otherwise
AExceptionInfo.Options.loSaveProcessesSection := False;
// Log only exception in current thread
AExceptionInfo.Options.boPauseRTLThreads := False;
AExceptionInfo.Options.boPauseWindowsThreads := False;
AExceptionInfo.Options.csoShowWindowsThreads := False;
AExceptionInfo.Options.csoShowRTLThreads := False;
AExceptionInfo.Options.csoShowELThreads := False;
// Do not change AHandle - let EurekaLog to process exception
end;
// -= Differences between 3a and 3b =-
// 3a manually logs exceptions and fully disables EurekaLog for it.
// 3b reconfigures exception and let normal flow of EurekaLog code to process it according to altered options.
// Use 3a when you just need a simple .el file for exception.
// Use 3b when you need some of EurekaLog's features (such as counting duplicates).
// It is best to stick with option 3a when possible - to minimize overhead of processing handled exceptions.
// Remember, some code may use exceptions a lot
// (for example, a certain well-known components set uses exceptions in OnDraw handler -
// which means insane amount of exceptions during normal workflow of application;
// adding processing overhead for such exceptions may greatly slow down your application).
// Another "gotcha" when using logging of handled exceptions:
// You may log handled exceptions into individual bug report files,
// then attach these files to bug report for unhandled exception.
// This will deliver all handled exceptions bug reports to you.
// For example:
uses
SyncObjs;
var
HandledExceptionsFiles: TStringList;
HandledExceptionsFilesCS: TCriticalSection; // <- protects access to global HandledExceptionsFiles in multi-threaded application
procedure LogException(AExceptionInfo: TEurekaExceptionInfo; var AHandle: Boolean);
var
LogFileName: String;
begin
// ...
// Construct file name to save .el bug report to
LogFileName := ExtractFilePath(ExpandEnvVars(AEI.Options.OutputLogFile(''))) + 'Handled.el'; // <- just an example
// Remember this file:
HandledExceptionsFilesCS.Enter;
try
if HandledExceptionsFiles = nil then
begin
HandledExceptionsFiles := TStringList.Create;
HandledExceptionsFiles.Sorted := True;
HandledExceptionsFiles.Duplicates := dupIgnore;
end;
HandledExceptionsFiles.Add(LogFileName);
finally
HandledExceptionsFilesCS.Leave;
end;
// ...
// <- Use LogFileName to save bug report, e.g. LogBuilder.SaveToFile(LogFileName) or AEI.Options.OutputPath := LogFileName;
// ...
end;
// Service routine: cleanups HandledExceptionsFiles with deleting all files
procedure DeleteHandledExceptionsFiles;
var
X: Integer;
begin
HandledExceptionsFilesCS.Enter;
try
if HandledExceptionsFiles = nil then
Exit;
for X := 0 to HandledExceptionsFiles.Count - 1 do
DeleteFile(HandledExceptionsFiles[X]);
FreeAndNil(HandledExceptionsFiles);
finally
HandledExceptionsFilesCS.Leave;
end;
end;
procedure AttachHandledReports(const ACustom: Pointer; AExceptionInfo: TEurekaExceptionInfo; const ATempFolder: String; AAttachedFiles: TStrings; var ACallNextHandler: Boolean);
var
X: Integer;
DestFileName: string;
begin
HandledExceptionsFilesCS.Enter;
try
if HandledExceptionsFiles = nil then
Exit;
// Attach all files from HandledExceptionsFiles
for X := 0 to HandledExceptionsFiles.Count - 1 do
begin
DestFileName := ATempFolder + ExtractFileName(HandledExceptionsFiles[X]);
if CopyFile(PChar(HandledExceptionsFiles[X]), PChar(DestFileName), True) then
AAttachedFiles.Add(DestFileName);
end;
// Files are attached and no longer needed - delete them
DeleteHandledExceptionsFiles;
finally
HandledExceptionsFilesCS.Leave;
end;
end;
initialization
HandledExceptionsFilesCS := TCriticalSection.Create;
// "Pack send files into single file (.elp)" option is checked?
if CurrentEurekaLogOptions.sndPack then
RegisterEventZippedFilesRequest(nil, AttachHandledReports) // if yes - add reports inside .elp
else
RegisterEventAttachedFilesRequest(nil, AttachHandledReports); // otherwise - add reports side-by-side with .el
finalization
DeleteHandledExceptionsFiles;
FreeAndNil(HandledExceptionsFilesCS);
end.
Comments
0 B
|👍
/👎
0 B
|👍
/👎