fix(windows): unify config/data dir and add service log file

config_dir() on Windows now returns data_dir() (ProgramData) so config,
services.json, and log file are in the same place for both interactive
and service contexts. Service mode writes logs to numa.log via
env_logger pipe. Dashboard shows correct log path per OS.
This commit is contained in:
Razvan Dimescu
2026-04-16 19:12:42 +03:00
parent f0a1dd7106
commit 9bea038cb6
3 changed files with 28 additions and 23 deletions

View File

@@ -1153,13 +1153,10 @@ async function refresh() {
const isWin = stats.data_dir && stats.data_dir.includes(':\\'); const isWin = stats.data_dir && stats.data_dir.includes(':\\');
const isMac = stats.data_dir && stats.data_dir.includes('/usr/local/'); const isMac = stats.data_dir && stats.data_dir.includes('/usr/local/');
const logsEl = document.getElementById('footerLogs'); const logsEl = document.getElementById('footerLogs');
if (isWin) { logsEl.textContent = isWin
document.getElementById('footerLogsWrap').style.display = 'none'; ? stats.data_dir + '\\numa.log'
} else { : isMac ? '/usr/local/var/log/numa.log'
logsEl.textContent = isMac : 'journalctl -u numa -f';
? '/usr/local/var/log/numa.log'
: 'journalctl -u numa -f';
}
} }
// LAN status indicator // LAN status indicator
@@ -1523,7 +1520,7 @@ setInterval(refresh, 2000);
<div style="text-align:center;padding:0.8rem 0.8rem 0.4rem;font-family:var(--font-mono);font-size:0.68rem;color:var(--text-dim);line-height:1.8;"> <div style="text-align:center;padding:0.8rem 0.8rem 0.4rem;font-family:var(--font-mono);font-size:0.68rem;color:var(--text-dim);line-height:1.8;">
Config: <span id="footerConfig" style="user-select:all;color:var(--emerald);"></span> Config: <span id="footerConfig" style="user-select:all;color:var(--emerald);"></span>
· Data: <span id="footerData" style="user-select:all;color:var(--emerald);"></span> · Data: <span id="footerData" style="user-select:all;color:var(--emerald);"></span>
<span id="footerLogsWrap">· Logs: <span id="footerLogs" style="user-select:all;color:var(--emerald);"></span></span> · Logs: <span id="footerLogs" style="user-select:all;color:var(--emerald);"></span>
<br> <br>
Upstream: <span id="footerUpstream" style="user-select:all;color:var(--emerald);"></span> Upstream: <span id="footerUpstream" style="user-select:all;color:var(--emerald);"></span>
· DNSSEC: <span id="footerDnssec" style="color:var(--text-dim);"></span> · DNSSEC: <span id="footerDnssec" style="color:var(--text-dim);"></span>

View File

@@ -101,14 +101,11 @@ where
/// Linux root daemon: /var/lib/numa (FHS) — falls back to /usr/local/var/numa /// Linux root daemon: /var/lib/numa (FHS) — falls back to /usr/local/var/numa
/// if a pre-v0.10.1 install already lives there. /// if a pre-v0.10.1 install already lives there.
/// macOS root daemon: /usr/local/var/numa (Homebrew prefix) /// macOS root daemon: /usr/local/var/numa (Homebrew prefix)
/// Windows: %APPDATA%\numa /// Windows: %PROGRAMDATA%\numa (same as data_dir — no per-user config on Windows)
pub fn config_dir() -> std::path::PathBuf { pub fn config_dir() -> std::path::PathBuf {
#[cfg(windows)] #[cfg(windows)]
{ {
std::path::PathBuf::from( data_dir()
std::env::var("APPDATA").unwrap_or_else(|_| "C:\\ProgramData".into()),
)
.join("numa")
} }
#[cfg(not(windows))] #[cfg(not(windows))]
{ {

View File

@@ -4,21 +4,32 @@ use numa::system_dns::{
}; };
fn main() -> numa::Result<()> { fn main() -> numa::Result<()> {
// Handle CLI subcommands
let arg1 = std::env::args().nth(1).unwrap_or_default();
#[cfg(windows)]
if arg1 == "--service" {
// Running under SCM — stderr goes nowhere. Redirect logs to a file.
let log_path = numa::data_dir().join("numa.log");
let log_file = std::fs::OpenOptions::new()
.create(true)
.append(true)
.open(&log_path)
.expect("failed to open log file");
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info"))
.format_timestamp_millis()
.target(env_logger::Target::Pipe(Box::new(log_file)))
.init();
numa::windows_service::run_as_service()
.map_err(|e| format!("windows service dispatcher failed: {}", e))?;
return Ok(());
}
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")) env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info"))
.format_timestamp_millis() .format_timestamp_millis()
.init(); .init();
// Handle CLI subcommands
let arg1 = std::env::args().nth(1).unwrap_or_default();
match arg1.as_str() { match arg1.as_str() {
#[cfg(windows)]
"--service" => {
// Entry point used by Windows SCM (`sc create … binPath="numa.exe --service"`).
// Blocks until SCM sends Stop; never returns normally.
numa::windows_service::run_as_service()
.map_err(|e| format!("windows service dispatcher failed: {}", e))?;
return Ok(());
}
"install" => { "install" => {
eprintln!("\x1b[1;38;2;192;98;58mNuma\x1b[0m — installing\n"); eprintln!("\x1b[1;38;2;192;98;58mNuma\x1b[0m — installing\n");
return install_service().map_err(|e| e.into()); return install_service().map_err(|e| e.into());