Start with the decision your code needs to make: is reporting available, should this exception be processed, or does the report need more context? EurekaLog's automatic hooks cover ordinary unhandled exceptions in a configured project. These routines cover the places where your code must participate. Processing can show a dialog, save a report, send it, or skip those actions according to the options and the exception; calling a handling routine is not a promise that all three will happen.
| Your task | Start here |
|---|---|
| Check installation or temporarily change activation | Section 6.1; keep global and per-thread state separate. |
| Report a caught exception or a condition you detected | Section 6.2; choose an entry point that matches what you have. |
| Add context to reports or outgoing requests | Section 6.3; distinguish report fields from web fields. |
| Name a worker or inspect its reporting state | Section 6.4 and chapter 15. |
| Investigate a freeze, heap damage or a source location | Sections 6.5–6.7; the longer treatments are in chapters 14, 12 and 11. |
The declaration beside each routine identifies its unit. Configure and build the project first (chapters 1–2); adding a unit or an events component alone does not install EurekaLog.
6.1 Is EurekaLog there, and is it on?
Two different questions, and the API keeps them apart. Installed is a build-time fact: the source was included and the executable was processed. Active is a run-time state you can change, globally or per thread.
IsEurekaLogInstalled
function IsEurekaLogInstalled: Boolean; // EBase
Indicates whether EurekaLog is installed in this application. EurekaLog counts as installed when both are true: its source code was included in the application, and the executable was processed by the EurekaLog expert or the command-line compiler (ECC32/EMAKE).
Use it when a library or a shared routine has to behave differently in a build that has EurekaLog and
one that does not - not as a substitute for IsEurekaLogActive, which answers the run-time question.
IsEurekaLogActive
function IsEurekaLogActive: Boolean; // EBase
Indicates whether EurekaLog is active or disabled in this application. EurekaLog is active when it
should do its work; you control that with SetEurekaLogState. If EurekaLog was not installed, it is
always disabled.
IsEurekaLogActiveInThread
function IsEurekaLogActiveInThread(const AThreadID: Cardinal = 0): Boolean; // EBase
The per-thread version: indicates whether EurekaLog is active or disabled in the given thread. Pass 0
(which is also the default) for the current thread. This is per-thread state: it neither reports nor
changes the global state - IsEurekaLogActive reports that one, and SetEurekaLogState sets it. To
change the state of a single thread, use SetEurekaLogStateInThread.
SetEurekaLogState
function SetEurekaLogState(const AActivate: Boolean): Boolean; // EBase
Enables or disables EurekaLog in this application, and returns the previous state: True if
EurekaLog was active, False otherwise.
Use it to turn reporting off around a routine that raises and handles exceptions as a matter of course - and restore the returned value rather than always re-enabling: the change is global, so a nested call or an application that was already disabled must not be switched on by your cleanup. Where the suppression concerns only the calling thread, the per-thread setter is the right tool.
SetEurekaLogStateInThread
function SetEurekaLogStateInThread(const AThreadID: Cardinal; const AActivate: Boolean): Boolean; // EBase
Enables or disables EurekaLog in the specified thread, and returns the previous state: True if
EurekaLog was active, False otherwise. A thread id of 0 means the current thread. Use the returned
value to restore the previous state rather than assuming what it was.
CurrentEurekaLogOptions
function CurrentEurekaLogOptions: TEurekaModuleOptions; // EModules
Returns the current (global) EurekaLog options for the executable module. The options exist only if EurekaLog was installed.
Do not call this accessor while EurekaLog is inactive. Its documented failure is the message
Cannot use 'CurrentEurekaLogOptions' function in module "XYZ" without activate EurekaLog, followed by
immediate process termination, not a recoverable exception. Check IsEurekaLogActive before using
the accessor. In an exception event, change that exception's AExceptionInfo.Options instead of the
global options (chapter 7).
6.2 Handing exceptions over
Use EBase.HandleException to hand over an exception you caught. Use
ExceptionManager.StandardEurekaError when you have a message but do not want to raise an exception;
use StandardEurekaNotify when you need to supply an object explicitly, including an object that was
never raised. Chapter 8 explains the manager's processing and information objects.
ExceptionManager
function ExceptionManager: TExceptionManager; // EExceptionManager
Gives access to EurekaLog's global exception manager, which provides the methods for working with exception information objects. The instance is created and deleted automatically - you do not manage its lifetime.
HandleException
function HandleException(const E: TObject = nil; const AExpected: Boolean = False;
const AHandler: String = ''; const AExceptionAddress: Pointer = nil): Integer; // EBase
Handles (processes) an exception: in practice, saving the bug report, showing EurekaLog's exception
dialog, sending the report. With no argument it uses ExceptObject. It does nothing for EAbort.
The return value is an error code for the exception, which you can pass on as the failure reason of a
thread or a process.
If EurekaLog is installed, the call is redirected to ExceptionManager.Handle; if it is not, a simple
message box appears instead. That fallback is about behaviour in an application where EurekaLog is not
installed - the unit still has to be compiled in for the call to exist at all.
For a small, deliberate reporting test, place this procedure in a Delphi unit's implementation section,
with System.SysUtils and EBase in its uses list (SysUtils on older Delphi versions). Call it
only when you intend to exercise the configured exception-processing path:
procedure ReportCaughtTestException;
begin
try
raise Exception.Create('Deliberate reporting test');
except
on E: Exception do
EBase.HandleException(E);
end;
end;
The exception is caught and not re-raised; the RTL manages this raised exception's lifetime. Do not
add E.Free. With EurekaLog installed, the configured handling actions should run; without it the
documented fallback is a simple message box. Run outside the IDE debugger when checking the end-user
path (chapter 1). This test is not a replacement for handling the actual failure at its boundary.
If a VCL application's ordinary unhandled exceptions never reach EurekaLog, check for
Application.OnException, TApplicationEvents and VCL.AppEvnts before adding more hooks. Section 9.3
gives the integration rule and forwarding example; chapter 5 provides the full diagnostic sequence.
TExceptionManager.StandardEurekaNotify
public function StandardEurekaNotify(const Obj: TObject; const Addr: Pointer = nil;
const AOptions: TEurekaModuleOptions = nil): TResponse; // EExceptionManager
A combination of the manager's Info and Handle: it processes a specific exception object (with an optional exception address and options) and returns the result of that processing.
The documentation describes it as the tool for adding EurekaLog to application types it does not support:
call it from your own exception handler to hand the exception to EurekaLog. It differs from
ShowLastExceptionData in that the exception object is explicit.
TExceptionManager.StandardEurekaError
public function StandardEurekaError(const Error: String;
const AOptions: TEurekaModuleOptions = nil): TResponse; // EExceptionManager
Invokes EurekaLog without raising an exception: the message you pass becomes the error shown in
the dialogs and the report. Internally it creates an exception of class EEurekaLogGeneralError and
passes it to Handle, so exception filters and event handlers can still alter what happens.
Use it for the condition you detected rather than caught - the invariant that broke, the state that cannot be repaired - when you want a report and a dialog but no exception in your own stack.
TExceptionManager.ShowLastExceptionData
public function ShowLastExceptionData: TResponse; // EExceptionManager
Handles the last active exception, if there is one - the same as Handle(LastThreadException). With
no active exception it returns srNoExceptionInfo. The documentation notes that this is what the installed
hooks call, for example from TApplication.ShowException.
ExceptionMessage and SetExceptionMessage
function ExceptionMessage(const E: TObject): String; // EBase
procedure SetExceptionMessage(const E: TObject; const AMessage: String); // EBase
The first returns the error message of any given exception object - including objects that are not
descended from Exception. The second sets or changes that message.
SetExceptionMessage exists because of when EurekaLog captures information: it records an exception
the first time it sees it, so a later, manual change to .Message would go unnoticed. This call sets
the property and tells EurekaLog about it.
Building exception chains
procedure RaiseOuterException(const E: TObject); // EBase
procedure RaiseOuterExceptionExpected(const AException: TObject; const AContextNumber: Integer = -1;
const ABugID: TBugID = 0); overload; // EBase - also overloaded with a URL
Call RaiseOuterException from inside an except block: it raises your new exception and keeps the
current one as an inner exception, which is what makes it an exception chain.
RaiseOuterExceptionExpected does the same and marks the raised exception as expected.
Expected exceptions: mark, raise, show
procedure MarkExpected(const AException: TObject; const AContextNumber: Integer = -1;
const ABugID: TBugID = 0); overload; // EBase - also overloaded with a URL
procedure RaiseExpected(const AException: TObject; const AContextNumber: Integer = -1;
const ABugID: TBugID = 0); overload; // EBase - also overloaded with a URL
procedure ShowExpected(const AException: TObject; const AContextNumber: Integer = -1;
const ABugID: TBugID = 0); overload; // EBase - also overloaded with a URL
function IsExpected(const AException: TObject): Boolean; overload; // EBase
An expected exception is one that has been marked as expected - a marker, not a judgement about why the exception exists. The three procedures are the three degrees of putting that marker there: mark flags an exception you have already created - the overloads take either a help context number or a URL, plus a BugID; raise raises it and marks it; show goes one step further and handles it immediately, which normally means the dialog appears.
IsExpected answers the question - and an overload returns the recorded help context number, URL and
BugID alongside the answer. With a message-carrying overload, ShowExpected constructs an
EPlannedException with that message.
LastBugID
function LastBugID: TBugID; // ExceptionLog7
The BugID of the last exception in the current thread, or 0 if no exception was raised there. Use it when you need to quote that reference yourself - in your own log, in a message to the user, in a support request - rather than letting the dialog be the only place it appears.
6.3 Putting your own data into the report
AddCustomDataToBugReport
procedure AddCustomDataToBugReport(const AName, AValue: String); // EEvents
Adds a custom field to all EurekaLog bug reports. An empty value deletes the field again. The value is whatever it was when you called it, so this is for static data - the module you are in, the configuration file that was loaded.
For a value that changes, register OnCustomDataRequest through
RegisterEventCustomDataRequest and fill ADataFields.Values['Field-Name'] in the callback
(section 7.4). The value is then supplied while the report is being built.
AddCustomWebField
procedure AddCustomWebField(const AName, AValue: String); // EEvents
The same idea for the fields of the web request EurekaLog sends, rather than the report body.
Empty deletes the field. Again static: RegisterEventCustomWebFieldsRequest is the dynamic
counterpart.
The first call adds fields to the report; the second adds fields to an outgoing request. Use a deployment name or another non-sensitive correlation value when it helps identify the environment. Account and tenant identifiers may disclose user information: include only what your investigation needs, and review the delivery and privacy controls in chapter 3.
BuildBugReport
function BuildBugReport(const AExceptionInfo: TEurekaExceptionInfo;
const ALogBuilderClass: TBaseLogBuilderClass = nil): String; // ELogBuilder
Builds the textual report for a given exception information object. The optional class chooses the
builder; the default is TLogBuilder, and the exact text depends on the class used.
The documentation is explicit that you normally do not need this: it exists to re-create a report, or to create one on demand - for example to store the text somewhere of your own choosing.
ELog
function ELog: IEurekaLogger; overload; // ELogging
procedure ELog(const AMsg: String); overload; // ELogging
procedure ELog(const AMsg: String; const AValue: String); overload; // ELogging
// further overloads add hex formatting and a digit count for numeric values
Adds an entry to EurekaLog's log. The overload without arguments logs nothing immediately: it returns
the IEurekaLogger interface so you can build the entry yourself - category, colour and the rest -
and the other overloads are the shortcuts for a message, or a message with a value.
Use it to record what your program was doing; chapter 13 covers creating, shaping and retaining the
entries. Do not assume that an entry is included in a bug report merely because it was logged.
Application logging through ELogging is separate from EurekaLog's own internal diagnostic logging,
described in chapter 5.
6.4 Threads
BeginThreadEx
function BeginThreadEx(SecurityAttributes: Pointer; StackSize: LongWord; ThreadFunc: TThreadFunc;
Parameter: Pointer; CreationFlags: LongWord; var ThreadId: TThreadID;
const AThreadName: String = ''; const AEnableEL: Boolean = Boolean(2)): Integer; // EBase
EurekaLog's replacement for the RTL's BeginThread, with two additional arguments: the thread's
name and EurekaLog's state in that thread (its documented default is the unusual
Boolean(2)). EurekaLog automatically handles an unhandled exception inside ThreadFunc - unless
you passed AEnableEL = False, which turns that off.
Like BeginThread, it returns a handle on success and 0 on failure; the handle must be closed with
CloseHandle.
EndThreadEx
procedure EndThreadEx(const AExitCode: Integer = 0); // EBase
Terminates the current thread with an optional exit code. It does not return.
The documentation warns against it, and against EndThread and ExitThread: leaving the thread's
procedure normally is what ensures the resources allocated by it are cleaned up, and terminating from
the inside can leak memory if you do not know exactly what you are doing.
NameThread
procedure NameThread(const AName: String; const AThreadID: Cardinal = 0); // EBase
Sets a name and/or description for a thread; the second parameter defaults to 0, and names need not be
unique. The most recently set value is the one that counts, and you can read it back through
TEurekaThreadData.Name.
Prefer EurekaLog's naming routines when you need its thread descriptions in reports, including
support for GetThreadDescription/SetThreadDescription. Differences from the RTL are
version-sensitive; do not assume every later RTL release has the same limitations.
ThreadData
function ThreadData: TEurekaThreadData; // EThreadsManager
Information about the current thread. The returned object must not be destroyed, and it can be
nil in the cases the documentation names - before EThreadsManager's initialization or after its
finalization. No locking is needed: the object for the current thread lives as long as the thread.
Most properties are read-only and need no synchronisation.
6.5 Freeze detection
IsFreezeCheckInstalled and IsFreezeCheckEnabled
function IsFreezeCheckInstalled: Boolean; // EFreeze
function IsFreezeCheckEnabled: Boolean; // EFreeze
The first says whether freeze detection was initialised at all; the second says whether it is working
right now - False when it is not enabled, or when it has been paused.
The documentation adds a warning about the first one: the state may change in another thread immediately
after the call, so it advises against relying on it and recommends using the paired calls that start
and stop the check instead. IsFreezeCheckEnabled carries no such warning and may be called from any
thread.
FreezeNotifyStillAlive
procedure FreezeNotifyStillAlive; // EFreeze
Tells EurekaLog that your main thread is still working. EurekaLog sends messages to the main thread from time to time; a main thread that is busy or hung will not process them, and that is what triggers the "The thread appears to be frozen" report.
One call skips one check, so the documentation's instruction is to call it frequently during the operation rather than once around it - this temporarily suspends a check without shutting down the background thread that performs it.
6.6 Memory and leaks
IsMemLeaksInstalled and IsMemLeaksEnabled
function IsMemLeaksInstalled: Boolean; // EMemLeaks
function IsMemLeaksEnabled: Boolean; // EMemLeaks
Installed means EurekaLog's memory filter replaced the memory manager - and therefore that the overhead it adds is present. Enabled means leak checks are on: EurekaLog collects the call stack of every allocated block, plus information such as name and grouping. When the checks are disabled it collects neither, and the overhead falls.
CheckHeap
procedure CheckHeap; // EMemLeaks
Scans the heap and checks blocks for errors - overflow and underflow, the ones that overwrite a
block's header or footer. Each error found calls the MemLeaksError event handler, and the usual
outcome is a report and termination of the application, not a report alone.
Two conditions come with it: the scan covers the blocks allocated through EurekaLog's memory filter
with leak registration enabled, and the call does nothing when leak checks are disabled or when
leOverflow is listed in MemLeaksErrorsToIgnore.
Use this as a debugging check, not a production health probe: place it at points where you suspect damage is already present but not yet visible, and expect the failure path to terminate the process. It blocks all memory operations during the scan and can take a long time. The documented scope is local debugging of a known corruption problem, not routine monitoring.
DumpAllocationsToFile
procedure DumpAllocationsToFile(const AFileName: String; const ACount: Boolean = True;
const AGroup: Boolean = True; const AGroupHeuristic: Boolean = True;
const ASort: Boolean = True; const AFilter: TDumpFilterFunc = nil;
const ACompare: TDumpCompareFunc = nil; const ACompareForCount: TDumpCompareFunc = nil); // EMemLeaks
Logs the allocated memory blocks to a file - each entry with its call stack, its properties (name, type, size, count) and a short memory dump - followed by total statistics. With the documented defaults the output is aggregated, not one record per allocation: duplicate blocks are grouped (only the first of them is logged) and child blocks are grouped with their parent. The folder must exist and be writable, and the file is recreated.
Use it in a local debugging run to investigate recorded allocations, not as a snapshot API in a running service. It covers only blocks allocated through EurekaLog's memory filter while leak registration was enabled; live allocations are not automatically leaks and are not the whole process footprint.
Two operational warnings are part of the contract. Logging blocks all memory operations and can take a long time, so the routine is not for production. The heap may be invalid afterwards; the reference recommends terminating the process immediately after the dump. Plan one final dump per disposable diagnostic run. For comparisons, repeat the workload in fresh processes rather than continuing after a dump (chapters 12 and 22).
MemWipeStack
procedure MemWipeStack; // ELowLevel
Wipes the unused part of the current thread's stack with the debug pattern $CCCCCCCC. The point is
what happens next: uninitialised local variables then hold a non-zero, non-nil, inaccessible value,
so using one of them before assigning it tends to fail visibly instead of quietly working.
The documentation adds that the wipe should be preceded by CanCallMemWipeStack, the unit's own check for
whether wiping is appropriate for the situation - call it first, and wipe when it says the wipe is
safe.
6.7 Where in the code am I?
CurrentAddress and ReturnAddress
function CurrentAddress: Pointer; // ECallStack
function ReturnAddress: Pointer; // ECallStack
The first is a pointer to the currently executing instruction; the second is a pointer to the
instruction after the call to the current function - that is, a pointer into the caller. Both are
raw material: use them with GetLocationInfo to turn an address into something readable, or to build
a call stack of your own.
GetLocationInfo, GetLocationInfoStr and LocationToStr
function GetLocationInfo(const Addr: Pointer): TELLocationInfo; overload; // EDebugInfo
function GetLocationInfo(const Addr: Pointer; var Info: TELLocationInfo): Boolean; overload;
function GetLocationInfoStr(const Addr: Pointer): String; overload; // EDebugInfo
function GetLocationInfoStr(const Addr: Pointer; out Info: String): Boolean; overload;
function LocationToStr(const AInfo: TELLocationInfo; const AIncludeModuleName: Boolean = True;
const AIncludeAddressOffset: Boolean = True; const AIncludeStartProcLineOffset: Boolean = False;
const AIncludeVAddress: Boolean = True; const AIncludePointer: Boolean = True;
const AIncludeLine: Boolean = True; const AUseParent: TELUseParent = eupNone): String; // EDebugInfo
GetLocationInfo looks an address up in the debug information EurekaLog can load and returns the
human-readable description - unit, class, routine, line, offsets. The first overload returns the
record; the second writes it through Info and returns a Boolean that says whether the lookup
succeeded. GetLocationInfoStr is the same thing as a string, and is described as a combination of
GetLocationInfo and LocationToStr. LocationToStr converts a record into a single line, with
switches for the module name, the offset from the routine, the offset from the line, the virtual
address, the pointer, the line, and whether the parent location is used.
LOCATION, MODULE, UNIT, FUNCTION, FILE, LINE
function __LOCATION__: String; // EDebugInfo - for example 'Unit1.TMyClass.DoSomething 42'
function __MODULE__: String; // EDebugInfo - for example 'Project1.exe'
function __UNIT__: String; // EDebugInfo - for example 'Unit1'
function __FUNCTION__: String; // EDebugInfo - for example 'DoSomething', or 'TMyClass.DoSomething'
function __FILE__: String; // EDebugInfo - for example 'Unit1.pas', 'Unit1.cpp', 'Code.inc'
function __LINE__: Integer; // EDebugInfo - for example 42
The six call-site helpers, each a combination of GetLocationInfo and GetCaller: they describe the
place they are called from. Put them in a log entry or a message where that place should be visible -
they say where they are, not where an exception happened.
Two notes the documentation makes about the unit/file/line trio: the unit name and the line number can
disagree when the code lives in an include file, and the same is true of the unit name and the source
file name - __FILE__ is the file the line is actually in, __UNIT__ is the unit being compiled.
6.8 Low-level helpers
DebugBreak
procedure DebugBreak; // ELowLevel
Causes a breakpoint exception in the current process, which signals the debugger. The documentation's interpretation is worth knowing: if you are running under the debugger and it stops inside this routine, EurekaLog is notifying the debugger about a problem - possibly a fatal one.
Exception2HRESULT
function Exception2HRESULT(const AExceptObject: TObject; const AExceptAddr: Pointer;
const AClassName: String = ''; const AInvokeEurekaLog: Boolean = True;
const ASafecall: Boolean = True): HRESULT; // EAppDLL
Converts an exception into the HRESULT to return to a caller from a DLL - the helper for code that
implements a safecall boundary, where an exception must become a result code.
ResStringCleanupCache
procedure ResStringCleanupCache; // EResourceStrings
Clears the internal cache of loaded resource strings - which the documentation marks as useful for applications that change their resource DLLs at run time.
__initialize_security_cookie and __security_check_cookie
procedure __initialize_security_cookie(out ASecurityCookie: Pointer); // ELowLevel
procedure __security_check_cookie(var ASecurityCookie: Pointer;
const ALocation: PChar = nil); // ELowLevel
The stack-guard pair. The first stores a magic value in a local variable of the routine being protected - the variable must be declared first, and it is supposed to stay unchanged for the whole call. The second verifies that it did. A changed cookie means the stack was corrupted inside that routine, typically by a buffer overflow, and the check triggers a EurekaLog crash report; with EurekaLog disabled it raises a run-time error, and an unhandled error terminates the process.