Often you need to collect additional data in order to successfully identify the bug in your application. You write ("log") additional useful information (events) into a single file ("log"), which is then attached to bug report. It is called "logging" (the act of keeping a log).
There are two engines in EurekaLog which you may use for logging purposes:
EMemLeaksYou can set a name for any memory block allocated via EurekaLog memory manager (when leaks checking is active). MemLeaksName is a basic function for this task. For example:
GetMem(P, 1024);
Here is how anonymous P memory block looks in leak and dump reports:
$06961F90 x 1 DATA [Data at $06961F90] 1024 bytes (total of 1024 bytes) (00318491){Project70.exe} [00718491] Unit62.TForm62.Button1Click (Line 33, "Unit62.pas") + $5 (00247C57){Project70.exe} [00647C57] Vcl.Controls.TControl.Click (Line 7442, "Vcl.Controls.pas") + $8 ...
It is hard to understand what this leak is
And here is how it looks after naming it with MemLeaksName:
$06F91F90 x 1 DATA [[P variable] Data at $06F91F90] 1024 bytes (total of 1024 bytes) (00318491){Project70.exe} [00718491] Unit62.TForm62.Button1Click (Line 33, "Unit62.pas") + $5 (00247C57){Project70.exe} [00647C57] Vcl.Controls.TControl.Click (Line 7442, "Vcl.Controls.pas") + $8 ...
Now leak will show assigned name ("P variable")
You can convert any of the dynamically allocated types to a pointer. For example:
MemLeaksName(Pointer(fmMain), 'Main Form');
The exception to this rule: strings and dynamic arrays. These types have headers at negative offsets - therefore you can not pass these types to MemLeaksName function directly. Use:
S := 'Message';
EurekaLog is capable to extract some information about variables (for example, content of the string, dimensions of dynamic array, class name of objects, names of components). Therefore, it is not necessary to specify all tiny details.
BTW, you can change name again at any time.
You can also define a parent-child relationship between two memory blocks. These relationships will be using for grouping and merging of memory blocks during leaks checking or dumping (see CheckHeap or DumpAllocationsToFile function). For example:
MemLeaksOwn(Pointer(fmDialog), Pointer(Stream));
This makes Stream a child of fmDialog. This means that Stream will not appear in reports. Instead - its size will be added to fmDialog.
Here is how fmDialog and Stream will look in leak and dump reports before grouping:
Two independent leaks will be shown
And here is when you indicate that fmDialog is the owner of the stream:
Only parent block is shown, sizes are summed
Such construct is used to indicate ownership. Basically, it says that fmDialog is responsible for deleting Stream. If you want to give ownership to external code, simply use:
MemLeaksOwn(nil, Pointer(Stream));
This code will remove parent-child relationship.
You can also assign and name at the same time:
MemLeaksOwn(Pointer(fmDialog), Pointer(Stream), 'Stream for Dialog Form');
Of course, there are separate functions for strings and dynamic arrays:
MemLeaksOwnStr(Pointer(fmDialog), Pointer(S), 'Message for Dialog');
ELoggingELogging unit writes log into CodeSite-compatible format (.csl file format). CodeSite format is mostly textual. You can view it in advanced text editors (such as Notepad++) or use free CodeSite File Viewer tool. You can obtain it either via installing CodeSite (it is available via GetIt in latest RAD Studio IDEs) or download standalone installer.
Note: EurekaLog is not a replacement for CodeSite (or any other logging framework). EurekaLog has no log dispatcher, no live logging, no TCP/HTTP logging, no complex logging methods, etc. EurekaLog simply writes local report file. Only simple logging methods are available.
First, if you want a permanent log file - you have to create a new log file by calling ELogOpen function:
ExeName := ParamStr(0);
This code will create new log file in the APPDATA folder (with the same name as .exe file). You can create log file in any location. We recommend to use .csl file extension.
Creating log file should be the first action by your code, before you call any other routines in ELogging unit. If you do not call ELogOpen function - logging will be performed into temporal file, which will be deleted when application exists. Always call ELogOpen function to get permanently saved log. Do not call ELogOpen function if you only want log file as attach to bug report (see below).
You can write to log using various ELog functions:
ELog('Say Hello');
The result will be:
Resulting log being viewed in CodeSite File Viewer
See ELogging unit for more information on possible constructs.
You can alter created entries by assigning a category or colors:
ELog.FontColor(clRed).Log('Say Hello');
As well as chain several modifiers together:
ELog.Category('My Category').Color(clBlack).FontColor(clWhite).Log('Say Hello');
You can also log entering and exiting functions:
procedure Test; // Including other logging code, // such as: ELog('Some log inside function'); end;
This code will log entering and exiting from the function, as well as indents log to the right, so any nested calls to ELog inside Test function will be written indented to the right.
You can log function parameters as well:
procedure Test(const AMsg: String; const AValue: Integer);
Please note, that you have to always call either D or C methods as the last action in chain - to indicate that function has no more arguments. Otherwise (if you forgot to close function call) indentation for nested log entries will be wrong. The difference between D and C is that D creates a normal (expanded) log entry, and C creates closed (collapsed) entry.
If you want to log a call to a method - simply specify an object/class as the first argument:
procedure TMyObject.Test(const AMsg: String; const AValue: Integer);
If you want to log a returned value too:
function TMyObject.Test(const AMsg: String; const AValue: Integer): Integer; Unit1.Test(AMsg, AValue);
The existing log file will automatically be added to bug report during sending. When you receive bug report - the log will be shown as file attach:
Log file inside bug report Double-click log to view
If you do not want to use EurekaLog logging, you can use any other logging framework - such as CodeSite, SmartInspect, or any other framework. You can use OnAttachedFilesRequest or OnZippedFilesRequest events (depending on if you want to send log as separate file or as packed inside EurekaLog report). For example:
// Example for CodeSite ChangeFileExt(ExtractFileName(ParamStr(0)), '.csl'); AExceptionInfo: TEurekaExceptionInfo { EException }; const ATempFolder: String; AAttachedFiles: TStrings; var ACallNextHandler: Boolean);
// Example for SmartInspect
procedure PackLogFile(const ACustom: Pointer; AExceptionInfo: TEurekaExceptionInfo; const ATempFolder: String; AAttachedFiles: TStrings; var ACallNextHandler: Boolean);
|