change(ui): Enable the progress bar feature by default, but only show progress bars when the config is enabled (#7615)
* Add a progress bar config that is disabled unless the feature is on * Simplify the default config * Enable the progress bar feature by default, but require the config * Rename progress bars config to avoid merge conflicts * Use a log file when the progress bar is activated * Document how to configure progress bars * Handle log files in config_tests and check config path * Fix doc link * Fix path check * Fix config log matching * Fix clippy warning * Add tracing to config tests * It's zebrad not zebra * cargo fmt --all * Update release for config file changes * Fix config test failures * Allow printing to stdout in a method
This commit is contained in:
parent
0cffae5dd0
commit
ae52e3d23d
|
@ -5779,6 +5779,7 @@ dependencies = [
|
|||
"humantime",
|
||||
"indexmap 2.0.1",
|
||||
"insta",
|
||||
"itertools 0.11.0",
|
||||
"lazy_static",
|
||||
"once_cell",
|
||||
"owo-colors",
|
||||
|
|
17
README.md
17
README.md
|
@ -11,7 +11,7 @@
|
|||
- [Getting Started](#getting-started)
|
||||
- [Docker](#docker)
|
||||
- [Building Zebra](#building-zebra)
|
||||
- [Optional Features](#optional-features)
|
||||
- [Optional Configs & Features](#optional-features)
|
||||
- [Known Issues](#known-issues)
|
||||
- [Future Work](#future-work)
|
||||
- [Documentation](#documentation)
|
||||
|
@ -116,13 +116,24 @@ zebrad start
|
|||
See the [Installing Zebra](https://zebra.zfnd.org/user/install.html) and [Running Zebra](https://zebra.zfnd.org/user/run.html)
|
||||
sections in the book for more details.
|
||||
|
||||
#### Optional Features
|
||||
#### Optional Configs & Features
|
||||
|
||||
##### Configuring Progress Bars
|
||||
|
||||
Configure `tracing.progress_bar` in your `zebrad.toml` to
|
||||
[show key metrics in the terminal using progress bars](https://zfnd.org/experimental-zebra-progress-bars/).
|
||||
When progress bars are active, Zebra automatically sends logs to a file.
|
||||
|
||||
In future releases, the `progress_bar = "summary"` config will show a few key metrics,
|
||||
and the "detailed" config will show all available metrics. Please let us know which metrics are
|
||||
important to you!
|
||||
|
||||
##### Custom Build Features
|
||||
|
||||
You can also build Zebra with additional [Cargo features](https://doc.rust-lang.org/cargo/reference/features.html#command-line-feature-options):
|
||||
|
||||
- `getblocktemplate-rpcs` for [mining support](https://zebra.zfnd.org/user/mining.html)
|
||||
- `prometheus` for [Prometheus metrics](https://zebra.zfnd.org/user/metrics.html)
|
||||
- `progress-bar` [experimental progress bars](https://zfnd.org/experimental-zebra-progress-bars/)
|
||||
- `sentry` for [Sentry monitoring](https://zebra.zfnd.org/user/tracing.html#sentry-production-monitoring)
|
||||
- `elasticsearch` for [experimental Elasticsearch support](https://zebra.zfnd.org/user/elasticsearch.html)
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ hex = "0.4.3"
|
|||
indexmap = "2.0.1"
|
||||
lazy_static = "1.4.0"
|
||||
insta = "1.33.0"
|
||||
itertools = "0.11.0"
|
||||
proptest = "1.3.1"
|
||||
once_cell = "1.18.0"
|
||||
rand = "0.8.5"
|
||||
|
|
|
@ -21,10 +21,11 @@ use tracing::instrument;
|
|||
|
||||
#[macro_use]
|
||||
mod arguments;
|
||||
|
||||
pub mod to_regex;
|
||||
|
||||
pub use self::arguments::Arguments;
|
||||
use self::to_regex::{CollectRegexSet, ToRegex, ToRegexSet};
|
||||
use self::to_regex::{CollectRegexSet, ToRegexSet};
|
||||
|
||||
/// A super-trait for [`Iterator`] + [`Debug`].
|
||||
pub trait IteratorDebug: Iterator + Debug {}
|
||||
|
@ -791,7 +792,7 @@ impl<T> TestChild<T> {
|
|||
#[allow(clippy::unwrap_in_result)]
|
||||
pub fn expect_stdout_line_matches<R>(&mut self, success_regex: R) -> Result<String>
|
||||
where
|
||||
R: ToRegex + Debug,
|
||||
R: ToRegexSet + Debug,
|
||||
{
|
||||
self.apply_failure_regexes_to_outputs();
|
||||
|
||||
|
@ -823,7 +824,7 @@ impl<T> TestChild<T> {
|
|||
#[allow(clippy::unwrap_in_result)]
|
||||
pub fn expect_stderr_line_matches<R>(&mut self, success_regex: R) -> Result<String>
|
||||
where
|
||||
R: ToRegex + Debug,
|
||||
R: ToRegexSet + Debug,
|
||||
{
|
||||
self.apply_failure_regexes_to_outputs();
|
||||
|
||||
|
@ -855,7 +856,7 @@ impl<T> TestChild<T> {
|
|||
#[allow(clippy::unwrap_in_result)]
|
||||
pub fn expect_stdout_line_matches_silent<R>(&mut self, success_regex: R) -> Result<String>
|
||||
where
|
||||
R: ToRegex + Debug,
|
||||
R: ToRegexSet + Debug,
|
||||
{
|
||||
self.apply_failure_regexes_to_outputs();
|
||||
|
||||
|
@ -887,7 +888,7 @@ impl<T> TestChild<T> {
|
|||
#[allow(clippy::unwrap_in_result)]
|
||||
pub fn expect_stderr_line_matches_silent<R>(&mut self, success_regex: R) -> Result<String>
|
||||
where
|
||||
R: ToRegex + Debug,
|
||||
R: ToRegexSet + Debug,
|
||||
{
|
||||
self.apply_failure_regexes_to_outputs();
|
||||
|
||||
|
@ -1246,9 +1247,9 @@ impl<T> TestOutput<T> {
|
|||
#[allow(clippy::unwrap_in_result)]
|
||||
pub fn stdout_matches<R>(&self, regex: R) -> Result<&Self>
|
||||
where
|
||||
R: ToRegex + Debug,
|
||||
R: ToRegexSet + Debug,
|
||||
{
|
||||
let re = regex.to_regex().expect("regex must be valid");
|
||||
let re = regex.to_regex_set().expect("regex must be valid");
|
||||
|
||||
self.output_check(
|
||||
|stdout| re.is_match(stdout),
|
||||
|
@ -1270,9 +1271,9 @@ impl<T> TestOutput<T> {
|
|||
#[allow(clippy::unwrap_in_result)]
|
||||
pub fn stdout_line_matches<R>(&self, regex: R) -> Result<&Self>
|
||||
where
|
||||
R: ToRegex + Debug,
|
||||
R: ToRegexSet + Debug,
|
||||
{
|
||||
let re = regex.to_regex().expect("regex must be valid");
|
||||
let re = regex.to_regex_set().expect("regex must be valid");
|
||||
|
||||
self.any_output_line(
|
||||
|line| re.is_match(line),
|
||||
|
@ -1300,9 +1301,9 @@ impl<T> TestOutput<T> {
|
|||
#[allow(clippy::unwrap_in_result)]
|
||||
pub fn stderr_matches<R>(&self, regex: R) -> Result<&Self>
|
||||
where
|
||||
R: ToRegex + Debug,
|
||||
R: ToRegexSet + Debug,
|
||||
{
|
||||
let re = regex.to_regex().expect("regex must be valid");
|
||||
let re = regex.to_regex_set().expect("regex must be valid");
|
||||
|
||||
self.output_check(
|
||||
|stderr| re.is_match(stderr),
|
||||
|
@ -1324,9 +1325,9 @@ impl<T> TestOutput<T> {
|
|||
#[allow(clippy::unwrap_in_result)]
|
||||
pub fn stderr_line_matches<R>(&self, regex: R) -> Result<&Self>
|
||||
where
|
||||
R: ToRegex + Debug,
|
||||
R: ToRegexSet + Debug,
|
||||
{
|
||||
let re = regex.to_regex().expect("regex must be valid");
|
||||
let re = regex.to_regex_set().expect("regex must be valid");
|
||||
|
||||
self.any_output_line(
|
||||
|line| re.is_match(line),
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use std::iter;
|
||||
|
||||
use itertools::Itertools;
|
||||
use regex::{Error, Regex, RegexBuilder, RegexSet, RegexSetBuilder};
|
||||
|
||||
/// A trait for converting a value to a [`Regex`].
|
||||
|
@ -135,15 +136,17 @@ pub trait CollectRegexSet {
|
|||
impl<I> CollectRegexSet for I
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: ToRegex,
|
||||
I::Item: ToRegexSet,
|
||||
{
|
||||
fn collect_regex_set(self) -> Result<RegexSet, Error> {
|
||||
let regexes: Result<Vec<Regex>, Error> =
|
||||
self.into_iter().map(|item| item.to_regex()).collect();
|
||||
let regexes: Result<Vec<RegexSet>, Error> = self
|
||||
.into_iter()
|
||||
.map(|item| item.to_regex_set())
|
||||
.try_collect();
|
||||
let regexes = regexes?;
|
||||
|
||||
// This conversion discards flags and limits from Regex and RegexBuilder.
|
||||
let regexes = regexes.iter().map(|regex| regex.as_str());
|
||||
let regexes = regexes.iter().flat_map(|regex_set| regex_set.patterns());
|
||||
|
||||
RegexSet::new(regexes)
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ features = [
|
|||
|
||||
[features]
|
||||
# In release builds, don't compile debug logging code, to improve performance.
|
||||
default = ["release_max_level_info"]
|
||||
default = ["release_max_level_info", "progress-bar"]
|
||||
|
||||
# Default features for official ZF binary release builds
|
||||
default-release-binaries = ["default", "sentry"]
|
||||
|
|
|
@ -434,6 +434,7 @@ impl Application for ZebradApp {
|
|||
// Override the default tracing filter based on the command-line verbosity.
|
||||
tracing_config.filter = tracing_config
|
||||
.filter
|
||||
.clone()
|
||||
.or_else(|| Some(default_filter.to_owned()));
|
||||
} else {
|
||||
// Don't apply the configured filter for short-lived commands.
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
//! Tracing and logging infrastructure for Zebra.
|
||||
|
||||
use std::{net::SocketAddr, path::PathBuf};
|
||||
use std::{
|
||||
net::SocketAddr,
|
||||
ops::{Deref, DerefMut},
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
@ -16,10 +20,59 @@ pub use endpoint::TracingEndpoint;
|
|||
#[cfg(feature = "flamegraph")]
|
||||
pub use flame::{layer, Grapher};
|
||||
|
||||
/// Tracing configuration section.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(deny_unknown_fields, default)]
|
||||
/// Tracing configuration section: outer config after cross-field defaults are applied.
|
||||
///
|
||||
/// This is a wrapper type that dereferences to the inner config type.
|
||||
///
|
||||
//
|
||||
// TODO: replace with serde's finalizer attribute when that feature is implemented.
|
||||
// we currently use the recommended workaround of a wrapper struct with from/into attributes.
|
||||
// https://github.com/serde-rs/serde/issues/642#issuecomment-525432907
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(
|
||||
deny_unknown_fields,
|
||||
default,
|
||||
from = "InnerConfig",
|
||||
into = "InnerConfig"
|
||||
)]
|
||||
pub struct Config {
|
||||
inner: InnerConfig,
|
||||
}
|
||||
|
||||
impl Deref for Config {
|
||||
type Target = InnerConfig;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Config {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InnerConfig> for Config {
|
||||
fn from(mut inner: InnerConfig) -> Self {
|
||||
inner.log_file = runtime_default_log_file(inner.log_file, inner.progress_bar);
|
||||
|
||||
Self { inner }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Config> for InnerConfig {
|
||||
fn from(mut config: Config) -> Self {
|
||||
config.log_file = disk_default_log_file(config.log_file.clone(), config.progress_bar);
|
||||
|
||||
config.inner
|
||||
}
|
||||
}
|
||||
|
||||
/// Tracing configuration section: inner config used to deserialize and apply cross-field defaults.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(deny_unknown_fields, default)]
|
||||
pub struct InnerConfig {
|
||||
/// Whether to use colored terminal output, if available.
|
||||
///
|
||||
/// Colored terminal output is automatically disabled if an output stream
|
||||
|
@ -108,10 +161,16 @@ pub struct Config {
|
|||
/// replaced with `.folded` and `.svg` for the respective files.
|
||||
pub flamegraph: Option<PathBuf>,
|
||||
|
||||
/// Shows progress bars for block syncing, and mempool transactions, and peer networking.
|
||||
/// Also sends logs to the default log file path.
|
||||
///
|
||||
/// This config field is ignored unless the `progress-bar` feature is enabled.
|
||||
pub progress_bar: Option<ProgressConfig>,
|
||||
|
||||
/// If set to a path, write the tracing logs to that path.
|
||||
///
|
||||
/// By default, logs are sent to the terminal standard output.
|
||||
/// But if the `progress-bar` feature is activated, logs are sent to the standard log file path:
|
||||
/// But if the `progress_bar` config is activated, logs are sent to the standard log file path:
|
||||
/// - Linux: `$XDG_STATE_HOME/zebrad.log` or `$HOME/.local/state/zebrad.log`
|
||||
/// - macOS: `$HOME/Library/Application Support/zebrad.log`
|
||||
/// - Windows: `%LOCALAPPDATA%\zebrad.log` or `C:\Users\%USERNAME%\AppData\Local\zebrad.log`
|
||||
|
@ -131,6 +190,21 @@ pub struct Config {
|
|||
pub use_journald: bool,
|
||||
}
|
||||
|
||||
/// The progress bars that Zebra will show while running.
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum ProgressConfig {
|
||||
/// Show a lot of progress bars.
|
||||
Detailed,
|
||||
|
||||
/// Show a few important progress bars.
|
||||
//
|
||||
// TODO: actually hide some progress bars in this mode.
|
||||
#[default]
|
||||
#[serde(other)]
|
||||
Summary,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// Returns `true` if standard output should use color escapes.
|
||||
/// Automatically checks if Zebra is running in a terminal.
|
||||
|
@ -152,12 +226,10 @@ impl Config {
|
|||
}
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
impl Default for InnerConfig {
|
||||
fn default() -> Self {
|
||||
#[cfg(feature = "progress-bar")]
|
||||
let default_log_file = dirs::state_dir()
|
||||
.or_else(dirs::data_local_dir)
|
||||
.map(|dir| dir.join("zebrad.log"));
|
||||
// TODO: enable progress bars by default once they have been tested
|
||||
let progress_bar = None;
|
||||
|
||||
Self {
|
||||
use_color: true,
|
||||
|
@ -166,11 +238,50 @@ impl Default for Config {
|
|||
buffer_limit: 128_000,
|
||||
endpoint_addr: None,
|
||||
flamegraph: None,
|
||||
#[cfg(not(feature = "progress-bar"))]
|
||||
log_file: None,
|
||||
#[cfg(feature = "progress-bar")]
|
||||
log_file: default_log_file,
|
||||
progress_bar,
|
||||
log_file: runtime_default_log_file(None, progress_bar),
|
||||
use_journald: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the runtime default log file path based on the `log_file` and `progress_bar` configs.
|
||||
fn runtime_default_log_file(
|
||||
log_file: Option<PathBuf>,
|
||||
progress_bar: Option<ProgressConfig>,
|
||||
) -> Option<PathBuf> {
|
||||
if let Some(log_file) = log_file {
|
||||
return Some(log_file);
|
||||
}
|
||||
|
||||
// If the progress bar is active, we want to use a log file regardless of the config.
|
||||
// (Logging to a terminal erases parts of the progress bars, making both unreadable.)
|
||||
if progress_bar.is_some() {
|
||||
return default_log_file();
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Returns the configured log file path using the runtime `log_file` and `progress_bar` config.
|
||||
///
|
||||
/// This is the inverse of [`runtime_default_log_file()`].
|
||||
fn disk_default_log_file(
|
||||
log_file: Option<PathBuf>,
|
||||
progress_bar: Option<ProgressConfig>,
|
||||
) -> Option<PathBuf> {
|
||||
// If the progress bar is active, and we've likely substituted the default log file path,
|
||||
// don't write that substitute to the config on disk.
|
||||
if progress_bar.is_some() && log_file == default_log_file() {
|
||||
return None;
|
||||
}
|
||||
|
||||
log_file
|
||||
}
|
||||
|
||||
/// Returns the default log file path.
|
||||
fn default_log_file() -> Option<PathBuf> {
|
||||
dirs::state_dir()
|
||||
.or_else(dirs::data_local_dir)
|
||||
.map(|dir| dir.join("zebrad.log"))
|
||||
}
|
||||
|
|
|
@ -79,14 +79,14 @@ impl Tracing {
|
|||
/// and the Zebra logo on startup. (If the terminal supports it.)
|
||||
//
|
||||
// This method should only print to stderr, because stdout is for tracing logs.
|
||||
#[allow(clippy::print_stderr, clippy::unwrap_in_result)]
|
||||
#[allow(clippy::print_stdout, clippy::print_stderr, clippy::unwrap_in_result)]
|
||||
pub fn new(network: Network, config: Config, uses_intro: bool) -> Result<Self, FrameworkError> {
|
||||
// Only use color if tracing output is being sent to a terminal or if it was explicitly
|
||||
// forced to.
|
||||
let use_color = config.use_color_stdout();
|
||||
let use_color_stderr = config.use_color_stderr();
|
||||
|
||||
let filter = config.filter.unwrap_or_default();
|
||||
let filter = config.filter.clone().unwrap_or_default();
|
||||
let flame_root = &config.flamegraph;
|
||||
|
||||
// Only show the intro for user-focused node server commands like `start`
|
||||
|
@ -139,7 +139,8 @@ impl Tracing {
|
|||
}
|
||||
|
||||
if uses_intro {
|
||||
eprintln!("Sending logs to {log_file:?}...");
|
||||
// We want this to appear on stdout instead of the usual log messages.
|
||||
println!("Sending logs to {log_file:?}...");
|
||||
}
|
||||
let log_file = File::options().append(true).create(true).open(log_file)?;
|
||||
Box::new(log_file) as BoxWrite
|
||||
|
@ -305,7 +306,7 @@ impl Tracing {
|
|||
//
|
||||
// TODO: move this to its own module?
|
||||
#[cfg(feature = "progress-bar")]
|
||||
{
|
||||
if let Some(progress_bar_config) = config.progress_bar.as_ref() {
|
||||
use howudoin::consumers::TermLine;
|
||||
use std::time::Duration;
|
||||
|
||||
|
@ -315,7 +316,11 @@ impl Tracing {
|
|||
let terminal_consumer = TermLine::with_debounce(PROGRESS_BAR_DEBOUNCE);
|
||||
howudoin::init(terminal_consumer);
|
||||
|
||||
info!("activated progress bar");
|
||||
info!(?progress_bar_config, "activated progress bars");
|
||||
} else {
|
||||
info!(
|
||||
"set 'tracing.progress_bar =\"summary\"' in zebrad.toml to activate progress bars"
|
||||
);
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
|
|
|
@ -61,9 +61,10 @@
|
|||
//!
|
||||
//! ### Metrics
|
||||
//!
|
||||
//! * `prometheus`: export metrics to prometheus.
|
||||
//! * `progress-bar`: shows key metrics in the terminal using progress bars,
|
||||
//! * configuring a `tracing.progress_bar`: shows key metrics in the terminal using progress bars,
|
||||
//! and automatically configures Zebra to send logs to a file.
|
||||
//! (The `progress-bar` feature is activated by default.)
|
||||
//! * `prometheus`: export metrics to prometheus.
|
||||
//!
|
||||
//! Read the [metrics](https://zebra.zfnd.org/user/metrics.html) section of the book
|
||||
//! for more details.
|
||||
|
|
|
@ -161,7 +161,12 @@ use zebra_network::constants::PORT_IN_USE_ERROR;
|
|||
use zebra_node_services::rpc_client::RpcRequestClient;
|
||||
use zebra_state::{constants::LOCK_FILE_ERROR, database_format_version_in_code};
|
||||
|
||||
use zebra_test::{args, command::ContextFrom, net::random_known_port, prelude::*};
|
||||
use zebra_test::{
|
||||
args,
|
||||
command::{to_regex::CollectRegexSet, ContextFrom},
|
||||
net::random_known_port,
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
mod common;
|
||||
|
||||
|
@ -605,7 +610,7 @@ fn config_tests() -> Result<()> {
|
|||
// Check that Zebra's previous configurations still work
|
||||
stored_configs_work()?;
|
||||
|
||||
// Runs `zebrad` serially to avoid potential port conflicts
|
||||
// We run the `zebrad` app test after the config tests, to avoid potential port conflicts
|
||||
app_no_args()?;
|
||||
|
||||
Ok(())
|
||||
|
@ -619,6 +624,8 @@ fn app_no_args() -> Result<()> {
|
|||
// start caches state, so run one of the start tests with persistent state
|
||||
let testdir = testdir()?.with_config(&mut persistent_test_config()?)?;
|
||||
|
||||
tracing::info!(?testdir, "running zebrad with no config (default settings)");
|
||||
|
||||
let mut child = testdir.spawn_child(args![])?;
|
||||
|
||||
// Run the program and kill it after a few seconds
|
||||
|
@ -651,6 +658,8 @@ fn valid_generated_config(command: &str, expect_stdout_line_contains: &str) -> R
|
|||
// Add a config file name to tempdir path
|
||||
let generated_config_path = testdir.path().join("zebrad.toml");
|
||||
|
||||
tracing::info!(?generated_config_path, "generating valid config");
|
||||
|
||||
// Generate configuration in temp dir path
|
||||
let child =
|
||||
testdir.spawn_child(args!["generate", "-o": generated_config_path.to_str().unwrap()])?;
|
||||
|
@ -664,6 +673,8 @@ fn valid_generated_config(command: &str, expect_stdout_line_contains: &str) -> R
|
|||
"generated config file not found"
|
||||
);
|
||||
|
||||
tracing::info!(?generated_config_path, "testing valid config parsing");
|
||||
|
||||
// Run command using temp dir and kill it after a few seconds
|
||||
let mut child = testdir.spawn_child(args![command])?;
|
||||
std::thread::sleep(LAUNCH_DELAY);
|
||||
|
@ -702,6 +713,8 @@ fn last_config_is_stored() -> Result<()> {
|
|||
// Add a config file name to tempdir path
|
||||
let generated_config_path = testdir.path().join("zebrad.toml");
|
||||
|
||||
tracing::info!(?generated_config_path, "generated current config");
|
||||
|
||||
// Generate configuration in temp dir path
|
||||
let child =
|
||||
testdir.spawn_child(args!["generate", "-o": generated_config_path.to_str().unwrap()])?;
|
||||
|
@ -715,6 +728,11 @@ fn last_config_is_stored() -> Result<()> {
|
|||
"generated config file not found"
|
||||
);
|
||||
|
||||
tracing::info!(
|
||||
?generated_config_path,
|
||||
"testing current config is in stored configs"
|
||||
);
|
||||
|
||||
// Get the contents of the generated config file
|
||||
let generated_content =
|
||||
fs::read_to_string(generated_config_path).expect("Should have been able to read the file");
|
||||
|
@ -815,6 +833,11 @@ fn invalid_generated_config() -> Result<()> {
|
|||
// Add a config file name to tempdir path.
|
||||
let config_path = testdir.path().join("zebrad.toml");
|
||||
|
||||
tracing::info!(
|
||||
?config_path,
|
||||
"testing invalid config parsing: generating valid config"
|
||||
);
|
||||
|
||||
// Generate a valid config file in the temp dir.
|
||||
let child = testdir.spawn_child(args!["generate", "-o": config_path.to_str().unwrap()])?;
|
||||
|
||||
|
@ -849,10 +872,14 @@ fn invalid_generated_config() -> Result<()> {
|
|||
secs = 3600
|
||||
";
|
||||
|
||||
tracing::info!(?config_path, "writing invalid config");
|
||||
|
||||
// Write the altered config file so that Zebra can pick it up.
|
||||
fs::write(config_path.to_str().unwrap(), config_file.as_bytes())
|
||||
.expect("Could not write the altered config file.");
|
||||
|
||||
tracing::info!(?config_path, "testing invalid config parsing");
|
||||
|
||||
// Run Zebra in a temp dir so that it loads the config.
|
||||
let mut child = testdir.spawn_child(args!["start"])?;
|
||||
|
||||
|
@ -883,6 +910,8 @@ fn invalid_generated_config() -> Result<()> {
|
|||
fn stored_configs_work() -> Result<()> {
|
||||
let old_configs_dir = configs_dir();
|
||||
|
||||
tracing::info!(?old_configs_dir, "testing older config parsing");
|
||||
|
||||
for config_file in old_configs_dir
|
||||
.read_dir()
|
||||
.expect("read_dir call failed")
|
||||
|
@ -892,10 +921,10 @@ fn stored_configs_work() -> Result<()> {
|
|||
let config_file_name = config_file_path
|
||||
.file_name()
|
||||
.expect("config files must have a file name")
|
||||
.to_string_lossy();
|
||||
.to_str()
|
||||
.expect("config file names are valid unicode");
|
||||
|
||||
if config_file_name.as_ref().starts_with('.') || config_file_name.as_ref().starts_with('#')
|
||||
{
|
||||
if config_file_name.starts_with('.') || config_file_name.starts_with('#') {
|
||||
// Skip editor files and other invalid config paths
|
||||
tracing::info!(
|
||||
?config_file_path,
|
||||
|
@ -907,10 +936,7 @@ fn stored_configs_work() -> Result<()> {
|
|||
// ignore files starting with getblocktemplate prefix
|
||||
// if we were not built with the getblocktemplate-rpcs feature.
|
||||
#[cfg(not(feature = "getblocktemplate-rpcs"))]
|
||||
if config_file_name
|
||||
.as_ref()
|
||||
.starts_with(GET_BLOCK_TEMPLATE_CONFIG_PREFIX)
|
||||
{
|
||||
if config_file_name.starts_with(GET_BLOCK_TEMPLATE_CONFIG_PREFIX) {
|
||||
tracing::info!(
|
||||
?config_file_path,
|
||||
"skipping getblocktemplate-rpcs config file path"
|
||||
|
@ -921,12 +947,41 @@ fn stored_configs_work() -> Result<()> {
|
|||
let run_dir = testdir()?;
|
||||
let stored_config_path = config_file_full_path(config_file.path());
|
||||
|
||||
tracing::info!(
|
||||
?stored_config_path,
|
||||
"testing old config can be parsed by current zebrad"
|
||||
);
|
||||
|
||||
// run zebra with stored config
|
||||
let mut child =
|
||||
run_dir.spawn_child(args!["-c", stored_config_path.to_str().unwrap(), "start"])?;
|
||||
|
||||
// zebra was able to start with the stored config
|
||||
child.expect_stdout_line_matches("Starting zebrad".to_string())?;
|
||||
let success_regexes = [
|
||||
// When logs are sent to the terminal, we see the config loading message and path.
|
||||
format!(
|
||||
"loaded zebrad config.*config_path.*=.*{}",
|
||||
regex::escape(config_file_name)
|
||||
),
|
||||
// If they are sent to a file, we see a log file message on stdout,
|
||||
// and a logo, welcome message, and progress bar on stderr.
|
||||
"Sending logs to".to_string(),
|
||||
// TODO: add expect_stdout_or_stderr_line_matches() and check for this instead:
|
||||
//"Thank you for running a mainnet zebrad".to_string(),
|
||||
];
|
||||
|
||||
tracing::info!(
|
||||
?stored_config_path,
|
||||
?success_regexes,
|
||||
"waiting for zebrad to parse config and start logging"
|
||||
);
|
||||
|
||||
let success_regexes = success_regexes
|
||||
.iter()
|
||||
.collect_regex_set()
|
||||
.expect("regexes are valid");
|
||||
|
||||
// Zebra was able to start with the stored config.
|
||||
child.expect_stdout_line_matches(success_regexes)?;
|
||||
|
||||
// finish
|
||||
child.kill(false)?;
|
||||
|
|
|
@ -58,10 +58,9 @@ pub fn default_test_config() -> Result<ZebradConfig> {
|
|||
env::var("ZEBRA_FORCE_USE_COLOR"),
|
||||
Err(env::VarError::NotPresent)
|
||||
);
|
||||
let tracing = tracing::Config {
|
||||
force_use_color,
|
||||
..tracing::Config::default()
|
||||
};
|
||||
|
||||
let mut tracing = tracing::Config::default();
|
||||
tracing.force_use_color = force_use_color;
|
||||
|
||||
let mut state = zebra_state::Config::ephemeral();
|
||||
state.debug_validity_check_interval = Some(DATABASE_FORMAT_CHECK_INTERVAL);
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
# Default configuration for zebrad.
|
||||
#
|
||||
# This file can be used as a skeleton for custom configs.
|
||||
#
|
||||
# Unspecified fields use default values. Optional fields are Some(field) if the
|
||||
# field is present and None if it is absent.
|
||||
#
|
||||
# This file is generated as an example using zebrad's current defaults.
|
||||
# You should set only the config options you want to keep, and delete the rest.
|
||||
# Only a subset of fields are present in the skeleton, since optional values
|
||||
# whose default is None are omitted.
|
||||
#
|
||||
# The config format (including a complete list of sections and fields) is
|
||||
# documented here:
|
||||
# https://doc.zebra.zfnd.org/zebrad/config/struct.ZebradConfig.html
|
||||
#
|
||||
# zebrad attempts to load configs in the following order:
|
||||
#
|
||||
# 1. The -c flag on the command line, e.g., `zebrad -c myconfig.toml start`;
|
||||
# 2. The file `zebrad.toml` in the users's preference directory (platform-dependent);
|
||||
# 3. The default config.
|
||||
|
||||
[consensus]
|
||||
checkpoint_sync = true
|
||||
debug_skip_parameter_preload = false
|
||||
|
||||
[mempool]
|
||||
eviction_memory_time = "1h"
|
||||
tx_cost_limit = 80000000
|
||||
|
||||
[metrics]
|
||||
|
||||
[network]
|
||||
cache_dir = true
|
||||
crawl_new_peer_interval = "1m 1s"
|
||||
initial_mainnet_peers = [
|
||||
"dnsseed.z.cash:8233",
|
||||
"dnsseed.str4d.xyz:8233",
|
||||
"mainnet.seeder.zfnd.org:8233",
|
||||
"mainnet.is.yolo.money:8233",
|
||||
]
|
||||
initial_testnet_peers = [
|
||||
"dnsseed.testnet.z.cash:18233",
|
||||
"testnet.seeder.zfnd.org:18233",
|
||||
"testnet.is.yolo.money:18233",
|
||||
]
|
||||
listen_addr = "0.0.0.0:8233"
|
||||
max_connections_per_ip = 1
|
||||
network = "Mainnet"
|
||||
peerset_initial_target_size = 25
|
||||
|
||||
[rpc]
|
||||
debug_force_finished_sync = false
|
||||
parallel_cpu_threads = 1
|
||||
|
||||
[state]
|
||||
cache_dir = "cache_dir"
|
||||
delete_old_database = true
|
||||
ephemeral = false
|
||||
|
||||
[sync]
|
||||
checkpoint_verify_concurrency_limit = 1000
|
||||
download_concurrency_limit = 50
|
||||
full_verify_concurrency_limit = 20
|
||||
parallel_cpu_threads = 0
|
||||
|
||||
[tracing]
|
||||
buffer_limit = 128000
|
||||
force_use_color = false
|
||||
progress_bar = "summary"
|
||||
use_color = true
|
||||
use_journald = false
|
||||
|
Loading…
Reference in New Issue