Log like a debug build on macOS, where a Mac user can find it
Nobody working on DarkRoom has a Mac, so every macOS build is in the hands of someone who can send a log and cannot attach a debugger. Three changes make that log worth sending: - The desktop's default filter on macOS is `debug` for every `dr_*` crate, the desktop crate and `onnxruntime` (the runtime's own session log). - The state directory — the log and crash records — is `~/Library/Logs` on macOS rather than the `~/.local/state` Finder hides; Console.app lists it. Config and data keep the Unix rules. - A `diagnostic` cargo profile: release plus line tables, so a crash record's backtrace reads file:line. On macOS the tables are in the `.dSYM` beside the executable, which the bundle must keep.
This commit is contained in:
+12
@@ -278,6 +278,18 @@ opt-level = 0
|
||||
lto = "thin"
|
||||
codegen-units = 1
|
||||
|
||||
# A release build that can say where it panicked: line tables, so a crash
|
||||
# record's backtrace (`dr_plat::crash`) reads `file.rs:123` rather than bare
|
||||
# addresses. The macOS build uses it (docs/dev/macos.md) — no one here can
|
||||
# reproduce a Mac bug, so its reports carry what a debugger would have — at
|
||||
# the price of a larger binary and no slower code. On macOS the tables land
|
||||
# in a `.dSYM` beside the executable (rustc's default `packed`), and the
|
||||
# bundle must carry that directory next to the binary for the backtrace to
|
||||
# find it.
|
||||
[profile.diagnostic]
|
||||
inherits = "release"
|
||||
debug = "line-tables-only"
|
||||
|
||||
# Three upstream crates carry a local patch: wgpu-hal and Slint's Skia
|
||||
# renderer so that the Android build can draw with wgpu on a rotated display
|
||||
# (technical-debt.md TD-1), and rawler so that a linear DNG wider than 16 700
|
||||
|
||||
@@ -15,6 +15,22 @@ use std::path::PathBuf;
|
||||
|
||||
use dr_plat::diagnostics::Installed;
|
||||
|
||||
/// What the log keeps when `RUST_LOG` does not say.
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
const DEFAULT_LOG: &str =
|
||||
"info,wgpu_core=warn,wgpu_hal=warn,zbus=warn,tracing=warn,calloop=warn,rawler=warn";
|
||||
|
||||
/// The same, and `debug` from this application's own crates and from ONNX
|
||||
/// Runtime, whose `debug` is how many nodes each provider took
|
||||
/// (docs/dev/macos.md). Nobody here runs a Mac: every macOS build is in
|
||||
/// the hands of someone who can send us a log and cannot attach a debugger,
|
||||
/// so the log is written as if for a debug build. `dr_` is a prefix, and
|
||||
/// `env_logger` matches directives by prefix, so it names every `dr-*`
|
||||
/// crate — present and future — without naming a dependency.
|
||||
#[cfg(target_os = "macos")]
|
||||
const DEFAULT_LOG: &str = "info,dr_=debug,darkroom_desktop=debug,onnxruntime=debug,\
|
||||
wgpu_core=warn,wgpu_hal=warn,zbus=warn,tracing=warn,calloop=warn,rawler=warn";
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
// TRACES: FR-PLAT-WIN-3
|
||||
// Before the logger, the crash hook and everything else: this exists so a
|
||||
@@ -33,10 +49,9 @@ fn main() -> anyhow::Result<()> {
|
||||
// (NFR-OPS-1). `filter()` is asked afterwards because the environment may
|
||||
// have overridden the default below, and the file must not be quieter than
|
||||
// the terminal.
|
||||
let console = env_logger::Builder::from_env(env_logger::Env::default().default_filter_or(
|
||||
"info,wgpu_core=warn,wgpu_hal=warn,zbus=warn,tracing=warn,calloop=warn,rawler=warn",
|
||||
))
|
||||
.build();
|
||||
let console =
|
||||
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or(DEFAULT_LOG))
|
||||
.build();
|
||||
let level = console.filter();
|
||||
let logging = dr_plat::diagnostics::install(Box::new(console), level);
|
||||
|
||||
|
||||
@@ -98,7 +98,8 @@ pub fn set_state_dir(dir: PathBuf) {
|
||||
|
||||
/// Where this application keeps state that is neither configuration nor cache.
|
||||
///
|
||||
/// `$XDG_STATE_HOME/darkroom`, falling back to `~/.local/state/darkroom`.
|
||||
/// `$XDG_STATE_HOME/darkroom`, falling back to `~/.local/state/darkroom` —
|
||||
/// `~/Library/Logs/darkroom` on macOS (`dirs`).
|
||||
/// State rather than cache because a crash record must survive the sweep that
|
||||
/// a cache directory exists to permit, and rather than config because it is
|
||||
/// not something the user edits.
|
||||
|
||||
@@ -46,6 +46,8 @@
|
||||
//!
|
||||
//! * Linux: `$XDG_STATE_HOME/darkroom/darkroom.log`, else
|
||||
//! `~/.local/state/darkroom/darkroom.log`.
|
||||
//! * macOS: `$XDG_STATE_HOME/darkroom/darkroom.log`, else
|
||||
//! `~/Library/Logs/darkroom/darkroom.log`, where Console.app lists it.
|
||||
//! * Android: `/sdcard/Android/data/paris.tourolle.darkroom/files/darkroom.log`,
|
||||
//! which `adb pull` reads from an ordinary release build. See
|
||||
//! [`crate::state`] for why not the internal directory, and
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
//! | Unix default | `~/.config` | `~/.local/share` | `~/.local/state` |
|
||||
//! | Windows | `%APPDATA%` | `%LOCALAPPDATA%` | `%LOCALAPPDATA%`, then `state` |
|
||||
//! | Windows default | `%USERPROFILE%\AppData\Roaming` | `…\AppData\Local` | `…\AppData\Local` |
|
||||
//! | macOS default | `~/.config` | `~/.local/share` | `~/Library/Logs` |
|
||||
//!
|
||||
//! macOS follows the Unix rules except for the one directory a user is asked
|
||||
//! to find by hand: the log. Finder hides `~/.local`, and `~/Library/Logs`
|
||||
//! is where Console.app and a Mac user already look (docs/dev/macos.md).
|
||||
//!
|
||||
//! then `darkroom` under each. Config roams on Windows and the rest does not,
|
||||
//! which is the same split XDG makes between config and everything else, and
|
||||
@@ -100,11 +105,18 @@ fn resolve(kind: Base, env: impl Fn(&str) -> Option<OsString>) -> PathBuf {
|
||||
}
|
||||
}
|
||||
|
||||
/// Where state goes under `$HOME` when `XDG_STATE_HOME` does not say.
|
||||
const STATE_UNDER_HOME: &str = if cfg!(target_os = "macos") {
|
||||
"Library/Logs"
|
||||
} else {
|
||||
".local/state"
|
||||
};
|
||||
|
||||
fn xdg_base(kind: Base, env: &impl Fn(&str) -> Option<OsString>) -> Option<PathBuf> {
|
||||
let (var, under_home) = match kind {
|
||||
Base::Config => ("XDG_CONFIG_HOME", ".config"),
|
||||
Base::Data => ("XDG_DATA_HOME", ".local/share"),
|
||||
Base::State => ("XDG_STATE_HOME", ".local/state"),
|
||||
Base::State => ("XDG_STATE_HOME", STATE_UNDER_HOME),
|
||||
};
|
||||
absolute(env(var)).or_else(|| absolute(env("HOME")).map(|h| h.join(under_home)))
|
||||
}
|
||||
@@ -150,7 +162,7 @@ mod tests {
|
||||
);
|
||||
assert_eq!(
|
||||
xdg_base(Base::State, &e),
|
||||
Some(PathBuf::from("/home/someone/.local/state"))
|
||||
Some(PathBuf::from("/home/someone").join(STATE_UNDER_HOME))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -162,7 +174,7 @@ mod tests {
|
||||
let e = env(&[("XDG_STATE_HOME", "state"), ("HOME", "/home/someone")]);
|
||||
assert_eq!(
|
||||
xdg_base(Base::State, &e),
|
||||
Some(PathBuf::from("/home/someone/.local/state"))
|
||||
Some(PathBuf::from("/home/someone").join(STATE_UNDER_HOME))
|
||||
);
|
||||
assert_eq!(xdg_base(Base::State, &env(&[("HOME", "")])), None);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user