== Debug Logging Declared in ``. A crash-tracing logger that writes `joeylog.txt` in the program's folder, beside `DATA/` and `SAVES/` (<<_files>>: on the ST, the current directory; on DVX, the program's user folder, `USER\APPS\VENDOR\NAME\JOEYLOG.TXT`; on macOS, its Application Support folder). Debugging a program on an emulated 1988 machine is awkward, and this is usually the fastest way to find out what it did before it stopped doing it. The headless run scripts retrieve the log automatically. The library itself writes to it only when something fails, such as sound that does not start. How the file is written differs: * *Every port but the IIgs* opens the file on the first line and appends to it, writing each line out as it is logged, so a crash or hang leaves every line before it on disk. The file grows across runs until `jlLogReset`. * *The IIgs* keeps the lines in an 8 KB ring in memory, because a write per line costs seconds of floppy time there. Nothing reaches the disk until `jlLogFlush`, which replaces the file with the last 8 KB logged. A program that never calls it leaves no log. * *The web* writes the file into the page's memory, where it is lost when the page closes, so every line also goes to the browser's console. [NOTE] ==== The logger's buffer is linked into every program, since the library logs its own failures: the 8 KB ring on the IIgs, and a 512-byte line buffer on every other port but DVX. A memory-tight program can still leave its own log calls out and observe hardware state through the emulator instead. ==== On DOS the library also opens `CRASH.LOG` beside the program at `jlInit`, and writes the processor's registers there if the program faults; a run that shuts down cleanly deletes it, so it is only there after a crash. === jlLog [source,c] ---- void jlLog(const char *msg); ---- Appends a message to the log. [cols="1,1,4", options="header"] |=== |Parameter |Type |Description |`msg` |`const char *` |NUL-terminated message. |=== *Returns:* nothing. === jlLogF [source,c] ---- void jlLogF(const char *fmt, ...); ---- Appends a formatted message, `printf` style, as one line: like `jlLog`, the library ends the line, so the format needs no trailing `\n`. A formatted line is cut at 255 characters, on every port. [cols="1,1,4", options="header"] |=== |Parameter |Type |Description |`fmt` |`const char *` |Format string. |`+...+` | |Arguments matching the format string. |=== *Returns:* nothing. [TIP] ==== Keep format strings simple. The C libraries on these targets vary in what they support, and on the IIgs the `printf` family is expensive in both code size and time. ==== === jlLogFlush [source,c] ---- void jlLogFlush(void); ---- Flushes buffered log output to disk. On the IIgs it is the only way the log reaches the disk: it rewrites the whole file with the last 8 KB logged, so call it before anything that might crash or exit, or the last and most interesting lines are never written. Every other port has already written each line. *Parameters:* none. *Returns:* nothing. === jlLogReset [source,c] ---- void jlLogReset(void); ---- Clears the log, discarding previous contents. Call once at startup so each run produces a fresh log rather than appending to the last one. On the IIgs it clears the ring only; the file on disk changes at the next `jlLogFlush`. *Parameters:* none. *Returns:* nothing. [source,c] ---- int main(void) { jlConfigT config; config.codegenBytes = 32UL * 1024; config.noAudio = true; if (!jlInit(&config)) { return 1; } jlLogReset(); jlLogF("build %s %s", __DATE__, __TIME__); // ... game ... jlLogFlush(); jlShutdown(); return 0; } ----