📝 Boot Log¶
HIX captures in a static thread-safe hash everything that happens during server startup: loaded configuration files, initialized subsystems, compiled loaders, applied middlewares, and registered routes. This record remains accessible at runtime for inspection, diagnostics, or to display it in an admin UI.
Each event is saved as an array of 4 elements:
| Field | Type | Meaning |
|---|---|---|
cAction |
C |
Type of action: "file", "config", "init", "route", ... |
lStatus |
L |
.T. if the operation succeeded, .F. if it failed |
cValue |
C |
Human-readable identifier of the resource (myapp.prg, users.list, ...) |
xCargo |
X |
Free payload (error description, metadata, NIL by default) |
When do you need it?¶
- To diagnose why a module, middleware, or route didn't load.
- To expose the startup status to the team as JSON or a view.
- To verify at a glance that all subsystems (logger, proxy, firewall, access log, metrics, socket) started without errors.
Sections¶
The hash is organized by loading processes. The standard sections are:
| Section | Content |
|---|---|
config |
Loaded configuration files (hix.json, www/config.json, …) |
server |
Initialized subsystems: logger, proxy, firewall, access log, metrics… |
loaders |
.prg files compiled and loaded from www/loaders/ |
middlewares |
Middlewares loaded from www/middlewares/config.json |
routes |
Registered routes (JSON or programmatic; excludes internal hix.*) |
You can add your own sections from code by calling HIX_BootLogAdd.
Public API¶
HIX_BootLog() // complete hash (cloned)
HIX_BootLogSection( cKey ) // array of a section
HIX_BootLogAdd( cKey, cAction, lStatus, cValue, xCargo ) // add event
HIX_BootLogReset() // empty the hash
HIX_BootLogShow() // dump to console formatted
HIX_BootLogAction( bAction ) // callback on each Add
HIX_BootLogVerbose( lOn ) // enable/disable verbose
HIX_BootLogIsVerbose() // query the verbose flag
HIX_BootLog()¶
Returns a cloned copy of the complete hash, thread-safe. Ideal for sending as JSON:
HIX_BootLogSection( cKey )¶
Returns the array of a specific section (or {} if it doesn't exist):
aRoutes := HIX_BootLogSection( "routes" )
FOR EACH aItem IN aRoutes
? aItem[3], aItem[4] // cValue, xCargo
NEXT
HIX_BootLogAdd( cKey, cAction, lStatus, cValue, xCargo )¶
Adds an entry. lStatus defaults to .T.; xCargo defaults to NIL.
If lStatus == .F. and xCargo == NIL, it is replaced with a localized
placeholder (BOOT_ERR_NO_DESC) so the UI doesn't see NIL in errors.
HIX_BootLogAdd( "loaders", "file", .T., "myapp.prg" )
HIX_BootLogAdd( "loaders", "file", .F., "bad.prg", oErr:description )
HIX_BootLogReset()¶
Empties the hash. It is called automatically at the start of _Init() if the process
owns the globals.
HIX_BootLogShow()¶
Dumps the content to console with human-readable format, in logical order
(config → server → loaders → middlewares → routes):
=== HIX Boot Log ===
[config]
OK file hix.json
OK file www/config.json
[server]
OK init logger level=info console=T
OK init access_log enabled=T file=access.log
OK init metrics
OK init socket ssl=F
[loaders]
OK file myapp.prg
ERR file bad.prg -> Unterminated string 'x, HB_COMPILEFROMBUF
[middlewares]
OK file cors.prg
OK config session: cookie=hix_sess ttl=3600 storage=memory
[routes]
OK init users.list -> type:compiled, route=[/users], method[GET,OPTIONS], context:[]
OK init admin.edit -> type:file[api.json], route=[/admin/:id], method[GET,POST,OPTIONS], context:[admin]
====================
HIX_BootLogAction( bAction )¶
Registers a codeblock that executes each time an entry is added to the boot log. The codeblock receives the five fields of the newly inserted entry:
It's useful for:
- Forwarding each event to the logger (
l()/lw()/le()) in real time. - Reporting errors to an external system (Sentry, webhook, e-mail).
- Updating a live UI during startup (progress bar, admin panel).
Pass NIL to disable it. Returns the previous codeblock in case you need to
restore it.
Example - forward to logger with a helper function:
// On server startup
HIX_BootLogAction( {|cKey, cAction, lStatus, cValue, xCargo| ;
MyBootLog( cKey, cAction, lStatus, cValue, xCargo ) } )
// Helper function in your app
FUNCTION MyBootLog( cKey, cAction, lStatus, cValue, xCargo )
_t( "[BOOT/" + cKey + "] " + cAction + " " + ;
iif( lStatus, "OK", "ERR" ) + " " + cValue + ;
iif( xCargo == NIL, "", " -> " + hb_CStr( xCargo ) ) )
RETURN NIL
Each entry added to the boot log triggers MyBootLog() with the event data;
the function formats them and sends them to _t() (trace), which can
dump them to console, file, or wherever you decide.
The callback is invoked outside the internal mutex so as not to block other writes. Still, keep the codeblock fast - it executes synchronously during startup.
HIX_BootLogVerbose( lOn ) / HIX_BootLogIsVerbose()¶
Enables or queries detailed mode (reserved for extensive records like per-route entries). Returns the previous value.
Format of xCargo by section¶
Loaders (errors)¶
When a .prg/.hrb fails, xCargo contains:
Real example:
If the error has no operation, only the description appears. If there's
no capturable exception, it defaults to the internal message (BOOT_LOADER_LOAD_FAIL_NX).
Middlewares¶
fileon success →xCargo=NILfileon error →xCargo="compile failed","handle NIL"oroErr:descriptionconfig(session/csrf setup) →xCargo=NILand the description goes incValue
Routes¶
Each registered route (except internal hix.* ones) generates:
Where type is:
compiled- the route was registered from code (for example withAddRouteGet).file[<name.json>]- the route was loaded fromwww/routes/<name.json>.
Server¶
Subsystems are registered as cAction = "init" and cValue describes the
resource with its key parameters (logger level=info console=T,
firewall mode=blacklist filter=…, socket ssl=T, etc.).
Exposing the boot log to the user¶
Since the hash is serializable, the most straightforward way is an HTTP route:
// Raw JSON endpoint
oSrv:AddRouteGet( "hix.boot", "/hix-boot", ;
{|| USendJson( HIX_BootLog() ) } )
// Specific section
oSrv:AddRouteGet( "hix.boot.routes", "/hix-boot/routes", ;
{|| USendJson( HIX_BootLogSection( "routes" ) ) } )
// Tabulated HTML view
oSrv:AddRouteGet( "hix.boot.html", "/hix-boot.html", ;
{|| USendView( "hix/bootlog.html", { "hLog" => HIX_BootLog() } ) } )
These routes should be protected with HixMwAdmin or the session middleware
you use in your admin panel.
Example - custom section¶
You can use your own section to record events during your application's startup:
PROCEDURE Main()
LOCAL oSrv := THixServer():New()
oSrv:bInit := {||
HIX_BootLogAdd( "app", "init", .T., "warmup cache" )
IF ! _LoadCatalog()
HIX_BootLogAdd( "app", "init", .F., "catalog", "corrupted file" )
ENDIF
}
oSrv:Start()
IF oSrv:hThread != NIL
hb_threadJoin( oSrv:hThread )
ENDIF
RETURN
Your app section will appear at the end of the dump and also in the hash returned
by HIX_BootLog().