mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feature: loglevel value parser (#8573)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -7869,7 +7869,6 @@ dependencies = [
|
|||||||
name = "reth-storage-errors"
|
name = "reth-storage-errors"
|
||||||
version = "0.2.0-beta.8"
|
version = "0.2.0-beta.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
|
||||||
"reth-fs-util",
|
"reth-fs-util",
|
||||||
"reth-primitives",
|
"reth-primitives",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
|||||||
@ -16,7 +16,7 @@ reth-primitives.workspace = true
|
|||||||
reth-fs-util.workspace = true
|
reth-fs-util.workspace = true
|
||||||
reth-db = { workspace = true, features = ["mdbx"] }
|
reth-db = { workspace = true, features = ["mdbx"] }
|
||||||
reth-db-api.workspace = true
|
reth-db-api.workspace = true
|
||||||
reth-storage-errors = { workspace = true, features = ["clap"] }
|
reth-storage-errors.workspace = true
|
||||||
reth-provider.workspace = true
|
reth-provider.workspace = true
|
||||||
reth-network = { workspace = true, features = ["serde"] }
|
reth-network = { workspace = true, features = ["serde"] }
|
||||||
reth-network-p2p.workspace = true
|
reth-network-p2p.workspace = true
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
//! clap [Args](clap::Args) for database configuration
|
//! clap [Args](clap::Args) for database configuration
|
||||||
|
|
||||||
use crate::version::default_client_version;
|
use crate::version::default_client_version;
|
||||||
use clap::Args;
|
use clap::{
|
||||||
|
builder::{PossibleValue, TypedValueParser},
|
||||||
|
error::ErrorKind,
|
||||||
|
Arg, Args, Command, Error,
|
||||||
|
};
|
||||||
use reth_storage_errors::db::LogLevel;
|
use reth_storage_errors::db::LogLevel;
|
||||||
|
|
||||||
/// Parameters for database configuration
|
/// Parameters for database configuration
|
||||||
@ -9,7 +13,7 @@ use reth_storage_errors::db::LogLevel;
|
|||||||
#[command(next_help_heading = "Database")]
|
#[command(next_help_heading = "Database")]
|
||||||
pub struct DatabaseArgs {
|
pub struct DatabaseArgs {
|
||||||
/// Database logging level. Levels higher than "notice" require a debug build.
|
/// Database logging level. Levels higher than "notice" require a debug build.
|
||||||
#[arg(long = "db.log-level", value_enum)]
|
#[arg(long = "db.log-level", value_parser = LogLevelValueParser::default())]
|
||||||
pub log_level: Option<LogLevel>,
|
pub log_level: Option<LogLevel>,
|
||||||
/// Open environment in exclusive/monopolistic mode. Makes it possible to open a database on an
|
/// Open environment in exclusive/monopolistic mode. Makes it possible to open a database on an
|
||||||
/// NFS volume.
|
/// NFS volume.
|
||||||
@ -26,6 +30,44 @@ impl DatabaseArgs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// clap value parser for [`LogLevel`].
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
struct LogLevelValueParser;
|
||||||
|
|
||||||
|
impl TypedValueParser for LogLevelValueParser {
|
||||||
|
type Value = LogLevel;
|
||||||
|
|
||||||
|
fn parse_ref(
|
||||||
|
&self,
|
||||||
|
_cmd: &Command,
|
||||||
|
arg: Option<&Arg>,
|
||||||
|
value: &std::ffi::OsStr,
|
||||||
|
) -> Result<Self::Value, Error> {
|
||||||
|
let val =
|
||||||
|
value.to_str().ok_or_else(|| Error::raw(ErrorKind::InvalidUtf8, "Invalid UTF-8"))?;
|
||||||
|
|
||||||
|
val.parse::<LogLevel>().map_err(|err| {
|
||||||
|
let arg = arg.map(|a| a.to_string()).unwrap_or_else(|| "...".to_owned());
|
||||||
|
let possible_values = LogLevel::value_variants()
|
||||||
|
.iter()
|
||||||
|
.map(|v| format!("- {:?}: {}", v, v.help_message()))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n");
|
||||||
|
let msg = format!(
|
||||||
|
"Invalid value '{val}' for {arg}: {err}.\n Possible values:\n{possible_values}"
|
||||||
|
);
|
||||||
|
clap::Error::raw(clap::error::ErrorKind::InvalidValue, msg)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn possible_values(&self) -> Option<Box<dyn Iterator<Item = PossibleValue> + '_>> {
|
||||||
|
let values = LogLevel::value_variants()
|
||||||
|
.iter()
|
||||||
|
.map(|v| PossibleValue::new(v.variant_name()).help(v.help_message()));
|
||||||
|
Some(Box::new(values))
|
||||||
|
}
|
||||||
|
}
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -39,9 +81,60 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_database_args() {
|
fn test_default_database_args() {
|
||||||
let default_args = DatabaseArgs::default();
|
let default_args = DatabaseArgs::default();
|
||||||
let args = CommandParser::<DatabaseArgs>::parse_from(["reth"]).args;
|
let args = CommandParser::<DatabaseArgs>::parse_from(["reth"]).args;
|
||||||
assert_eq!(args, default_args);
|
assert_eq!(args, default_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_possible_values() {
|
||||||
|
// Initialize the LogLevelValueParser
|
||||||
|
let parser = LogLevelValueParser;
|
||||||
|
|
||||||
|
// Call the possible_values method
|
||||||
|
let possible_values: Vec<PossibleValue> = parser.possible_values().unwrap().collect();
|
||||||
|
|
||||||
|
// Expected possible values
|
||||||
|
let expected_values = vec![
|
||||||
|
PossibleValue::new("fatal")
|
||||||
|
.help("Enables logging for critical conditions, i.e. assertion failures"),
|
||||||
|
PossibleValue::new("error").help("Enables logging for error conditions"),
|
||||||
|
PossibleValue::new("warn").help("Enables logging for warning conditions"),
|
||||||
|
PossibleValue::new("notice")
|
||||||
|
.help("Enables logging for normal but significant condition"),
|
||||||
|
PossibleValue::new("verbose").help("Enables logging for verbose informational"),
|
||||||
|
PossibleValue::new("debug").help("Enables logging for debug-level messages"),
|
||||||
|
PossibleValue::new("trace").help("Enables logging for trace debug-level messages"),
|
||||||
|
PossibleValue::new("extra").help("Enables logging for extra debug-level messages"),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Check that the possible values match the expected values
|
||||||
|
assert_eq!(possible_values.len(), expected_values.len());
|
||||||
|
for (actual, expected) in possible_values.iter().zip(expected_values.iter()) {
|
||||||
|
assert_eq!(actual.get_name(), expected.get_name());
|
||||||
|
assert_eq!(actual.get_help(), expected.get_help());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_command_parser_with_valid_log_level() {
|
||||||
|
let cmd =
|
||||||
|
CommandParser::<DatabaseArgs>::try_parse_from(["reth", "--db.log-level", "Debug"])
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(cmd.args.log_level, Some(LogLevel::Debug));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_command_parser_with_invalid_log_level() {
|
||||||
|
let result =
|
||||||
|
CommandParser::<DatabaseArgs>::try_parse_from(["reth", "--db.log-level", "invalid"]);
|
||||||
|
assert!(result.is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_command_parser_without_log_level() {
|
||||||
|
let cmd = CommandParser::<DatabaseArgs>::try_parse_from(["reth"]).unwrap();
|
||||||
|
assert_eq!(cmd.args.log_level, None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,7 +15,5 @@ reth-primitives.workspace = true
|
|||||||
reth-fs-util.workspace = true
|
reth-fs-util.workspace = true
|
||||||
|
|
||||||
thiserror.workspace = true
|
thiserror.workspace = true
|
||||||
clap = { workspace = true, features = ["derive"], optional = true }
|
|
||||||
|
|
||||||
[features]
|
|
||||||
clap = ["dep:clap"]
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use std::fmt::Display;
|
use std::{fmt::Display, str::FromStr};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
/// Database error type.
|
/// Database error type.
|
||||||
@ -103,7 +103,6 @@ pub enum DatabaseWriteOperation {
|
|||||||
|
|
||||||
/// Database log level.
|
/// Database log level.
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
|
|
||||||
pub enum LogLevel {
|
pub enum LogLevel {
|
||||||
/// Enables logging for critical conditions, i.e. assertion failures.
|
/// Enables logging for critical conditions, i.e. assertion failures.
|
||||||
Fatal,
|
Fatal,
|
||||||
@ -122,3 +121,65 @@ pub enum LogLevel {
|
|||||||
/// Enables logging for extra debug-level messages.
|
/// Enables logging for extra debug-level messages.
|
||||||
Extra,
|
Extra,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl LogLevel {
|
||||||
|
/// All possible variants of the `LogLevel` enum
|
||||||
|
pub const fn value_variants() -> &'static [Self] {
|
||||||
|
&[
|
||||||
|
Self::Fatal,
|
||||||
|
Self::Error,
|
||||||
|
Self::Warn,
|
||||||
|
Self::Notice,
|
||||||
|
Self::Verbose,
|
||||||
|
Self::Debug,
|
||||||
|
Self::Trace,
|
||||||
|
Self::Extra,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Static str reference to `LogLevel` enum, required for `Clap::Builder::PossibleValue::new()`
|
||||||
|
pub const fn variant_name(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Fatal => "fatal",
|
||||||
|
Self::Error => "error",
|
||||||
|
Self::Warn => "warn",
|
||||||
|
Self::Notice => "notice",
|
||||||
|
Self::Verbose => "verbose",
|
||||||
|
Self::Debug => "debug",
|
||||||
|
Self::Trace => "trace",
|
||||||
|
Self::Extra => "extra",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns all variants descriptions
|
||||||
|
pub const fn help_message(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Fatal => "Enables logging for critical conditions, i.e. assertion failures",
|
||||||
|
Self::Error => "Enables logging for error conditions",
|
||||||
|
Self::Warn => "Enables logging for warning conditions",
|
||||||
|
Self::Notice => "Enables logging for normal but significant condition",
|
||||||
|
Self::Verbose => "Enables logging for verbose informational",
|
||||||
|
Self::Debug => "Enables logging for debug-level messages",
|
||||||
|
Self::Trace => "Enables logging for trace debug-level messages",
|
||||||
|
Self::Extra => "Enables logging for extra debug-level messages",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for LogLevel {
|
||||||
|
type Err = String;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s.to_lowercase().as_str() {
|
||||||
|
"fatal" => Ok(Self::Fatal),
|
||||||
|
"error" => Ok(Self::Error),
|
||||||
|
"warn" => Ok(Self::Warn),
|
||||||
|
"notice" => Ok(Self::Notice),
|
||||||
|
"verbose" => Ok(Self::Verbose),
|
||||||
|
"debug" => Ok(Self::Debug),
|
||||||
|
"trace" => Ok(Self::Trace),
|
||||||
|
"extra" => Ok(Self::Extra),
|
||||||
|
_ => Err(format!("Invalid log level: {}", s)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user