Use Windows event logging when an administrator needs to find application failures alongside other
machine events, especially for a service with no interactive desktop. EurekaLog's System log
reporting pseudo-dialog (edtService) adds an event without showing a window. It otherwise behaves
like the no-dialog choice. Services may also use ordinary local bug reports; event logging is an
option, not a requirement.
An event and a report are different artifacts. The default event contains the exception message and the full path to the bug report file. It does not embed that file or deliver it to your support system. Configure report storage and delivery separately (chapter 3), and ensure that the service account can write the report folder and the investigating administrator can read it.
To get a readable event, keep three values in agreement:
| Artifact | What it supplies |
|---|---|
| Message resource linked into an executable or resource DLL | The template text and full message identifier |
| Installed event-source registration | A source name and the path to the binary containing that resource |
| EurekaLog's System log reporting settings | The same source name and full message identifier |
A visible event whose description cannot be found usually means this agreement is broken. Do not mistake an event record for proof that the message resource or the separate report is available.
23.1 Plan the installed artifacts
The example in this chapter writes to the local machine's Application log. Choose a stable,
application-specific source name; SampleService below is illustrative, not a required value. An
installation may have more than one source for distinct components, but do not create a new source
for every exception. Windows limits the number of registered sources to 16,384.
You need:
Messages.mc, maintained with your project source.- Microsoft's Message Compiler (
mc.exe) and a resource compiler (rc.exe) on the build machine. The Windows SDK supplies these tools; use their installed paths or a build environment whosePATHcontains them. Delphi/C++Builder's resource compiler can also compile the generated.rc. - A linked executable or resource DLL deployed at a stable path on the target machine.
- An installer action with permission to create the event-source key under
HKEY_LOCAL_MACHINE. Perform this as an elevated installation task, not while handling the first exception. - EurekaLog configured with the matching source and event ID, followed by a test under the actual service/application account.
An event stores its insertion strings and a reference to a template, not a private copy of the whole template. Moving or removing the resource binary can therefore make old events unreadable. Plan resource retention and upgrades as well as initial installation.
23.2 Compile and link the message text
Usually one error event is enough for all exceptions. Define additional informational or warning
events only if your application needs distinct event semantics. This example defines one event with
English and Italian text and two insertion strings: %1 for the exception message, %2 for the
report path.
Save the following as Messages.mc in UTF-16LE. Keep the final newline after the last line
containing a dot. Each language's message body ends with a dot on its own line.
MessageIdTypedef=DWORD
SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS
Informational=0x1:STATUS_SEVERITY_INFORMATIONAL
Warning=0x2:STATUS_SEVERITY_WARNING
Error=0x3:STATUS_SEVERITY_ERROR
)
FacilityNames=(System=0x0:FACILITY_SYSTEM
Runtime=0x2:FACILITY_RUNTIME
Stubs=0x3:FACILITY_STUBS
Io=0x4:FACILITY_IO_ERROR_CODE
)
LanguageNames=(English=0x409:MSG00409)
LanguageNames=(Italian=0x410:MSG00410)
MessageId=0x1
Severity=Error
Facility=Runtime
SymbolicName=mcEurekaLogErrorMessage
Language=English
There was an exception "%1" in the service.
See %2 file for more information.
.
Language=Italian
Si e verificata un'eccezione "%1" nel servizio.
Consultare il file %2 per ulteriori informazioni.
.
Run these commands from the directory containing the file, stopping if a command fails:
mc -u -U Messages.mc
rc -r Messages.rc
Lowercase -u selects UTF-16LE input; uppercase -U selects Unicode messages in the generated
binary resource. Do not confuse either with the encoding of Delphi source files.
The first command generates Messages.h, Messages.rc and a .bin file for each language
(MSG00409.bin and MSG00410.bin here). Inspect the generated header before configuring EurekaLog:
#define mcEurekaLogErrorMessage ((DWORD)0xC0020001L)
The full identifier is $C0020001, not 1. It combines severity, facility and message code:
error severity contributes $C0000000, Runtime facility contributes $00020000, and the message
code contributes 1. With those same severity/facility values, MessageId=0x2 would produce
$C0020002. Use the generated value rather than assuming every event uses this layout's sample
values; changing compiler flags or severity/facility can change the full ID.
The second command compiles Messages.rc and its referenced .bin files into Messages.res.
For reference, the generated resource script for these two languages has the following structure:
LANGUAGE 0x10,0x1
1 11 "MSG00410.bin"
LANGUAGE 0x9,0x1
1 11 "MSG00409.bin"
Link the resource into the application. In a Delphi project source file, place this resource directive outside a procedure, alongside the project's other resource directives:
{$R Messages.res}
Alternatively, add the resource to the project using Project / Add to project. To have the
Delphi IDE compile the resource script, use this directive instead and retain the .rc and all
referenced .bin files:
{$R 'Messages.res' 'Messages.rc'}
For a repeatable command-line resource build, this batch file keeps the generated inputs and the header for inspection and stops on a failed compiler command:
@echo off
mc -u -U Messages.mc
if errorlevel 1 exit /b 1
rc -r Messages.rc
if errorlevel 1 exit /b 1
Have the parent build stop if this step fails; otherwise it could link a stale Messages.res.
Do not delete every MSG*.bin in a shared directory as part of a generic cleanup step. When linking
only the prebuilt .res, intermediate files are not runtime dependencies, but retain Messages.mc
and the resource-build recipe. You may link the .res into a dedicated resource DLL instead of the
main executable; registration must then point to that DLL.
23.3 Register the event source during installation
Create this key on the machine that will log the events:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application\SampleService
Set these values:
| Name | Type | Value in this example |
|---|---|---|
EventMessageFile |
String | Absolute path to the deployed executable containing Messages.res |
TypesSupported |
DWORD | $0007: error $0001, warning $0002, information $0004 |
If using a separate resource DLL, put its absolute path in EventMessageFile instead. The binary
must contain the message resource; pointing to Messages.mc or the standalone .res is not enough.
The following helper belongs in your installer code or a service unit. It uses Windows,
SysUtils and Registry. It registers one application-owned source and deliberately reports an
installation failure instead of silently skipping a failed key creation. It assumes the installer
has chosen a nonconflicting source name and has already deployed the resource binary.
uses
Windows, SysUtils, Registry;
procedure RegisterApplicationEventSource(const SourceName,
MessageBinary: String);
var
Reg: TRegistry;
begin
Reg := TRegistry.Create(KEY_WRITE);
try
Reg.RootKey := HKEY_LOCAL_MACHINE;
if not Reg.OpenKey(
'SYSTEM\CurrentControlSet\Services\Eventlog\Application\' + SourceName,
True) then
raise Exception.Create('Cannot create the application event-source key');
Reg.WriteString('EventMessageFile', MessageBinary);
Reg.WriteInteger('TypesSupported',
EVENTLOG_ERROR_TYPE or EVENTLOG_INFORMATION_TYPE or EVENTLOG_WARNING_TYPE);
finally
Reg.Free;
end;
end;
For a service with the resource in its own executable, wire the service's AfterInstall event to
a handler that calls RegisterApplicationEventSource(Name, ParamStr(0)). That uses the service's
Name as the event source; configure exactly that name in section 23.4. For a separate installer,
pass the installed service executable's path, not the installer's ParamStr(0).
The reverse installer operation removes only the application's own source key. In a service this
can be performed by its BeforeUninstall handler; a TRegistry with RootKey := HKEY_LOCAL_MACHINE can call DeleteKey with the same source path, and the installer must check
its Boolean result. Do not remove the entire Application key or another application's source.
Removing the source or its message binary affects later viewing of retained events: agree on
archival/resource-retention policy before uninstalling them.
This chapter uses the standard Application log. The other standard logs are System and
Security; custom logs are possible, but are a different deployment configuration, not a reason
to change this example's registry path without also designing the corresponding registration.
23.4 Select System log reporting and prove the result
In Project / EurekaLog options / Dialogs, select System log reporting (edtService).
Set the dialog's fields as follows:
| Field | Backing property | Local example |
|---|---|---|
| Computer name | .EventLogComputer |
Empty: current machine |
| Event source name | .EventLogName |
SampleService, or the service Name used at registration |
| Category ID | .EventLogCategory |
Empty: this example defines no categories |
| Message ID | .EventLogEventID |
$C0020001, copied from Messages.h |
Computer and category may remain empty for this workflow. Source name and message ID are required. These are the property names behind the settings, not a stand-alone Delphi assignment block. Rebuild and deploy the application with the resource and these settings together.
On a development or staging machine:
- Install/register the source using the deployed resource binary's path.
- Run the application under the account it will really use. Trigger a controlled exception through its normal handler, as in chapter 1; a service needs a development-only service action rather than an interactive GUI button.
- Open Windows Event Viewer / Windows Logs / Application. Refresh and filter by the configured source and the time of the test.
- Open the event. Confirm the exception text is substituted for
%1and the expected full report path for%2, without a missing-description warning. - Open the separate report at that path. Then verify any configured sending independently using chapter 3. An event is not an upload receipt.
| Observation | Investigate next |
|---|---|
| No matching event | Actual deployed settings, exception-handling route, source/computer name and the running account; first establish that EurekaLog processed the test exception. |
| Event exists, description cannot be found | Registered source key, absolute EventMessageFile path, deployed message resource and full ID from the matching generated header. |
| Text appears but insertion values are wrong | Order of FillData additions versus %1, %2, etc.; the template and override must be deployed together. |
| Event text is readable but report cannot be opened | Separate report creation/path, service-account write rights, administrator read rights and retention. |
| Local event/report exists but nothing arrived remotely | Delivery configuration and transport outcome, chapter 3. |
Do not broaden service privileges just to hide a setup problem. Register at installation with the needed administrative permission, then diagnose runtime access using the intended service identity.
23.5 Put different information into the event
The numbered placeholders (called qualificators in the EurekaLog reference) are insertion strings.
By default, TEventLogDialog.FillData supplies exactly two:
procedure TEventLogDialog.FillData(const AData: TStrings);
begin
AData.Add(ExceptionInfo.ExceptionMessage); // %1
AData.Add(LogFileName); // %2
end;
This illustrates the built-in method, not code you add alongside it. The first Add supplies %1,
the second %2, and so on. Their order in the displayed sentence can differ from their numeric
order. The dynamic data is stored in each event, so review its privacy and retention consequences.
For a custom event containing the message, exception class, compact stack and BugID, add this
complete unit to the project. It registers a descendant of EDialogService.TEventLogDialog during
unit initialization; it does not replace a send engine. The formatter is temporary and is freed
inside the override. Select System log reporting as in section 23.4.
unit CustomizedSystemLog;
interface
implementation
uses
SysUtils, Classes, ECallStack, EDialog, EDialogService;
type
TEventLogDialog = class(EDialogService.TEventLogDialog)
protected
procedure FillData(const AData: TStrings); override;
end;
procedure TEventLogDialog.FillData(const AData: TStrings);
var
Formatter: TCompactStackFormatter;
CallStack: String;
begin
Formatter := TCompactStackFormatter.Create;
try
CallStack := CallStackToString(ExceptionInfo.CallStack, '', Formatter);
finally
Formatter.Free;
end;
AData.Add(ExceptionInfo.ExceptionMessage); // %1
AData.Add(ExceptionInfo.ExceptionClass); // %2
AData.Add(CallStack); // %3
AData.Add(ExceptionInfo.BugIDStr); // %4
end;
initialization
RegisterDialogClassFirst(TEventLogDialog);
end.
The dialog's ExceptionInfo exposes the exception being reported; BugReport exposes the report
text if a different customization needs it. Do not put an entire report into the event merely
because it is accessible: choose the data an administrator actually needs.
For the four-string override, keep the severity/facility definitions from section 23.2, keep only
the English LanguageNames entry if you are supplying only English, and replace the event block
starting at MessageId=0x1 with this one:
MessageId=0x1
Severity=Error
Facility=Runtime
SymbolicName=mcEurekaLogErrorMessage
Language=English
There was an exception #%4 of type %2 with message:%n%1%nCall stack:%n%3
.
%n inserts a line break; it does not consume another insertion string. There are still four
strings, used in the order %4, %2, %1, %3 in the text. Recompile the resource and relink it;
the full event ID remains $C0020001 because severity, facility and code are unchanged. Re-run the
readability check after deploying the override and resource together. The new %2 is the exception
class, not the report path: do not interpret it using the original two-string template.
23.6 Choose the right log for the investigation
Use System log reporting for an exception event administrators can find in Windows Event Viewer.
Use ELogging for application breadcrumbs, values and timings while the program works: open a
log with ELogOpen, write entries, and flush deliberately when appropriate. Those entries go to a
log file and can accompany a packed report; they do not alter the event template. Chapter 13 supplies
the signatures, defaults and examples rather than duplicating the logging API here.
Use internal diagnostics only when investigating EurekaLog's own behavior, such as a failure during exception processing or unexpected overhead (chapter 5). Although diagnostic tracing can use the logging infrastructure, opening an application log alone does not request that internal trace. Finally, none of these mechanisms replaces report delivery and its outcome checks (chapter 3).