diff --git a/common/bin-common/Cargo.toml b/common/bin-common/Cargo.toml index 9ed9958a07..44f12bc19d 100644 --- a/common/bin-common/Cargo.toml +++ b/common/bin-common/Cargo.toml @@ -47,8 +47,9 @@ default = [] openapi = ["utoipa"] output_format = ["serde_json"] bin_info_schema = ["schemars"] +basic_tracing = ["tracing-subscriber"] tracing = [ - "tracing-subscriber", + "basic_tracing", "tracing-tree", "opentelemetry-jaeger", "tracing-opentelemetry", diff --git a/common/bin-common/src/logging/mod.rs b/common/bin-common/src/logging/mod.rs index 135736ac2b..b32281886f 100644 --- a/common/bin-common/src/logging/mod.rs +++ b/common/bin-common/src/logging/mod.rs @@ -43,6 +43,23 @@ pub fn setup_logging() { .init(); } +#[cfg(feature = "basic_tracing")] +pub fn setup_tracing_logger() { + tracing_subscriber::fmt() + // Use a more compact, abbreviated log format + .compact() + // Display source code file paths + .with_file(true) + // Display source code line numbers + .with_line_number(true) + // Don't display the event's target (module path) + .with_target(false) + // use env filter + .with_env_filter(tracing_subscriber::filter::EnvFilter::from_default_env()) + // Set the global subscriber + .init(); +} + // TODO: This has to be a macro, running it as a function does not work for the file_appender for some reason #[cfg(feature = "tracing")] #[macro_export] diff --git a/tools/nymvisor/Cargo.toml b/tools/nymvisor/Cargo.toml index acb1f0620a..ac23f9b2d8 100644 --- a/tools/nymvisor/Cargo.toml +++ b/tools/nymvisor/Cargo.toml @@ -24,5 +24,5 @@ tokio = { workspace = true, features = ["rt", "macros", "signal", "process"] } thiserror = { workspace = true } tracing = { workspace = true } -nym-bin-common = { path = "../../common/bin-common", features = ["output_format"] } +nym-bin-common = { path = "../../common/bin-common", features = ["output_format", "basic_tracing"] } nym-config = { path = "../../common/config" } diff --git a/tools/nymvisor/src/cli/init.rs b/tools/nymvisor/src/cli/init.rs index 749fc56483..c5f2dcd837 100644 --- a/tools/nymvisor/src/cli/init.rs +++ b/tools/nymvisor/src/cli/init.rs @@ -6,10 +6,12 @@ use crate::daemon::helpers::get_daemon_build_information; use crate::env::Env; use crate::error::NymvisorError; use nym_bin_common::build_information::BinaryBuildInformationOwned; +use nym_bin_common::logging::{setup_logging, setup_tracing_logger}; use nym_bin_common::output_format::OutputFormat; use std::fs; use std::path::{Path, PathBuf}; use std::time::Duration; +use tracing::{debug, error, info, trace, warn}; #[derive(clap::Args, Debug)] pub(crate) struct Args { @@ -157,12 +159,19 @@ fn try_build_config( let daemon_name = &daemon_info.binary_name; let daemon_home = daemon_home(args, env)?; + debug!( + "building config for '{daemon_name}' with home at {}", + daemon_home.display() + ); + let mut config = Config::new(daemon_name, daemon_home); // override config with environmental variables + debug!("overriding the config with command line arguments"); args.override_config(&mut config); // and then override the result with the passed arguments + debug!("overriding the config with environmental variables"); env.override_config(&mut config); Ok(config) @@ -191,12 +200,16 @@ fn use_logs(args: &Args, env: &Env) -> bool { fn init_paths(config: &Config) -> Result<(), NymvisorError> { fn init_path>(path: P) -> Result<(), NymvisorError> { let path = path.as_ref(); + trace!("initialising {}", path.display()); + fs::create_dir_all(path).map_err(|source| NymvisorError::PathInitFailure { path: path.to_path_buf(), source, }) } + info!("initialising the directory structure"); + init_path(config.daemon_nymvisor_dir())?; init_path(config.daemon_backup_dir())?; init_path(config.upgrade_data_dir())?; @@ -207,6 +220,8 @@ fn init_paths(config: &Config) -> Result<(), NymvisorError> { } fn copy_genesis_binary(config: &Config, source_dir: &Path) -> Result<(), NymvisorError> { + info!("setting up the genesis binary"); + // TODO: setup initial upgrade-info.json file let target = config.genesis_daemon_binary(); fs::copy(source_dir, &target).map_err(|source| NymvisorError::DaemonBinaryCopyFailure { @@ -218,6 +233,8 @@ fn copy_genesis_binary(config: &Config, source_dir: &Path) -> Result<(), Nymviso } fn create_current_symlink(config: &Config) -> Result<(), NymvisorError> { + info!("setting up the symlink to the genesis directory"); + let original = config.genesis_daemon_dir(); let link = config.current_daemon_dir(); std::os::unix::fs::symlink(&original, &link).map_err(|source| { @@ -230,6 +247,8 @@ fn create_current_symlink(config: &Config) -> Result<(), NymvisorError> { } fn save_config(config: Config, env: &Env) -> Result<(), NymvisorError> { + info!("saving the config file"); + let id = &config.nymvisor.id; let config_save_location = env .nymvisor_config_path @@ -262,9 +281,12 @@ pub(crate) fn execute(args: Args) -> Result<(), NymvisorError> { let env = Env::try_read()?; if use_logs(&args, &env) { - println!("TODO: setup logger here") + setup_tracing_logger(); + info!("enabled nymvisor logging"); } + info!("initialising the nymvisor"); + // this serves two purposes: // 1. we get daemon name if it wasn't provided via either a flag or env variable // 2. we check if valid executable was provided @@ -277,6 +299,5 @@ pub(crate) fn execute(args: Args) -> Result<(), NymvisorError> { create_current_symlink(&config)?; save_config(config, &env)?; - println!("init"); Ok(()) } diff --git a/tools/nymvisor/src/cli/mod.rs b/tools/nymvisor/src/cli/mod.rs index 3d8c0444e7..8dc37494a8 100644 --- a/tools/nymvisor/src/cli/mod.rs +++ b/tools/nymvisor/src/cli/mod.rs @@ -7,11 +7,14 @@ mod config; mod init; mod run; -use crate::env::setup_env; +use crate::config::{default_config_filepath, Config}; +use crate::env::{setup_env, Env}; use crate::error::NymvisorError; use clap::{Parser, Subcommand}; use lazy_static::lazy_static; use nym_bin_common::bin_info; +use std::path::{Path, PathBuf}; +use tracing::error; lazy_static! { pub static ref PRETTY_BUILD_INFORMATION: String = bin_info!().pretty_print(); @@ -64,3 +67,37 @@ pub(crate) enum Commands { /// TODO: document the command Config(config::Args), } + +pub(crate) fn try_load_current_config(env: &Env) -> Result { + let config_load_location = if let Some(config_path) = &env.nymvisor_config_path { + config_path.clone() + } else { + // if no explicit path was provided in the environment, try to infer it with other vars + let id = env.try_nymvisor_id()?; + default_config_filepath(id) + }; + + if let Ok(cfg) = Config::read_from_toml_file(&config_load_location) { + return Ok(cfg); + } + + // we couldn't load it - try upgrading it from older revisions + try_upgrade_config(&config_load_location)?; + + match Config::read_from_toml_file(&config_load_location) { + Ok(cfg) => Ok(cfg), + Err(source) => { + error!("Failed to load config from {}. Are you sure you have run `init` before? (Error was: {source})", config_load_location.display()); + Err(NymvisorError::ConfigLoadFailure { + id: env.try_nymvisor_id().unwrap_or_default(), + path: config_load_location, + source, + }) + } + } +} + +// no upgrades for now +fn try_upgrade_config>(_config_location: P) -> Result<(), NymvisorError> { + Ok(()) +} diff --git a/tools/nymvisor/src/cli/run.rs b/tools/nymvisor/src/cli/run.rs index 2ed94fb816..c80d11f36d 100644 --- a/tools/nymvisor/src/cli/run.rs +++ b/tools/nymvisor/src/cli/run.rs @@ -1,8 +1,12 @@ // Copyright 2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +use crate::cli::try_load_current_config; +use crate::env::Env; use crate::error::NymvisorError; +use nym_bin_common::logging::setup_tracing_logger; use tokio::runtime; +use tracing::info; #[derive(clap::Args, Debug)] pub(crate) struct Args { @@ -12,6 +16,14 @@ pub(crate) struct Args { } pub(crate) fn execute(args: Args) -> Result<(), NymvisorError> { + let env = Env::try_read()?; + let config = try_load_current_config(&env)?; + if !config.nymvisor.debug.disable_logs { + setup_tracing_logger(); + } + + info!("starting nymvisor for {}", config.daemon.name); + // TODO: experiment with the minimal runtime // look at futures::executor::LocalPool let rt = runtime::Builder::new_current_thread() diff --git a/tools/nymvisor/src/daemon/helpers.rs b/tools/nymvisor/src/daemon/helpers.rs index 2c3458749c..de1c55a03e 100644 --- a/tools/nymvisor/src/daemon/helpers.rs +++ b/tools/nymvisor/src/daemon/helpers.rs @@ -4,14 +4,19 @@ use crate::error::NymvisorError; use crate::error::NymvisorError::DaemonBuildInformationParseFailure; use nym_bin_common::build_information::BinaryBuildInformationOwned; +use std::fmt::Debug; use std::os::unix::prelude::ExitStatusExt; use std::path::Path; +use tracing::{debug, info, instrument}; // each of our nym binaries (that are supported by `nymvisor`) expose `build-info` command // that outputs the build information -pub(crate) fn get_daemon_build_information>( +#[instrument] +pub(crate) fn get_daemon_build_information + Debug>( executable_path: P, ) -> Result { + info!("attempting to obtain daemon build information"); + let path = executable_path.as_ref(); // TODO: do we need any timeouts here or could we just assume this is not going to take an eternity to execute? @@ -24,6 +29,8 @@ pub(crate) fn get_daemon_build_information>( source, })?; + debug!("execution status: {}", raw.status); + if !raw.status.success() { return Err(NymvisorError::DaemonExecutionFailure { exit_code: raw.status.code(), diff --git a/tools/nymvisor/src/env.rs b/tools/nymvisor/src/env.rs index 868c7c4e9a..50e6e3a5ea 100644 --- a/tools/nymvisor/src/env.rs +++ b/tools/nymvisor/src/env.rs @@ -107,6 +107,16 @@ impl Env { config.daemon.debug.unsafe_skip_backup = daemon_unsafe_skip_backup; } } + + pub(crate) fn try_nymvisor_id(&self) -> Result { + if let Some(nymvisor_id) = &self.nymvisor_id { + Ok(nymvisor_id.clone()) + } else if let Some(daemon_name) = &self.daemon_name { + Ok(Config::default_id(&daemon_name)) + } else { + Err(NymvisorError::UnknownNymvisorInstance) + } + } } // TODO: all of those seem like they could be moved to some common crate if we ever needed similar functionality elsewhere diff --git a/tools/nymvisor/src/error.rs b/tools/nymvisor/src/error.rs index a9ea675980..6c3d9f56ee 100644 --- a/tools/nymvisor/src/error.rs +++ b/tools/nymvisor/src/error.rs @@ -83,6 +83,9 @@ pub(crate) enum NymvisorError { #[error("the value of daemon home has to be provided by either `--daemon-home` flag or `$DAEMON_HOME` environmental variable")] DaemonHomeUnavailable, + #[error("could not identify nymvisor instance. please specify either $NYMVISOR_CONFIG_PATH, $NYMVISOR_ID or $DAEMON_NAME")] + UnknownNymvisorInstance, + #[error("failed to obtain build information from the daemon executable ('{}'): {source}", binary_path.display())] DaemonBuildInformationFailure { binary_path: PathBuf,