mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-10-19 08:15:38 +00:00
fix(core): show complete instance startup errors (#2724)
Restore the CLI's default instance-manager diagnostics without enabling unrelated module logs. Include failed instance IDs and their saved error chains in the final exit error. Attach the listener URL to required-listener failures and render full error chains in startup logs, so bind failures expose their OS cause. Extend listener regression coverage and document the default CLI targets.
This commit is contained in:
@@ -552,6 +552,13 @@ optional `tracing` feature selects the tokio-console subscriber integration;
|
||||
only that diagnostic profile pulls the main crate's `tracing-subscriber` and
|
||||
`console-subscriber` dependencies.
|
||||
|
||||
The native CLI enables the `CORE` and `easytier_core::instance::manager` console
|
||||
targets by default. Instance startup failures are reported immediately with the
|
||||
instance ID and complete error chain, including the listener URL for bind
|
||||
failures. When all instances stop, the CLI's failure summary retains each failed
|
||||
instance's ID and saved error. Explicit console levels and `RUST_LOG` directives
|
||||
still control which records are emitted.
|
||||
|
||||
Contrib applications and platform integrations may have independent logging
|
||||
requirements and are not implicitly wired to the native process logger.
|
||||
|
||||
|
||||
@@ -387,7 +387,11 @@ where
|
||||
let instance_state_changes = self.instance_state_changes.clone();
|
||||
runtime.spawn(async move {
|
||||
if let Err(error) = instance.start().await {
|
||||
tracing::error!(%error, %instance_id, "instance failed to start");
|
||||
tracing::error!(
|
||||
error = %format_args!("{error:#}"),
|
||||
%instance_id,
|
||||
"instance failed to start"
|
||||
);
|
||||
}
|
||||
instance_state_changes.mark_changed();
|
||||
notifier.notify_one();
|
||||
|
||||
@@ -342,10 +342,11 @@ where
|
||||
Accepted: Send + 'static,
|
||||
{
|
||||
let mut listener = creator();
|
||||
match listener.listen().await {
|
||||
Ok(()) => Ok(listener),
|
||||
Err(error) => Err(error),
|
||||
}
|
||||
listener
|
||||
.listen()
|
||||
.await
|
||||
.with_context(|| format!("failed to listen on {}", listener.local_url()))?;
|
||||
Ok(listener)
|
||||
}
|
||||
|
||||
async fn run_listener<Accepted, H>(
|
||||
@@ -782,7 +783,8 @@ mod tests {
|
||||
true,
|
||||
);
|
||||
|
||||
assert!(manager.run().await.is_err());
|
||||
let error = manager.run().await.unwrap_err();
|
||||
assert!(format!("{error:#}").contains("mock://second"));
|
||||
crate::foundation::time::sleep(Duration::from_millis(20)).await;
|
||||
assert!(handler.accepted.lock().unwrap().is_empty());
|
||||
assert!(
|
||||
|
||||
+18
-6
@@ -29,6 +29,7 @@ use rust_i18n::t;
|
||||
use serde_json::{Value, json};
|
||||
use std::str::FromStr;
|
||||
use std::{
|
||||
fmt::Write as _,
|
||||
net::{IpAddr, SocketAddr},
|
||||
path::PathBuf,
|
||||
process::ExitCode,
|
||||
@@ -1211,7 +1212,11 @@ fn win_service_main(arg: Vec<std::ffi::OsString>) {
|
||||
|
||||
async fn run_main(cli: Cli) -> anyhow::Result<()> {
|
||||
defer!(dump_profile(0););
|
||||
log::init(&cli.logging_options, true)?;
|
||||
log::init_with_default_console_targets(
|
||||
&cli.logging_options,
|
||||
true,
|
||||
&["CORE", "easytier_core::instance::manager"],
|
||||
)?;
|
||||
|
||||
let manager = Arc::new(native_cli_instance_manager().with_config_path(cli.config_dir.clone()));
|
||||
|
||||
@@ -1360,10 +1365,17 @@ async fn run_main(cli: Cli) -> anyhow::Result<()> {
|
||||
tokio::select! {
|
||||
_ = manager.wait() => {
|
||||
let infos = manager.collect_network_infos().await?;
|
||||
if infos
|
||||
.into_values()
|
||||
.filter_map(|info| info.error_msg).next().is_some() {
|
||||
return Err(anyhow::anyhow!("some instances stopped with errors"));
|
||||
let mut errors = String::new();
|
||||
for (instance_id, info) in infos {
|
||||
if let Some(error) = info.error_msg {
|
||||
if errors.is_empty() {
|
||||
errors.push_str("some instances stopped with errors:");
|
||||
}
|
||||
write!(errors, "\n{instance_id}: {error}").unwrap();
|
||||
}
|
||||
}
|
||||
if !errors.is_empty() {
|
||||
return Err(anyhow::anyhow!(errors));
|
||||
}
|
||||
}
|
||||
_ = tokio::signal::ctrl_c() => {
|
||||
@@ -1489,7 +1501,7 @@ pub async fn main() -> ExitCode {
|
||||
let mut ret_code = 0;
|
||||
|
||||
if let Err(error) = run_main(cli).await {
|
||||
log::error!(%error);
|
||||
log::error!(error = %format_args!("{error:#}"));
|
||||
ret_code = 1;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user