Advertisement
RandomClear

How to log all (handled) exceptions

Nov 6th, 2014
758
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 9.31 KB | None | 0 0
  1. // See also: http://pastebin.com/9P0PJcyc - "how to ignore particular exception"
  2.  
  3. // You may want to log catched exceptions from your "except" blocks.
  4. // The best way to do it - is to insert a manual call to logging to each "except" block which you want to log.
  5. // This approach is illustrated here: http://pastebin.com/ACtr0r6S or http://pastebin.com/XWpyDuw6
  6. // Please, use this approach when possible.
  7.  
  8. // Sometimes you may want to log all exceptions in your application.
  9. // For example, if you have too many already written code,
  10. // or if you are using 3rd party code which is not under your control.
  11. // Then you can use "Catch handled exceptions" option to globally trap all exceptions, including handled exceptions.
  12.  
  13.  
  14. //     -= Important Note =-
  15. // Use "Catch handled exceptions" option with caution.
  16. // Never enable this option for production WITHOUT altering processing for handled exceptions.
  17. // Consider this code:
  18.  
  19. for File in Files do
  20.   try
  21.     // ... try to read "File" file ...
  22.   except
  23.     on E: EStreamError do // <- E is catched by your code, thus it is called "handled" exception
  24.       CorruptedFiles.Add(File);
  25.     // <- other exceptions classes are not handled by your code, thus it is called "unhandled" exceptions
  26.   end;
  27. if CorruptedFiles.Count > 0 then
  28.   Application.MessageBox('The following files are corrupted: ' + CorruptedFiles.Text, 'Error.', MB_OK or MB_ICONSTOP);
  29.  
  30. // The above code EXPECTS exceptions coming from guarded code block.
  31. // The code establish a recovery strategy for a certain class of exceptions (EStreamError).
  32. // If you enable "Catch handled exceptions" option - such exceptions will be processes by EurekaLog.
  33. // The code in question DOES NOT expecting that.
  34. // It certainly does not expect error dialogs, long delays (UI, sending, etc.).
  35. // Therefore, you must either enable "Catch handled exceptions" option only for debugging purposes
  36. // OR alter processing of handled exceptions.
  37.  
  38. // -= end of note =-
  39.  
  40.  
  41.  
  42. // You must perform the following 3 steps to log all handled exceptions.
  43.  
  44. // 1. Enable "Catch handled exceptions" option.
  45.  
  46. // 2. Use the following event handler:
  47.  
  48. procedure LogHandledExceptions(const ACustom: Pointer; AExceptionInfo: TEurekaExceptionInfo; var AHandle, ACallNextHandler: Boolean);
  49. begin
  50.   // If exception is handled - change processing logic
  51.   if AExceptionInfo.Handled then
  52.   begin
  53.     LogException(AExceptionInfo, AHandled); // <- see below: option 3a or 3b
  54.     Exit;
  55.   end;
  56.  
  57.   // Unhandled exceptions remains unaltered
  58. end;
  59.  
  60. initialization
  61.   // Note that LogHandledExceptions will not be called for handled exceptions WITHOUT checked "Catch handled exceptions" option
  62.   RegisterEventExceptionNotify(nil, LogHandledExceptions);
  63. end.
  64.  
  65. // 3a. Use the following logging code:
  66.  
  67. procedure LogException(AExceptionInfo: TEurekaExceptionInfo; var AHandle: Boolean);
  68. var
  69.   LogBuilder: TBaseLogBuilder;
  70.   LogFileName: String;
  71. begin
  72.   // Create a generator for log content.
  73.   // You may use default class for your application (LogBuilderClass)
  74.   // Or a specific class (TLogBuilder, TXMLLogBuilder or your own descendant)
  75.   LogBuilder := LogBuilderClass.Create(AEI);  
  76.   try
  77.     // File name to save bug report to.
  78.     // You may use AEI.BugIDStr, if you want to save each report into individual file.
  79.     LogFileName := ExpandEnvVars(AEI.Options.OutputLogFile(''));
  80.     // Generate and save bug report. File will be overwritten.
  81.     LogBuilder.SaveToFile(LogFileName);
  82.   finally
  83.     FreeAndNil(LogBuilder);
  84.   end;
  85.  
  86.   // Disable EurekaLog for this exception
  87.   AHandle := False;
  88. end;
  89.  
  90. // 3b. Or you can use the following logging code:
  91.  
  92. procedure LogException(AExceptionInfo: TEurekaExceptionInfo; var AHandle: Boolean);
  93. begin
  94.   // Set options for "silent" exception
  95.   AExceptionInfo.Options.ExceptionDialogType     := edtNone;  // no dialog
  96.   AExceptionInfo.Options.SenderClasses           := '';       // no sending
  97.   AExceptionInfo.Options.AutoCrashOperation      := tbNone;   // no autocrash counting
  98.   AExceptionInfo.Options.SaveLogFile             := True;     // save bug report to disk
  99.   AExceptionInfo.Options.ExceptionsFilters.Clear;             // ignore exception filters
  100.  
  101.   // Log each exception to individual files
  102.   if ExtractFileExt(AExceptionInfo.Options.OutputPath) <> '' then // if report path contains file name - delete it
  103.     AExceptionInfo.Options.OutputPath := ExtractFilePath(AEI.Options.OutputPath);
  104.   AExceptionInfo.Options.loAddBugIDInLogFileName := True;
  105.   AExceptionInfo.Options.loAddComputerNameInLogFileName := False;
  106.   AExceptionInfo.Options.loAddDateInLogFileName  := False;
  107.   AExceptionInfo.Options.soExcCount              := True;
  108.   AExceptionInfo.Options.ErrorsNumberToSave      := 1;
  109.   AExceptionInfo.Options.loNoDuplicateErrors     := True;
  110.   AExceptionInfo.Options.soAppVersionNumber      := True;     // <- this assumes that you are using version info; comment this otherwise
  111.   AExceptionInfo.Options.loDeleteLogAtVersionChange := True;  // <- this assumes that you are using version info; comment this otherwise
  112.   AExceptionInfo.Options.loSaveProcessesSection  := False;
  113.  
  114.   // Log only exception in current thread
  115.   AExceptionInfo.Options.boPauseRTLThreads       := False;
  116.   AExceptionInfo.Options.boPauseWindowsThreads   := False;
  117.   AExceptionInfo.Options.csoShowWindowsThreads   := False;
  118.   AExceptionInfo.Options.csoShowRTLThreads       := False;
  119.   AExceptionInfo.Options.csoShowELThreads        := False;
  120.  
  121.   // Do not change AHandle - let EurekaLog to process exception
  122. end;
  123.  
  124.  
  125. // -= Differences between 3a and 3b =-
  126.  
  127. // 3a manually logs exceptions and fully disables EurekaLog for it.
  128. // 3b reconfigures exception and let normal flow of EurekaLog code to process it according to altered options.
  129. // Use 3a when you just need a simple .el file for exception.
  130. // Use 3b when you need some of EurekaLog's features (such as counting duplicates).
  131.  
  132. // It is best to stick with option 3a when possible - to minimize overhead of processing handled exceptions.
  133. // Remember, some code may use exceptions a lot
  134. // (for example, a certain well-known components set uses exceptions in OnDraw handler -
  135. // which means insane amount of exceptions during normal workflow of application;
  136. // adding processing overhead for such exceptions may greatly slow down your application).
  137.  
  138. // Another "gotcha" when using logging of handled exceptions:
  139. // You may log handled exceptions into individual bug report files,
  140. // then attach these files to bug report for unhandled exception.
  141. // This will deliver all handled exceptions bug reports to you.
  142. // For example:
  143.  
  144. uses
  145.   SyncObjs;
  146.  
  147. var
  148.   HandledExceptionsFiles: TStringList;
  149.   HandledExceptionsFilesCS: TCriticalSection; // <- protects access to global HandledExceptionsFiles in multi-threaded application
  150.  
  151. procedure LogException(AExceptionInfo: TEurekaExceptionInfo; var AHandle: Boolean);
  152. var
  153.   LogFileName: String;
  154. begin
  155.   // ...
  156.  
  157.   // Construct file name to save .el bug report to
  158.   LogFileName := ExtractFilePath(ExpandEnvVars(AEI.Options.OutputLogFile(''))) + 'Handled.el'; // <- just an example
  159.  
  160.   // Remember this file:
  161.   HandledExceptionsFilesCS.Enter;
  162.   try
  163.     if HandledExceptionsFiles = nil then
  164.     begin
  165.       HandledExceptionsFiles := TStringList.Create;
  166.       HandledExceptionsFiles.Sorted := True;
  167.       HandledExceptionsFiles.Duplicates := dupIgnore;
  168.     end;
  169.     HandledExceptionsFiles.Add(LogFileName);
  170.   finally
  171.     HandledExceptionsFilesCS.Leave;
  172.   end;
  173.  
  174.   // ...
  175.   //  <- Use LogFileName to save bug report, e.g. LogBuilder.SaveToFile(LogFileName) or AEI.Options.OutputPath := LogFileName;
  176.   // ...
  177. end;
  178.  
  179. // Service routine: cleanups HandledExceptionsFiles with deleting all files
  180. procedure DeleteHandledExceptionsFiles;
  181. var
  182.   X: Integer;
  183. begin
  184.   HandledExceptionsFilesCS.Enter;
  185.   try
  186.     if HandledExceptionsFiles = nil then
  187.       Exit;
  188.  
  189.     for X := 0 to HandledExceptionsFiles.Count - 1 do
  190.       DeleteFile(HandledExceptionsFiles[X]);
  191.  
  192.     FreeAndNil(HandledExceptionsFiles);
  193.   finally
  194.     HandledExceptionsFilesCS.Leave;
  195.   end;
  196. end;
  197.  
  198. procedure AttachHandledReports(const ACustom: Pointer; AExceptionInfo: TEurekaExceptionInfo;  const ATempFolder: String; AAttachedFiles: TStrings; var ACallNextHandler: Boolean);
  199. var
  200.   X: Integer;
  201.   DestFileName: string;
  202. begin
  203.   HandledExceptionsFilesCS.Enter;
  204.   try
  205.     if HandledExceptionsFiles = nil then
  206.       Exit;
  207.  
  208.     // Attach all files from HandledExceptionsFiles
  209.     for X := 0 to HandledExceptionsFiles.Count - 1 do
  210.     begin
  211.       DestFileName := ATempFolder + ExtractFileName(HandledExceptionsFiles[X]);
  212.       if CopyFile(PChar(HandledExceptionsFiles[X]), PChar(DestFileName), True) then
  213.         AAttachedFiles.Add(DestFileName);
  214.     end;
  215.  
  216.     // Files are attached and no longer needed - delete them
  217.     DeleteHandledExceptionsFiles;
  218.   finally
  219.     HandledExceptionsFilesCS.Leave;
  220.   end;
  221. end;
  222.  
  223. initialization
  224.   HandledExceptionsFilesCS := TCriticalSection.Create;
  225.   // "Pack send files into single file (.elp)" option is checked?
  226.   if CurrentEurekaLogOptions.sndPack then
  227.     RegisterEventZippedFilesRequest(nil, AttachHandledReports)     // if yes - add reports inside .elp
  228.   else
  229.     RegisterEventAttachedFilesRequest(nil, AttachHandledReports);  // otherwise - add reports side-by-side with .el
  230. finalization
  231.   DeleteHandledExceptionsFiles;
  232.   FreeAndNil(HandledExceptionsFilesCS);
  233. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement