// 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.