Capture logs for snap apps as well
This commit is contained in:
parent
1e584f2907
commit
15697465c5
4 changed files with 50 additions and 5 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
|
@ -1187,6 +1187,12 @@ dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shell-escape"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shepherd-api"
|
name = "shepherd-api"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
@ -1252,6 +1258,7 @@ dependencies = [
|
||||||
"dirs",
|
"dirs",
|
||||||
"nix",
|
"nix",
|
||||||
"serde",
|
"serde",
|
||||||
|
"shell-escape",
|
||||||
"shepherd-api",
|
"shepherd-api",
|
||||||
"shepherd-host-api",
|
"shepherd-host-api",
|
||||||
"shepherd-util",
|
"shepherd-util",
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ config_version = 1
|
||||||
# data_dir = "~/.local/share/shepherdd"
|
# data_dir = "~/.local/share/shepherdd"
|
||||||
|
|
||||||
# Capture stdout/stderr from child applications to log files
|
# Capture stdout/stderr from child applications to log files
|
||||||
# Logs are written to child_log_dir (or log_dir/sessions if not set)` to view logs.
|
# Logs are written to child_log_dir (or log_dir/sessions if not set)
|
||||||
# File format: <entry_id>_<timestamp>.log
|
# File format: <entry_id>_<timestamp>.log
|
||||||
# capture_child_output = true
|
# capture_child_output = true
|
||||||
# child_log_dir = "~/.local/state/shepherdd/sessions"
|
# child_log_dir = "~/.local/state/shepherdd/sessions"
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ tokio = { workspace = true }
|
||||||
nix = { workspace = true }
|
nix = { workspace = true }
|
||||||
async-trait = "0.1"
|
async-trait = "0.1"
|
||||||
dirs = "5.0"
|
dirs = "5.0"
|
||||||
|
shell-escape = "0.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = { workspace = true }
|
tempfile = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,8 @@ impl ManagedProcess {
|
||||||
/// systemd scope-based killing instead of signal-based killing.
|
/// systemd scope-based killing instead of signal-based killing.
|
||||||
///
|
///
|
||||||
/// If `log_path` is provided, stdout and stderr will be redirected to that file.
|
/// If `log_path` is provided, stdout and stderr will be redirected to that file.
|
||||||
|
/// For snap apps, we use `script` to capture output from all child processes
|
||||||
|
/// via a pseudo-terminal, since snap child processes don't inherit file descriptors.
|
||||||
pub fn spawn(
|
pub fn spawn(
|
||||||
argv: &[String],
|
argv: &[String],
|
||||||
env: &HashMap<String, String>,
|
env: &HashMap<String, String>,
|
||||||
|
|
@ -141,8 +143,42 @@ impl ManagedProcess {
|
||||||
return Err(HostError::SpawnFailed("Empty argv".into()));
|
return Err(HostError::SpawnFailed("Empty argv".into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let program = &argv[0];
|
// For snap apps with log capture, wrap with `script` to capture all child output
|
||||||
let args = &argv[1..];
|
// via a pseudo-terminal. Snap child processes don't inherit file descriptors,
|
||||||
|
// but they do write to the controlling terminal.
|
||||||
|
let (actual_argv, actual_log_path) = match (&snap_name, &log_path) {
|
||||||
|
(Some(_), Some(log_file)) => {
|
||||||
|
// Create parent directory if it doesn't exist
|
||||||
|
if let Some(parent) = log_file.parent()
|
||||||
|
&& let Err(e) = std::fs::create_dir_all(parent)
|
||||||
|
{
|
||||||
|
warn!(path = %parent.display(), error = %e, "Failed to create log directory");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build command: script -q -c "original command" logfile
|
||||||
|
// -q: quiet mode (no start/done messages)
|
||||||
|
// -c: command to run
|
||||||
|
let original_cmd = argv.iter()
|
||||||
|
.map(|arg| shell_escape::escape(std::borrow::Cow::Borrowed(arg)))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(" ");
|
||||||
|
|
||||||
|
let script_argv = vec![
|
||||||
|
"script".to_string(),
|
||||||
|
"-q".to_string(),
|
||||||
|
"-c".to_string(),
|
||||||
|
original_cmd,
|
||||||
|
log_file.to_string_lossy().to_string(),
|
||||||
|
];
|
||||||
|
|
||||||
|
info!(log_path = %log_file.display(), "Using script to capture snap output via pty");
|
||||||
|
(script_argv, None) // script handles the log file itself
|
||||||
|
}
|
||||||
|
_ => (argv.to_vec(), log_path),
|
||||||
|
};
|
||||||
|
|
||||||
|
let program = &actual_argv[0];
|
||||||
|
let args = &actual_argv[1..];
|
||||||
|
|
||||||
let mut cmd = Command::new(program);
|
let mut cmd = Command::new(program);
|
||||||
cmd.args(args);
|
cmd.args(args);
|
||||||
|
|
@ -248,9 +284,10 @@ impl ManagedProcess {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure output handling
|
// Configure output handling
|
||||||
// If log_path is provided, redirect stdout/stderr to the log file
|
// If actual_log_path is provided, redirect stdout/stderr to the log file
|
||||||
|
// (For snap apps, we already wrapped with `script` which handles logging)
|
||||||
// Otherwise, inherit from parent so we can see child output for debugging
|
// Otherwise, inherit from parent so we can see child output for debugging
|
||||||
if let Some(ref path) = log_path {
|
if let Some(ref path) = actual_log_path {
|
||||||
// Create parent directory if it doesn't exist
|
// Create parent directory if it doesn't exist
|
||||||
if let Some(parent) = path.parent()
|
if let Some(parent) = path.parent()
|
||||||
&& let Err(e) = std::fs::create_dir_all(parent)
|
&& let Err(e) = std::fs::create_dir_all(parent)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue