Custom :logger handler that routes log messages to the *Messages* buffer.
When the TUI is active, the default console handler writes to stderr which corrupts the terminal display. This module:
- Replaces the default
:logger_std_hhandler with a file-based one (writes to~/.local/share/minga/minga.log) - Adds a custom handler that forwards messages to the
*Messages*buffer viaMinga.Eventsbroadcasts - Redirects the
:standard_errorIO device to the same log file so that raw BEAM warnings (e.g.IO.warn/2) don't corrupt the TUI either
Crash recovery
When the Editor GenServer is down (e.g., mid-restart after a crash), log
messages are buffered in an ETS table owned by the Application supervisor.
The Editor calls flush_buffer/0 during init/1 to replay them into
*Messages*. The buffer is capped at @max_buffered entries to prevent
unbounded growth during crash loops.
Installation
Called from the Editor's init/1 after the *Messages* buffer is ready:
Minga.LoggerHandler.install()The handler stays installed across Editor restarts so that crash reports
are captured in the ETS buffer. uninstall/0 is called only during
clean application shutdown (Application.stop/1).
install/0 is idempotent: safe to call on every Editor init even
when the handlers are already in place from a previous Editor lifetime.
Summary
Functions
Creates the ETS buffer table if it doesn't already exist.
Flush buffered log messages into the Editor.
Install the file handler and stderr redirect for TUI mode.
Install just the custom :log_message-broadcast handler.
Restore the default console handler and original stderr device.
Functions
@spec ensure_buffer_table() :: :ok
Creates the ETS buffer table if it doesn't already exist.
Called from Minga.Application.start/2 so the table is owned by the
supervisor process and survives Editor crashes.
Flush buffered log messages into the Editor.
Called from the Editor's init/1 after *Messages* is ready. Replays all
buffered messages in order, then clears the buffer. Messages that arrived
while the Editor was down (e.g., supervisor crash reports) will appear
in *Messages* as if they'd been logged normally.
@spec install() :: String.t()
Install the file handler and stderr redirect for TUI mode.
Idempotent: skips any handler or redirect that is already in place.
Safe to call on every Editor init, including restarts after a crash
where the handlers survived because terminate/2 no longer tears them down.
Also ensures the :log_message broadcast handler is installed (no-op if
the application boot already added it).
Returns the log file path for display in *Messages*.
@spec install_messages_handler() :: :ok
Install just the custom :log_message-broadcast handler.
Called from Minga.Application.start/2 and Minga.Runtime.start/1 so the
broadcast path is live before any editor (or the gateway, or the singleton
*Messages* buffer owner) is up. Idempotent.
Unlike install/0, this does not replace the default :logger handler
and does not redirect stderr — those are TUI-only concerns and stay in
the editor's init path so headless and mix invocations keep stdout/stderr
output.
@spec uninstall() :: :ok
Restore the default console handler and original stderr device.