logging: document GHOSTTY_LOG and make it more flexible
parent
6d2beed1b0
commit
f8c03bb6f6
30
HACKING.md
30
HACKING.md
|
|
@ -93,6 +93,36 @@ produced.
|
|||
> may ask you to fix it and close the issue. It isn't a maintainers job to
|
||||
> review a PR so broken that it requires significant rework to be acceptable.
|
||||
|
||||
## Logging
|
||||
|
||||
Ghostty can write logs to a number of destinations. On all platforms, logging to
|
||||
`stderr` is available. Depending on the platform and how Ghostty was launched,
|
||||
logs sent to `stderr` may be stored by the system and made available for later
|
||||
retrieval.
|
||||
|
||||
On Linux if Ghostty is launched by the default `systemd` user service, you can use
|
||||
`journald` to see Ghostty's logs: `journalctl --user --unit app-com.mitchellh.ghostty.service`.
|
||||
|
||||
On macOS logging to the macOS unified log is available and enabled by default.
|
||||
Use the system `log` CLI to view Ghostty's logs: `sudo log stream --level debug --predicate 'subsystem=="com.mitchellh.ghostty"'`.
|
||||
|
||||
Ghostty's logging can be configured in two ways. The first is by what
|
||||
optimization level Ghostty is compiled with. If Ghostty is compiled with `Debug`
|
||||
optimizations debug logs will be output to `stderr`. If Ghostty is compiled with
|
||||
any other optimization the debug logs will not be output to `stderr`.
|
||||
|
||||
Ghostty also checks the `GHOSTTY_LOG` environment variable. It can be used
|
||||
to control which destinations receive logs. Ghostty currently defines two
|
||||
destinations:
|
||||
|
||||
- `stderr` - logging to `stderr`.
|
||||
- `macos` - logging to macOS's unified log (has no effect on non-macOS platforms).
|
||||
|
||||
Combine values with a comma to enable multiple destinations. Prefix a
|
||||
destination with `no-` to disable it. Enabling and disabling destinations
|
||||
can be done at the same time. Setting `GHOSTTY_LOG` to `true` will enable all
|
||||
destinations. Setting `GHOSTTY_LOG` to `false` will disable all destinations.
|
||||
|
||||
## Linting
|
||||
|
||||
### Prettier
|
||||
|
|
|
|||
|
|
@ -607,6 +607,9 @@ pub fn init(
|
|||
};
|
||||
errdefer env.deinit();
|
||||
|
||||
// don't leak GHOSTTY_LOG to any subprocesses
|
||||
env.remove("GHOSTTY_LOG");
|
||||
|
||||
// Initialize our IO backend
|
||||
var io_exec = try termio.Exec.init(alloc, .{
|
||||
.command = command,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ const glib = @import("glib");
|
|||
const gobject = @import("gobject");
|
||||
const gtk = @import("gtk");
|
||||
|
||||
const build_config = @import("../../../build_config.zig");
|
||||
const state = &@import("../../../global.zig").state;
|
||||
const i18n = @import("../../../os/main.zig").i18n;
|
||||
const apprt = @import("../../../apprt.zig");
|
||||
const cgroup = @import("../cgroup.zig");
|
||||
|
|
@ -2677,7 +2679,9 @@ fn setGtkEnv(config: *const CoreConfig) error{NoSpaceLeft}!void {
|
|||
/// disable it.
|
||||
@"vulkan-disable": bool = false,
|
||||
} = .{
|
||||
.opengl = config.@"gtk-opengl-debug",
|
||||
// `gtk-opengl-debug` dumps logs directly to stderr so both must be true
|
||||
// to enable OpenGL debugging.
|
||||
.opengl = state.logging.stderr and config.@"gtk-opengl-debug",
|
||||
};
|
||||
|
||||
var gdk_disable: struct {
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ pub fn init(
|
|||
|
||||
// This overrides our default behavior and forces logs to show
|
||||
// up on stderr (in addition to the centralized macOS log).
|
||||
open.setEnvironmentVariable("GHOSTTY_LOG", "1");
|
||||
open.setEnvironmentVariable("GHOSTTY_LOG", "stderr,macos");
|
||||
|
||||
// Configure how we're launching
|
||||
open.setEnvironmentVariable("GHOSTTY_MAC_LAUNCH_SOURCE", "zig_run");
|
||||
|
|
|
|||
|
|
@ -37,6 +37,19 @@ precedence over the XDG environment locations.
|
|||
|
||||
: **WINDOWS ONLY:** alternate location to search for configuration files.
|
||||
|
||||
**GHOSTTY_LOG**
|
||||
|
||||
: The `GHOSTTY_LOG` environment variable can be used to control which
|
||||
destinations receive logs. Ghostty currently defines two destinations:
|
||||
|
||||
: - `stderr` - logging to `stderr`.
|
||||
: - `macos` - logging to macOS's unified log (has no effect on non-macOS platforms).
|
||||
|
||||
: Combine values with a comma to enable multiple destinations. Prefix a
|
||||
destination with `no-` to disable it. Enabling and disabling destinations
|
||||
can be done at the same time. Setting `GHOSTTY_LOG` to `true` will enable all
|
||||
destinations. Setting `GHOSTTY_LOG` to `false` will disable all destinations.
|
||||
|
||||
# BUGS
|
||||
|
||||
See GitHub issues: <https://github.com/ghostty-org/ghostty/issues>
|
||||
|
|
|
|||
|
|
@ -73,16 +73,12 @@ the public config files of many Ghostty users for examples and inspiration.
|
|||
## Configuration Errors
|
||||
|
||||
If your configuration file has any errors, Ghostty does its best to ignore
|
||||
them and move on. Configuration errors currently show up in the log. The log
|
||||
is written directly to stderr, so it is up to you to figure out how to access
|
||||
that for your system (for now). On macOS, you can also use the system `log` CLI
|
||||
utility with `log stream --level debug --predicate 'subsystem=="com.mitchellh.ghostty"'`.
|
||||
them and move on. Configuration errors will be logged.
|
||||
|
||||
## Debugging Configuration
|
||||
|
||||
You can verify that configuration is being properly loaded by looking at the
|
||||
debug output of Ghostty. Documentation for how to view the debug output is in
|
||||
the "building Ghostty" section at the end of the README.
|
||||
debug output of Ghostty.
|
||||
|
||||
In the debug output, you should see in the first 20 lines or so messages about
|
||||
loading (or not loading) a configuration file, as well as any errors it may have
|
||||
|
|
@ -93,3 +89,34 @@ will fall back to default values for erroneous keys.
|
|||
You can also view the full configuration Ghostty is loading using `ghostty
|
||||
+show-config` from the command-line. Use the `--help` flag to additional options
|
||||
for that command.
|
||||
|
||||
## Logging
|
||||
|
||||
Ghostty can write logs to a number of destinations. On all platforms, logging to
|
||||
`stderr` is available. Depending on the platform and how Ghostty was launched,
|
||||
logs sent to `stderr` may be stored by the system and made available for later
|
||||
retrieval.
|
||||
|
||||
On Linux if Ghostty is launched by the default `systemd` user service, you can use
|
||||
`journald` to see Ghostty's logs: `journalctl --user --unit app-com.mitchellh.ghostty.service`.
|
||||
|
||||
On macOS logging to the macOS unified log is available and enabled by default.
|
||||
--Use the system `log` CLI to view Ghostty's logs: `sudo log stream level debug
|
||||
--predicate 'subsystem=="com.mitchellh.ghostty"'`.
|
||||
|
||||
Ghostty's logging can be configured in two ways. The first is by what
|
||||
optimization level Ghostty is compiled with. If Ghostty is compiled with `Debug`
|
||||
optimizations debug logs will be output to `stderr`. If Ghostty is compiled with
|
||||
any other optimization the debug logs will not be output to `stderr`.
|
||||
|
||||
Ghostty also checks the `GHOSTTY_LOG` environment variable. It can be used
|
||||
to control which destinations receive logs. Ghostty currently defines two
|
||||
destinations:
|
||||
|
||||
- `stderr` - logging to `stderr`.
|
||||
- `macos` - logging to macOS's unified log (has no effect on non-macOS platforms).
|
||||
|
||||
Combine values with a comma to enable multiple destinations. Prefix a
|
||||
destination with `no-` to disable it. Enabling and disabling destinations
|
||||
can be done at the same time. Setting `GHOSTTY_LOG` to `true` will enable all
|
||||
destinations. Setting `GHOSTTY_LOG` to `false` will disable all destinations.
|
||||
|
|
|
|||
|
|
@ -604,7 +604,7 @@ pub fn parseAutoStruct(
|
|||
return result;
|
||||
}
|
||||
|
||||
fn parsePackedStruct(comptime T: type, v: []const u8) !T {
|
||||
pub fn parsePackedStruct(comptime T: type, v: []const u8) !T {
|
||||
const info = @typeInfo(T).@"struct";
|
||||
comptime assert(info.layout == .@"packed");
|
||||
|
||||
|
|
|
|||
|
|
@ -39,9 +39,13 @@ pub const GlobalState = struct {
|
|||
resources_dir: internal_os.ResourcesDir,
|
||||
|
||||
/// Where logging should go
|
||||
pub const Logging = union(enum) {
|
||||
disabled: void,
|
||||
stderr: void,
|
||||
pub const Logging = packed struct {
|
||||
/// Whether to log to stderr. For lib mode we always disable stderr
|
||||
/// logging by default. Otherwise it's enabled by default.
|
||||
stderr: bool = build_config.app_runtime != .none,
|
||||
/// Whether to log to macOS's unified logging. Enabled by default
|
||||
/// on macOS.
|
||||
macos: bool = builtin.os.tag.isDarwin(),
|
||||
};
|
||||
|
||||
/// Initialize the global state.
|
||||
|
|
@ -61,7 +65,7 @@ pub const GlobalState = struct {
|
|||
.gpa = null,
|
||||
.alloc = undefined,
|
||||
.action = null,
|
||||
.logging = .{ .stderr = {} },
|
||||
.logging = .{},
|
||||
.rlimits = .{},
|
||||
.resources_dir = .{},
|
||||
};
|
||||
|
|
@ -100,12 +104,7 @@ pub const GlobalState = struct {
|
|||
// If we have an action executing, we disable logging by default
|
||||
// since we write to stderr we don't want logs messing up our
|
||||
// output.
|
||||
if (self.action != null) self.logging = .{ .disabled = {} };
|
||||
|
||||
// For lib mode we always disable stderr logging by default.
|
||||
if (comptime build_config.app_runtime == .none) {
|
||||
self.logging = .{ .disabled = {} };
|
||||
}
|
||||
if (self.action != null) self.logging.stderr = false;
|
||||
|
||||
// I don't love the env var name but I don't have it in my heart
|
||||
// to parse CLI args 3 times (once for actions, once for config,
|
||||
|
|
@ -114,9 +113,7 @@ pub const GlobalState = struct {
|
|||
// easy to set.
|
||||
if ((try internal_os.getenv(self.alloc, "GHOSTTY_LOG"))) |v| {
|
||||
defer v.deinit(self.alloc);
|
||||
if (v.value.len > 0) {
|
||||
self.logging = .{ .stderr = {} };
|
||||
}
|
||||
self.logging = cli.args.parsePackedStruct(Logging, v.value) catch .{};
|
||||
}
|
||||
|
||||
// Setup our signal handlers before logging
|
||||
|
|
|
|||
|
|
@ -118,19 +118,17 @@ fn logFn(
|
|||
comptime format: []const u8,
|
||||
args: anytype,
|
||||
) void {
|
||||
// Stuff we can do before the lock
|
||||
const level_txt = comptime level.asText();
|
||||
const prefix = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): ";
|
||||
|
||||
// Lock so we are thread-safe
|
||||
std.debug.lockStdErr();
|
||||
defer std.debug.unlockStdErr();
|
||||
|
||||
// On Mac, we use unified logging. To view this:
|
||||
//
|
||||
// sudo log stream --level debug --predicate 'subsystem=="com.mitchellh.ghostty"'
|
||||
//
|
||||
if (builtin.target.os.tag.isDarwin()) {
|
||||
// macOS logging is thread safe so no need for locks/mutexes
|
||||
macos: {
|
||||
if (comptime !builtin.target.os.tag.isDarwin()) break :macos;
|
||||
if (!state.logging.macos) break :macos;
|
||||
|
||||
const prefix = if (scope == .default) "" else @tagName(scope) ++ ": ";
|
||||
|
||||
// Convert our levels to Mac levels
|
||||
const mac_level: macos.os.LogType = switch (level) {
|
||||
.debug => .debug,
|
||||
|
|
@ -143,26 +141,35 @@ fn logFn(
|
|||
// but we shouldn't be logging too much.
|
||||
const logger = macos.os.Log.create(build_config.bundle_id, @tagName(scope));
|
||||
defer logger.release();
|
||||
logger.log(std.heap.c_allocator, mac_level, format, args);
|
||||
logger.log(std.heap.c_allocator, mac_level, prefix ++ format, args);
|
||||
}
|
||||
|
||||
switch (state.logging) {
|
||||
.disabled => {},
|
||||
stderr: {
|
||||
// don't log debug messages to stderr unless we are a debug build
|
||||
if (comptime builtin.mode != .Debug and level == .debug) break :stderr;
|
||||
|
||||
.stderr => {
|
||||
// Always try default to send to stderr
|
||||
var buffer: [1024]u8 = undefined;
|
||||
var stderr = std.fs.File.stderr().writer(&buffer);
|
||||
const writer = &stderr.interface;
|
||||
nosuspend writer.print(level_txt ++ prefix ++ format ++ "\n", args) catch return;
|
||||
// TODO: Do we want to use flushless stderr in the future?
|
||||
writer.flush() catch {};
|
||||
},
|
||||
// skip if we are not logging to stderr
|
||||
if (!state.logging.stderr) break :stderr;
|
||||
|
||||
// Lock so we are thread-safe
|
||||
var buf: [64]u8 = undefined;
|
||||
const stderr = std.debug.lockStderrWriter(&buf);
|
||||
defer std.debug.unlockStderrWriter();
|
||||
|
||||
const level_txt = comptime level.asText();
|
||||
const prefix = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): ";
|
||||
nosuspend stderr.print(level_txt ++ prefix ++ format ++ "\n", args) catch break :stderr;
|
||||
nosuspend stderr.flush() catch break :stderr;
|
||||
}
|
||||
}
|
||||
|
||||
pub const std_options: std.Options = .{
|
||||
// Our log level is always at least info in every build mode.
|
||||
//
|
||||
// Note, we don't lower this to debug even with conditional logging
|
||||
// via GHOSTTY_LOG because our debug logs are very expensive to
|
||||
// calculate and we want to make sure they're optimized out in
|
||||
// builds.
|
||||
.log_level = switch (builtin.mode) {
|
||||
.Debug => .debug,
|
||||
else => .info,
|
||||
|
|
|
|||
Loading…
Reference in New Issue