feat(native): filter Ghostty logs (#1426)

## Summary
- recognize the selected Ghostty `std.log` scopes in OpenTUI's root
logger
- keep all standard-library logs silent by default
- read `OTUI_GHOSTTY_LOG_LEVEL` inside the native `logFn` and forward
enabled messages through the existing `logger.logMessage` path
- support `error`/`err`, `warn`/`warning`, `info`, and `debug`
thresholds
- document the environment variable

## Behavior
Unset or invalid `OTUI_GHOSTTY_LOG_LEVEL` values emit no `std.log`
messages. Recognized Ghostty scopes are forwarded up to the configured
severity. Logs from every other scope are discarded. Explicit OpenTUI
logger calls are unchanged.

## Testing
- release `bun run build` from `packages/core`
- `bun run test:native` from `packages/core` (2066 passed, 8 skipped)
- `zig fmt --check packages/native/src/lib.zig
packages/native/src/logger.zig`
- `oxfmt --check packages/web/src/content/docs/reference/env-vars.mdx`
This commit is contained in:
James Long
2026-08-24 16:58:16 -04:00
committed by GitHub
parent 189f1007f8
commit a7fb4ec78e
2 changed files with 54 additions and 10 deletions
+45 -6
View File
@@ -4,19 +4,58 @@ const build_options = @import("build_options");
const Allocator = std.mem.Allocator;
pub const std_options: std.Options = .{
.logFn = discardStdLog,
.log_level = .debug,
.logFn = handleStdLog,
};
fn discardStdLog(
fn handleStdLog(
comptime message_level: std.log.Level,
comptime scope: @EnumLiteral(),
comptime format: []const u8,
args: anytype,
) void {
_ = message_level;
_ = scope;
_ = format;
_ = args;
const ghostty_scope = switch (scope) {
.parser,
.stream,
.stream_terminal,
.screen,
.terminal,
.terminal_mem,
.terminal_apc,
.terminal_dcs,
.osc,
.osc_color,
.osc_iterm2,
.kitty_gfx,
.key_encode,
.mouse_encode,
.render_state_c,
=> true,
else => false,
};
if (!ghostty_scope) return;
const configured = ghosttyLogLevel() orelse return;
if (@intFromEnum(message_level) > @intFromEnum(configured)) return;
const level: logger.LogLevel = switch (message_level) {
.err => .err,
.warn => .warn,
.info => .info,
.debug => .debug,
};
logger.logMessage(level, "(" ++ @tagName(scope) ++ ") " ++ format, args);
}
fn ghosttyLogLevel() ?std.log.Level {
const Environment = struct {
extern "c" fn getenv(name: [*:0]const u8) ?[*:0]const u8;
};
const value = std.mem.span(Environment.getenv("OTUI_GHOSTTY_LOG_LEVEL") orelse return null);
if (std.ascii.eqlIgnoreCase(value, "error") or std.ascii.eqlIgnoreCase(value, "err")) return .err;
if (std.ascii.eqlIgnoreCase(value, "warning") or std.ascii.eqlIgnoreCase(value, "warn")) return .warn;
if (std.ascii.eqlIgnoreCase(value, "info")) return .info;
if (std.ascii.eqlIgnoreCase(value, "debug")) return .debug;
return null;
}
var io_threaded: std.Io.Threaded = .init_single_threaded;
@@ -112,16 +112,21 @@ Tree-sitter worker started. An explicit client `workerPath` option takes precede
## Security-sensitive diagnostics
| Variable | Type | Default | Read time | Purpose |
| ---------------- | --------- | ------- | ----------------- | ----------------------------------------- |
| `OTUI_DEBUG` | `boolean` | `false` | Renderer creation | Retain raw input sequences for debugging |
| `OTUI_STDIN_LOG` | `string` | `""` | Renderer creation | Write the raw stdin byte stream to a file |
| Variable | Type | Default | Read time | Purpose |
| ------------------------ | --------- | ------- | --------------------- | ------------------------------------------------------------- |
| `OTUI_DEBUG` | `boolean` | `false` | Renderer creation | Retain raw input sequences for debugging |
| `OTUI_STDIN_LOG` | `string` | `""` | Renderer creation | Write the raw stdin byte stream to a file |
| `OTUI_GHOSTTY_LOG_LEVEL` | `string` | `""` | Native initialization | Forward scoped Ghostty logs through the normal OpenTUI logger |
`OTUI_STDIN_LOG=/tmp/opentui-stdin.bin` records stdin before parsing. The renderer truncates the file when it starts
and writes to it synchronously. The binary data can contain passwords and other sensitive input. Use this option only
for short debugging sessions, and protect the recorded file. Treat `OTUI_DEBUG` input captures and
`OTUI_DUMP_CAPTURES` output as sensitive data too.
`OTUI_GHOSTTY_LOG_LEVEL` accepts `error`, `warn`, `info`, or `debug` (`err` and `warning` are aliases). The selected level
includes all more severe messages. Unset or invalid values disable Ghostty logs. Standard-library logs outside the
recognized Ghostty scopes are always discarded.
## Remote sessions
A renderer with `remote: true` forwards no local environment keys to native terminal detection by default. Add only