From 5bcfef5c8695a27d0c61b083f896ef42c8f46cf1 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 26 Jun 2026 07:20:46 +0000 Subject: [PATCH 1/2] fix(dgw): write boot.stacktrace file when running as a service Previously the boot.stacktrace file was only written when Gateway ran in foreground/CLI mode. In Windows service mode, startup failures inside gateway_service_main (config init, service load, service start) only emitted a Windows event-log entry and returned an SCM error code, so no boot.stacktrace was produced even when the logging subsystem never came up. The boot.stacktrace-writing logic is now factored into a reusable helper and invoked from each service-mode startup-failure branch, in addition to the existing event-log reporting. Issue: DGW-401 --- devolutions-gateway/src/main.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/devolutions-gateway/src/main.rs b/devolutions-gateway/src/main.rs index ddf3168a1..cdfcd5da8 100644 --- a/devolutions-gateway/src/main.rs +++ b/devolutions-gateway/src/main.rs @@ -77,13 +77,15 @@ use tap::prelude::*; use crate::service::{DESCRIPTION, DISPLAY_NAME, GatewayService, SERVICE_NAME}; fn main() -> anyhow::Result<()> { - run().inspect_err(|error| { - let bootstacktrace_path = devolutions_gateway::config::get_data_dir().join("boot.stacktrace"); + run().inspect_err(write_boot_stacktrace) +} - if let Err(write_error) = std::fs::write(&bootstacktrace_path, format!("{error:?}")) { - eprintln!("Failed to write the boot stacktrace to {bootstacktrace_path}: {write_error}"); - } - }) +fn write_boot_stacktrace(error: &anyhow::Error) { + let bootstacktrace_path = devolutions_gateway::config::get_data_dir().join("boot.stacktrace"); + + if let Err(write_error) = std::fs::write(&bootstacktrace_path, format!("{error:?}")) { + eprintln!("Failed to write the boot stacktrace to {bootstacktrace_path}: {write_error}"); + } } fn run() -> anyhow::Result<()> { @@ -179,6 +181,8 @@ fn gateway_service_main( &error, devolutions_gateway::config::get_data_dir().join("gateway.json"), )); + // Also write the boot stacktrace, because the logging subsystem may never come up in service mode. + write_boot_stacktrace(&error); return BAD_CONFIG_ERR_CODE; } }; @@ -189,6 +193,8 @@ fn gateway_service_main( // At this point, the logger may or may not be initialized. error!(error = format!("{error:#}"), "Failed to load service"); let _ = SYSTEM_LOGGER.emit(sysevent_codes::start_failed(&error, "service_load")); + // Also write the boot stacktrace, because the logging subsystem may never come up in service mode. + write_boot_stacktrace(&error); return START_FAILED_ERR_CODE; } }; @@ -201,6 +207,8 @@ fn gateway_service_main( Err(error) => { error!(error = format!("{error:#}"), "Failed to start"); let _ = SYSTEM_LOGGER.emit(sysevent_codes::start_failed(&error, "service_start")); + // Also write the boot stacktrace, because the logging subsystem may never come up in service mode. + write_boot_stacktrace(&error); return START_FAILED_ERR_CODE; } } From 59b56dd47e36ee4c36676b20775bafbaff8f99ab Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 26 Jun 2026 07:34:43 +0000 Subject: [PATCH 2/2] fix(dgw): ensure data directory exists before writing boot.stacktrace Per review feedback on DGW-401: write_boot_stacktrace assumed the data directory already existed. In service mode the eprintln fallback is not visible, so a missing directory silently lost the diagnostic file. Now create_dir_all is attempted (best-effort) before the write. --- devolutions-gateway/src/main.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/devolutions-gateway/src/main.rs b/devolutions-gateway/src/main.rs index cdfcd5da8..059f4044d 100644 --- a/devolutions-gateway/src/main.rs +++ b/devolutions-gateway/src/main.rs @@ -81,7 +81,13 @@ fn main() -> anyhow::Result<()> { } fn write_boot_stacktrace(error: &anyhow::Error) { - let bootstacktrace_path = devolutions_gateway::config::get_data_dir().join("boot.stacktrace"); + let data_dir = devolutions_gateway::config::get_data_dir(); + let bootstacktrace_path = data_dir.join("boot.stacktrace"); + + // Best-effort directory creation: in service mode the eprintln fallback below is not visible, so make sure the write can succeed. + if let Err(create_error) = std::fs::create_dir_all(&data_dir) { + eprintln!("Failed to create the data directory {data_dir}: {create_error}"); + } if let Err(write_error) = std::fs::write(&bootstacktrace_path, format!("{error:?}")) { eprintln!("Failed to write the boot stacktrace to {bootstacktrace_path}: {write_error}");