This article is a continuation of how to deal with send failures article. If you are looking for local bug reports - take a look at bug report file settings.
You may want to store bug reports to some local offline storage (such as a directory) instead of sending reports. You may send reports from such offline storage via some other means later - external background process, task scheduler, etc.
EurekaLog do not offer build-in implementation for such feature, because of many questions:
• | How should EurekaLog limit size of this storage? |
• | How often should EurekaLog clean it? |
• | What if application is uninstalled: who will clear the storage? |
• | How uninstaller will know about EurekaLog's storage location? |
• | Who and when will resend reports from storage? |
• | Should EurekaLog resend on application's startup? |
• | Should EurekaLog resend when another exception occur? |
• | What if application is non-GUI? |
• | What if startup time is important? |
• | What if next exception never occur? |
• | Should EurekaLog monitor network for availability? |
• | What if application is a DLL or COM object; in other words: it can not run by itself to resend reports? |
• | If you will perform sending from another process - what about firewall? Your application may be allowed in firewall, while some random background process is not. |
You have to answer each question before even starting with writing the code.
Application
You have to save bug report with all additional files and options into some storage. The following code illustrates this by saving files into sub-folders. Options for sending are saved to params.json file. You may use this code as is; you may modify it; or you may write your own code based on this example.
uses
EDLLs, // for CoCreateGuid
ESend, // for TELUniversalSender and RegisterSender
EModules, // for CurrentEurekaLogOptions
ESysInfo, // for GetFolderAppData
EJSON, // for JSONCreate and IJSONValues
EEncoding, // for TextToFile
ETypes; // for TResponse
type
// Create a new "send engine".
// It will be dummy that will perform no actual sending.
// Instead - it will save all files attachments to folder (offline storage).
TSaveToFolder = class(TELUniversalSender)
public
function SendMessage: TResponse; override;
end;
// The dummy send function will simply copy bug report files to the specified folder
// Folder is hard-coded inside; but you may specify it via options
function TSaveToFolder.SendMessage: TResponse;
// Copies bug report files to the specified folder
// Also creates parameters file with send options
procedure CopyBugReport(const AFolder: String);
// Create parameters file, which will contain list of options and files to send
procedure CreateSendParams(const AFolder: String);
function CopyCurrentEurekaLogOptionsToJSON: IJSONValues;
var
Options: TStringList;
X: Integer;
begin
Result := JSONCreate;
Options := TStringList.Create;
try
// .Options property of current sender engine is
// a copy of CurrentEurekaLogOptions
// See for more info
Options.Assign(Self.Options);
for X := 0 to Options.Count - 1 do
Result[Options.Names[X]] := Options.ValueFromIndex[X];
finally
FreeAndNil(Options);
end;
end;
function CopyBugReportFilesToJSON: IJSONValues;
var
X: Integer;
begin
Result := JSONCreate;
Result['count'] := AttachedFiles.Count;
for X := 0 to AttachedFiles.Count - 1 do
Result['file' + IntToStr(X)] := AFolder + ExtractFileName(AttachedFiles[X]);
end;
var
JSON: IJSONValues;
begin
JSON := JSONCreate;
JSON.Items['files'] := CopyBugReportFilesToJSON;
JSON.Items['options'] := CopyCurrentEurekaLogOptionsToJSON;
TextToFile(AFolder + 'params.json', JSON.ToString, TEncoding.Unicode);
end;
var
Folder: String;
GUID: TGUID;
X: Integer;
begin
// Create sub-folder for bug report
if Failed(CoCreateGuid(GUID)) then
Folder := IncludeTrailingPathDelimiter(AFolder) +
ChangeFileExt(ExtractFileName(AttachedFiles[0]), '') +
PathDelim
else
Folder := IncludeTrailingPathDelimiter(AFolder) +
GUIDToString(GUID) + '_' + ChangeFileExt(ExtractFileName(AttachedFiles[0]), '') +
PathDelim;
ForceDirectories(Folder);
// Create parameters file, which will contain list of options and files to send
CreateSendParams(Folder);
// Copy primary attachment (.elp bug report)
Win32Check(CopyFile(PChar(AttachedFiles[0]),
PChar(Folder + ExtractFileName(AttachedFiles[0])), False));
if AttachedFiles.Count = 1 then
Exit;
// Copy all remaining files attachments to some folder.
// Usually there is only one file (.elp), but it can be several files -
// depends on your project options and your customization code
for X := 1 to AttachedFiles.Count - 1 do
Win32Check(CopyFile(PChar(AttachedFiles[X]),
PChar(Folder + ExtractFileName(AttachedFiles[X])), False));
end;
begin
Finalize(Result);
FillChar(Result, SizeOf(Result), 0);
try
if AttachedFiles.Count = 0 then
begin
// We should not really get there, this is just fail-safe check
Result.SendResult := srNoExceptionInfo;
Exit;
end;
CopyBugReport(GetFolderAppData + 'YourApp' + PathDelim + 'BugReports');
// Alternative:
// CopyBugReport(ExpandEnvVars(Options.CustomField['Custom_BugReportFolder']));
//
// You must enter "Custom_BugReportFolder" value in Custom / Manual page
// of EurekaLog's project options, e.g.:
// Custom_BugReportFolder="%APPDATA%\\YourApp\\BugReports"
//
// See for more info
// Indicate that "send" was a success.
Result.SendResult := srSent;
except
on E: Exception do
begin
// Indicate that "send" was a failure.
Result.SendResult := srUnknownError;
if E is EOSError then
Result.ErrorCode := Integer(EOSError(E).ErrorCode);
Result.ErrorMessage := E.Message;
end;
end;
end;
initialization
// Register our fake send engine
RegisterSenderFirst(TSaveToFolder);
// Once engine is registered - we can use it
CurrentEurekaLogOptions.SenderClasses := TSaveToFolder.ClassName;
// This registers our fake send engine as the only send method
// Alternative:
// CurrentEurekaLogOptions.AddSenderClass(TSaveToFolder.ClassName);
// This registers our fake send engine as last resort fallback send method
// E.g. it will only be used if send fails completely
end.
Background sender
Code which will perform actual send can use the following code. The example below assumes that the example above was used to store bug reports in the offline storage. E.g. bug report files were saved to sub-folders, and sending settings were saved to params.json file. The example below will use Jira sender, but you may replace it with any other sender. You may use this code as is; you may modify it; or you may write your own code based on this example.
uses
ESendAPIJIRA, // for TELTrackerJIRASender - replace for your actual sender
EClasses, // for TEurekaModuleOptions
EJSON, // for JSONCreate and IJSONValues
EEncoding, // for FileToText
ETools, // for DelTree(Ex)
ETypes; // for TResponse
function SendReport(const AFolder: String): TResponse;
function SendReportEx(const AOptions, AFiles: TStrings): TResponse;
var
// Replace for your actual sender
Sender: TELTrackerJIRASender;
begin
Sender := TELTrackerJIRASender.Create;
try
Sender.AttachedFiles := AFiles;
// This example assumes that settings for sender are stored
// in options loaded from params.json file
// E.g. settings for sending were set up in your real project
// (not in current project!)
Sender.Options.Assign(AOptions);
// Alternative / optional:
// you may set up sending settings right here, locally
Result := Sender.SendMessage;
finally
FreeAndNil(Sender);
end;
end;
procedure JSONToStrings(const AJSONValue: Variant; AList: TStrings);
var
Values: IJSONValues;
X: Integer;
begin
Values := JSONValues(AJSONValue);
for X := 0 to Values.Count - 1 do
AList.Values[Values.ItemNames[X]] := Values.ItemValues[X];
end;
procedure CleanupFiles(AFiles: TStrings);
var
I: Integer;
begin
I := AFiles.IndexOfName('count');
if I >= 0 then
AFiles.Delete(I);
for I := 0 to AFiles.Count - 1 do
AFiles[I] := AFiles.ValueFromIndex[I];
end;
var
Folder: String;
JSON: IJSONValues;
Options: TStringList;
Files: TStringList;
begin
Folder := IncludeTrailingPathDelimiter(AFolder);
JSON := JSONCreate(FileToText(Folder + 'params.json'));
Options := TStringList.Create;
Files := TStringList.Create;
try
JSONToStrings(JSON['options'], Options);
JSONToStrings(JSON['files'], Files);
CleanupFiles(Files);
Result := SendReportEx(Options, Files);
finally
FreeAndNil(Files);
FreeAndNil(Options);
end;
end;
You can call this function like this:
var
Folder: String;
SR: TSearchRec;
Reports: TStringList;
R: TResponse;
X: Integer;
begin
Folder := GetFolderAppData + 'YourApp' + PathDelim + 'BugReports' + PathDelim;
// Alternative:
// Folder := ExpandEnvVars(CurrentEurekaLogOptions.CustomField['Custom_BugReportFolder']);
//
// You must enter "Custom_BugReportFolder" value in Custom / Manual page
// of EurekaLog's project options, e.g.:
// Custom_BugReportFolder="%APPDATA%\\YourApp\\BugReports"
//
// See for more info
Reports := TStringList.Create;
try
if FindFirst(Folder + '*.*', faDirectory, SR) = 0 then
try
repeat
if (SR.Name <> '.') and (SR.Name <> '..') then
Reports.Add(Folder + SR.Name);
until FindNext(SR) <> 0;
finally
FindClose(SR);
end;
for X := 0 to Reports.Count - 1 do
begin
R := SendReport(Reports[X]);
if Succeeded(HRESULT(R.SendResult)) then
DelTree(Reports[X]);
// You may also analyze R and, for example, show user some feedback messages
// See EDialog.pas, TBaseDialog.ShowSendResult for a sample implementation
end;
finally
FreeAndNil(Reports);
end;
end;
If you intend to running this code in a background process - then you probably want to subscribe to change notifications for %APPDATA%\YourApp\BugReports folder.
Conclusion
Please note that the code above is just an example. You still have to decide how you are going to manage offline storage, how and when launch sending, etc. You would need to write more code.
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/offline_storage.php
|
|