diff --git a/Cargo.lock b/Cargo.lock index c72989e8..a4d75316 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -252,12 +252,55 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" +[[package]] +name = "anstream" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is-terminal", + "utf8parse", +] + [[package]] name = "anstyle" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" +[[package]] +name = "anstyle-parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "anstyle-wincon" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" +dependencies = [ + "anstyle", + "windows-sys 0.48.0", +] + [[package]] name = "anyhow" version = "1.0.72" @@ -290,17 +333,6 @@ dependencies = [ "critical-section", ] -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -548,21 +580,6 @@ dependencies = [ "libloading", ] -[[package]] -name = "clap" -version = "3.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" -dependencies = [ - "atty", - "bitflags 1.3.2", - "clap_lex 0.2.4", - "indexmap 1.9.3", - "strsim", - "termcolor", - "textwrap", -] - [[package]] name = "clap" version = "4.3.19" @@ -578,17 +595,10 @@ version = "4.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01c6a3f08f1fe5662a35cfe393aec09c4df95f60ee93b7556505260f75eee9e1" dependencies = [ + "anstream", "anstyle", - "clap_lex 0.5.0", -] - -[[package]] -name = "clap_lex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", + "clap_lex", + "strsim", ] [[package]] @@ -603,6 +613,12 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + [[package]] name = "combine" version = "4.6.6" @@ -617,6 +633,26 @@ dependencies = [ "tokio-util", ] +[[package]] +name = "const_format" +version = "0.2.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c990efc7a285731f9a4378d81aff2f0e85a2c8781a05ef0f8baa8dac54d0ff48" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e026b6ce194a874cb9cf32cd5772d1ef9767cc8fcb5765948d74f37a9d8b2bf6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "convert_case" version = "0.4.0" @@ -677,7 +713,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.3.19", + "clap", "criterion-plot", "is-terminal", "itertools", @@ -1115,15 +1151,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.3.2" @@ -1296,7 +1323,7 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ - "hermit-abi 0.3.2", + "hermit-abi", "rustix", "windows-sys 0.48.0", ] @@ -1450,7 +1477,8 @@ version = "1.3.0-dev" dependencies = [ "actix-rt", "actix-web", - "clap 3.2.25", + "clap", + "const_format", "env_logger", "limitador", "log", @@ -1654,7 +1682,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.2", + "hermit-abi", "libc", ] @@ -1723,12 +1751,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "os_str_bytes" -version = "6.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" - [[package]] name = "paperclip" version = "0.8.0" @@ -2386,18 +2408,18 @@ checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" [[package]] name = "serde" -version = "1.0.177" +version = "1.0.179" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63ba2516aa6bf82e0b19ca8b50019d52df58455d3cf9bdaf6315225fdd0c560a" +checksum = "0a5bf42b8d227d4abf38a1ddb08602e229108a517cd4e5bb28f9c7eaafdce5c0" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.177" +version = "1.0.179" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "401797fe7833d72109fedec6bfcbe67c0eed9b99772f26eb8afd261f0abc6fd3" +checksum = "741e124f5485c7e60c03b043f79f320bff3527f4bbf12cf3831750dc46a0ec2c" dependencies = [ "proc-macro2", "quote", @@ -2612,12 +2634,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "textwrap" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" - [[package]] name = "thiserror" version = "1.0.44" @@ -2934,6 +2950,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + [[package]] name = "unsafe-libyaml" version = "0.2.9" @@ -2957,6 +2979,12 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "vcpkg" version = "0.2.15" diff --git a/limitador-server/Cargo.toml b/limitador-server/Cargo.toml index 88bebd03..f37b44bb 100644 --- a/limitador-server/Cargo.toml +++ b/limitador-server/Cargo.toml @@ -33,7 +33,8 @@ actix-rt = "2" paperclip = { version = "0.8.0", features = ["actix4"] } serde = { version = "1", features = ["derive"] } notify = "6.0.1" -clap = "3.2" +const_format = "0.2.31" +clap = "4.3" [build-dependencies] tonic-build = "0.9.2" diff --git a/limitador-server/build.rs b/limitador-server/build.rs index 98a8d23a..0a816902 100644 --- a/limitador-server/build.rs +++ b/limitador-server/build.rs @@ -21,9 +21,11 @@ fn generate_protobuf() -> Result<(), Box> { } fn set_features(env: &str) { + let mut features = vec![]; if cfg!(feature = "infinispan") { - println!("cargo:rustc-env={env}=[+infinispan]"); + features.push("+infinispan"); } + println!("cargo:rustc-env={env}={features:?}"); } fn set_profile(env: &str) { diff --git a/limitador-server/src/config.rs b/limitador-server/src/config.rs index 5ab21afe..ac015d31 100644 --- a/limitador-server/src/config.rs +++ b/limitador-server/src/config.rs @@ -35,6 +35,35 @@ pub struct Configuration { pub rate_limit_headers: RateLimitHeaders, } +pub mod env { + pub const LIMITS_FILE: Option<&'static str> = option_env!("LIMITS_FILE"); + + pub const ENVOY_RLS_HOST: Option<&'static str> = option_env!("ENVOY_RLS_HOST"); + pub const ENVOY_RLS_PORT: Option<&'static str> = option_env!("ENVOY_RLS_PORT"); + + pub const HTTP_API_HOST: Option<&'static str> = option_env!("HTTP_API_HOST"); + pub const HTTP_API_PORT: Option<&'static str> = option_env!("HTTP_API_PORT"); + + pub const DISK_PATH: Option<&'static str> = option_env!("DISK_PATH"); + pub const DISK_OPTIMIZE: Option<&'static str> = option_env!("DISK_OPTIMIZE"); + + pub const REDIS_URL: Option<&'static str> = option_env!("REDIS_URL"); + pub const REDIS_LOCAL_CACHE_MAX_TTL_CACHED_COUNTERS_MS: Option<&'static str> = + option_env!("REDIS_LOCAL_CACHE_MAX_TTL_CACHED_COUNTERS_MS"); + pub const REDIS_LOCAL_CACHE_FLUSHING_PERIOD_MS: Option<&'static str> = + option_env!("REDIS_LOCAL_CACHE_FLUSHING_PERIOD_MS"); + pub const REDIS_LOCAL_CACHE_TTL_RATIO_CACHED_COUNTERS: Option<&'static str> = + option_env!("REDIS_LOCAL_CACHE_TTL_RATIO_CACHED_COUNTERS"); + + pub const RATE_LIMIT_HEADERS: Option<&'static str> = option_env!("RATE_LIMIT_HEADERS"); + + #[cfg(feature = "infinispan")] + pub const INFINISPAN_CACHE_NAME: Option<&'static str> = option_env!("INFINISPAN_CACHE_NAME"); + #[cfg(feature = "infinispan")] + pub const INFINISPAN_COUNTERS_CONSISTENCY: Option<&'static str> = + option_env!("INFINISPAN_COUNTERS_CONSISTENCY"); +} + impl Configuration { pub const DEFAULT_RLS_PORT: &'static str = "8081"; pub const DEFAULT_HTTP_PORT: &'static str = "8080"; diff --git a/limitador-server/src/main.rs b/limitador-server/src/main.rs index 0eb0e801..95398cc9 100644 --- a/limitador-server/src/main.rs +++ b/limitador-server/src/main.rs @@ -12,17 +12,14 @@ use crate::config::{ }; use crate::envoy_rls::server::{run_envoy_rls_server, RateLimitHeaders}; use crate::http_api::server::run_http_server; -use clap::{App, Arg, SubCommand}; +use clap::{value_parser, Arg, ArgAction, Command}; +use const_format::formatcp; use env_logger::Builder; use limitador::errors::LimitadorError; use limitador::limit::Limit; use limitador::storage::disk::DiskStorage; #[cfg(feature = "infinispan")] use limitador::storage::infinispan::{Consistency, InfinispanStorageBuilder}; -#[cfg(feature = "infinispan")] -use limitador::storage::infinispan::{ - DEFAULT_INFINISPAN_CONSISTENCY, DEFAULT_INFINISPAN_LIMITS_CACHE_NAME, -}; use limitador::storage::redis::{ AsyncRedisStorage, CachedRedisStorage, CachedRedisStorageBuilder, DEFAULT_FLUSHING_PERIOD_SEC, DEFAULT_MAX_CACHED_COUNTERS, DEFAULT_MAX_TTL_CACHED_COUNTERS_SEC, @@ -51,7 +48,7 @@ mod config; const LIMITADOR_VERSION: &str = env!("CARGO_PKG_VERSION"); const LIMITADOR_PROFILE: &str = env!("LIMITADOR_PROFILE"); -const LIMITADOR_FEATURES: Option<&'static str> = option_env!("LIMITADOR_FEATURES"); +const LIMITADOR_FEATURES: &str = env!("LIMITADOR_FEATURES"); const LIMITADOR_HEADER: &str = "Limitador Server"; #[derive(Error, Debug)] @@ -396,84 +393,39 @@ async fn main() -> Result<(), Box> { Ok(()) } -fn create_config() -> (Configuration, String) { - let full_version = { - let build = match LIMITADOR_PROFILE { - "release" => "".to_owned(), - other => format!(" {other} build"), - }; - - format!( - "v{} ({}) {}{}", - LIMITADOR_VERSION, - env!("LIMITADOR_GIT_HASH"), - LIMITADOR_FEATURES.unwrap_or(""), - build, - ) - }; - - // figure defaults out - let default_limit_file = env::var("LIMITS_FILE").unwrap_or_else(|_| "".to_string()); - - let default_rls_host = - env::var("ENVOY_RLS_HOST").unwrap_or_else(|_| Configuration::DEFAULT_IP_BIND.to_string()); - let default_rls_port = - env::var("ENVOY_RLS_PORT").unwrap_or_else(|_| Configuration::DEFAULT_RLS_PORT.to_string()); - - let default_http_host = - env::var("HTTP_API_HOST").unwrap_or_else(|_| Configuration::DEFAULT_IP_BIND.to_string()); - let default_http_port = - env::var("HTTP_API_PORT").unwrap_or_else(|_| Configuration::DEFAULT_HTTP_PORT.to_string()); - - let disk_path = env::var("DISK_PATH").unwrap_or_else(|_| "".to_string()); - let disk_optimize = env::var("DISK_OPTIMIZE").unwrap_or_else(|_| "throughput".to_string()); - - let redis_url = env::var("REDIS_URL").unwrap_or_else(|_| "".to_string()); - - let redis_cached_ttl_default = env::var("REDIS_LOCAL_CACHE_MAX_TTL_CACHED_COUNTERS_MS") - .unwrap_or_else(|_| (DEFAULT_MAX_TTL_CACHED_COUNTERS_SEC * 1000).to_string()); - let redis_flushing_period_default = env::var("REDIS_LOCAL_CACHE_FLUSHING_PERIOD_MS") - .unwrap_or_else(|_| (DEFAULT_FLUSHING_PERIOD_SEC * 1000).to_string()); - let redis_max_cached_counters_default = DEFAULT_MAX_CACHED_COUNTERS.to_string(); - let redis_ttl_ratio_default = env::var("REDIS_LOCAL_CACHE_TTL_RATIO_CACHED_COUNTERS") - .unwrap_or_else(|_| DEFAULT_TTL_RATIO_CACHED_COUNTERS.to_string()); - - #[cfg(feature = "infinispan")] - let infinispan_cache_default = env::var("INFINISPAN_CACHE_NAME") - .unwrap_or_else(|_| DEFAULT_INFINISPAN_LIMITS_CACHE_NAME.to_string()); - #[cfg(feature = "infinispan")] - let infinispan_consistency_default = env::var("INFINISPAN_COUNTERS_CONSISTENCY") - .unwrap_or_else(|_| DEFAULT_INFINISPAN_CONSISTENCY.to_string()); - - let rate_limit_headers_default = env::var("RATE_LIMIT_HEADERS").unwrap_or("NONE".to_string()); +fn create_config() -> (Configuration, &'static str) { + let full_version: &'static str = formatcp!( + "v{} ({}) {} {}", + LIMITADOR_VERSION, + env!("LIMITADOR_GIT_HASH"), + LIMITADOR_FEATURES, + LIMITADOR_PROFILE, + ); // wire args based of defaults - let limit_arg = Arg::with_name("LIMITS_FILE") + let limit_arg = Arg::new("LIMITS_FILE") .help("The limit file to use") .index(1); - let limit_arg = if default_limit_file.is_empty() { - limit_arg.required(true) - } else { - limit_arg.default_value(&default_limit_file) + let limit_arg = match config::env::LIMITS_FILE { + None => limit_arg.required(true), + Some(file) => limit_arg.default_value(file), }; - let redis_url_arg = Arg::with_name("URL").help("Redis URL to use").index(1); - let redis_url_arg = if redis_url.is_empty() { - redis_url_arg.required(true) - } else { - redis_url_arg.default_value(&redis_url) + let redis_url_arg = Arg::new("URL").help("Redis URL to use").index(1); + let redis_url_arg = match config::env::REDIS_URL { + None => redis_url_arg.required(true), + Some(url) => redis_url_arg.default_value(url), }; - let disk_path_arg = Arg::with_name("PATH").help("Path to counter DB").index(1); - let disk_path_arg = if disk_path.is_empty() { - disk_path_arg.required(true) - } else { - disk_path_arg.default_value(&disk_path) + let disk_path_arg = Arg::new("PATH").help("Path to counter DB").index(1); + let disk_path_arg = match config::env::DISK_PATH { + None => disk_path_arg.required(true), + Some(path) => disk_path_arg.default_value(path), }; // build app - let cmdline = App::new(LIMITADOR_HEADER) - .version(full_version.as_str()) + let cmdline = Command::new(LIMITADOR_HEADER) + .version(full_version) .author("The Kuadrant team - github.com/Kuadrant") .about("Rate Limiting Server") .disable_help_subcommand(true) @@ -483,64 +435,74 @@ fn create_config() -> (Configuration, String) { .subcommand_required(false) .arg(limit_arg) .arg( - Arg::with_name("ip") + Arg::new("ip") .short('b') .long("rls-ip") - .default_value(&default_rls_host) + .default_value( + config::env::ENVOY_RLS_HOST.unwrap_or(Configuration::DEFAULT_IP_BIND), + ) .display_order(1) .help("The IP to listen on for RLS"), ) .arg( - Arg::with_name("port") + Arg::new("port") .short('p') .long("rls-port") - .default_value(&default_rls_port) + .default_value( + config::env::ENVOY_RLS_PORT.unwrap_or(Configuration::DEFAULT_RLS_PORT), + ) + .value_parser(value_parser!(u16)) .display_order(2) .help("The port to listen on for RLS"), ) .arg( - Arg::with_name("http_ip") + Arg::new("http_ip") .short('B') .long("http-ip") - .default_value(&default_http_host) + .default_value(config::env::HTTP_API_HOST.unwrap_or(Configuration::DEFAULT_IP_BIND)) .display_order(3) .help("The IP to listen on for HTTP"), ) .arg( - Arg::with_name("http_port") + Arg::new("http_port") .short('P') .long("http-port") - .default_value(&default_http_port) + .default_value( + config::env::HTTP_API_PORT.unwrap_or(Configuration::DEFAULT_HTTP_PORT), + ) + .value_parser(value_parser!(u16)) .display_order(4) .help("The port to listen on for HTTP"), ) .arg( - Arg::with_name("limit_name_in_labels") + Arg::new("limit_name_in_labels") .short('l') .long("limit-name-in-labels") + .action(ArgAction::SetTrue) .display_order(5) .help("Include the Limit Name in prometheus label"), ) .arg( - Arg::with_name("v") + Arg::new("v") .short('v') - .multiple_occurrences(true) - .max_occurrences(4) + .action(ArgAction::Count) + .value_parser(value_parser!(u8).range(..5)) .display_order(6) .help("Sets the level of verbosity"), ) .arg( - Arg::with_name("validate") + Arg::new("validate") .long("validate") + .action(ArgAction::SetTrue) .display_order(7) .help("Validates the LIMITS_FILE and exits"), ) .arg( - Arg::with_name("rate_limit_headers") + Arg::new("rate_limit_headers") .long("rate-limit-headers") .short('H') .display_order(8) - .default_value(&rate_limit_headers_default) + .default_value(config::env::RATE_LIMIT_HEADERS.unwrap_or("NONE")) .value_parser(clap::builder::PossibleValuesParser::new([ "NONE", "DRAFT_VERSION_03", @@ -548,21 +510,21 @@ fn create_config() -> (Configuration, String) { .help("Enables rate limit response headers"), ) .subcommand( - SubCommand::with_name("memory") + Command::new("memory") .display_order(1) .about("Counters are held in Limitador (ephemeral)"), ) .subcommand( - SubCommand::with_name("disk") + Command::new("disk") .display_order(2) .about("Counters are held on disk (persistent)") .arg(disk_path_arg) .arg( - Arg::with_name("OPTIMIZE") + Arg::new("OPTIMIZE") .long("optimize") - .takes_value(true) + .action(ArgAction::Set) .display_order(1) - .default_value(&disk_optimize) + .default_value(config::env::DISK_OPTIMIZE.unwrap_or("throughput")) .value_parser(clap::builder::PossibleValuesParser::new([ "throughput", "disk", @@ -571,49 +533,57 @@ fn create_config() -> (Configuration, String) { ), ) .subcommand( - SubCommand::with_name("redis") + Command::new("redis") .display_order(3) .about("Uses Redis to store counters") .arg(redis_url_arg.clone()), ) .subcommand( - SubCommand::with_name("redis_cached") + Command::new("redis_cached") .about("Uses Redis to store counters, with an in-memory cache") .display_order(4) .arg(redis_url_arg) .arg( - Arg::with_name("TTL") + Arg::new("TTL") .long("ttl") - .takes_value(true) + .action(ArgAction::Set) .value_parser(clap::value_parser!(u64)) - .default_value(&redis_cached_ttl_default) + .default_value( + config::env::REDIS_LOCAL_CACHE_MAX_TTL_CACHED_COUNTERS_MS + .unwrap_or("5000"), + ) .display_order(2) .help("TTL for cached counters in milliseconds"), ) .arg( - Arg::with_name("ratio") + Arg::new("ratio") .long("ratio") - .takes_value(true) + .action(ArgAction::Set) .value_parser(clap::value_parser!(u64)) - .default_value(&redis_ttl_ratio_default) + .default_value( + config::env::REDIS_LOCAL_CACHE_TTL_RATIO_CACHED_COUNTERS + .unwrap_or("10000"), + ) .display_order(3) .help("Ratio to apply to the TTL from Redis on cached counters"), ) .arg( - Arg::with_name("flush") + Arg::new("flush") .long("flush-period") - .takes_value(true) + .action(ArgAction::Set) .value_parser(clap::value_parser!(i64)) - .default_value(&redis_flushing_period_default) + .default_value( + config::env::REDIS_LOCAL_CACHE_FLUSHING_PERIOD_MS.unwrap_or("1000"), + ) .display_order(4) .help("Flushing period for counters in milliseconds"), ) .arg( - Arg::with_name("max") + Arg::new("max") .long("max-cached") - .takes_value(true) + .action(ArgAction::Set) .value_parser(clap::value_parser!(usize)) - .default_value(&redis_max_cached_counters_default) + .default_value("10000") .display_order(5) .help("Maximum amount of counters cached"), ), @@ -621,31 +591,31 @@ fn create_config() -> (Configuration, String) { #[cfg(feature = "infinispan")] let cmdline = cmdline.subcommand( - SubCommand::with_name("infinispan") + Command::new("infinispan") .about("Uses Infinispan to store counters") .display_order(5) .arg( - Arg::with_name("URL") + Arg::new("URL") .help("Infinispan URL to use") .display_order(1) .required(true) .index(1), ) .arg( - Arg::with_name("cache name") + Arg::new("cache name") .short('n') .long("cache-name") - .takes_value(true) - .default_value(&infinispan_cache_default) + .action(ArgAction::Set) + .default_value(config::env::INFINISPAN_CACHE_NAME.unwrap_or("infinispan")) .display_order(2) .help("Name of the cache to store counters in"), ) .arg( - Arg::with_name("consistency") + Arg::new("consistency") .short('c') .long("consistency") - .takes_value(true) - .default_value(&infinispan_consistency_default) + .action(ArgAction::Set) + .default_value(config::env::INFINISPAN_COUNTERS_CONSISTENCY.unwrap_or("Strong")) .value_parser(clap::builder::PossibleValuesParser::new(["Strong", "Weak"])) .display_order(3) .help("The consistency to use to read from the cache"), @@ -654,9 +624,9 @@ fn create_config() -> (Configuration, String) { let matches = cmdline.get_matches(); - let limits_file = matches.value_of("LIMITS_FILE").unwrap(); + let limits_file = matches.get_one::("LIMITS_FILE").unwrap(); - if matches.is_present("validate") { + if matches.get_flag("validate") { let error = match std::fs::File::open(limits_file) { Ok(f) => { let parsed_limits: Result, _> = serde_yaml::from_reader(f); @@ -696,19 +666,22 @@ fn create_config() -> (Configuration, String) { let storage = match matches.subcommand() { Some(("redis", sub)) => StorageConfiguration::Redis(RedisStorageConfiguration { - url: sub.value_of("URL").unwrap().to_owned(), + url: sub.get_one::("URL").unwrap().to_owned(), cache: None, }), Some(("disk", sub)) => StorageConfiguration::Disk(DiskStorageConfiguration { - path: sub.value_of("PATH").expect("We need a path!").to_string(), - optimization: match sub.value_of("OPTIMIZE") { + path: sub + .get_one::("PATH") + .expect("We need a path!") + .to_string(), + optimization: match sub.get_one::("OPTIMIZE").map(String::as_str) { Some("disk") => storage::disk::OptimizeFor::Space, Some("throughput") => storage::disk::OptimizeFor::Throughput, _ => unreachable!("Some disk OptimizeFor wasn't configured!"), }, }), Some(("redis_cached", sub)) => StorageConfiguration::Redis(RedisStorageConfiguration { - url: sub.value_of("URL").unwrap().to_owned(), + url: sub.get_one::("URL").unwrap().to_owned(), cache: Some(RedisStorageCacheConfiguration { flushing_period: *sub.get_one("flush").unwrap(), max_ttl: *sub.get_one("TTL").unwrap(), @@ -719,9 +692,9 @@ fn create_config() -> (Configuration, String) { #[cfg(feature = "infinispan")] Some(("infinispan", sub)) => { StorageConfiguration::Infinispan(InfinispanStorageConfiguration { - url: sub.value_of("URL").unwrap().to_owned(), - cache: Some(sub.value_of("cache name").unwrap().to_string()), - consistency: Some(sub.value_of("consistency").unwrap().to_string()), + url: sub.get_one::("URL").unwrap().to_owned(), + cache: Some(sub.get_one::("cache name").unwrap().to_string()), + consistency: Some(sub.get_one::("consistency").unwrap().to_string()), }) } Some(("memory", _sub)) => StorageConfiguration::InMemory, @@ -735,7 +708,11 @@ fn create_config() -> (Configuration, String) { _ => unreachable!("Some storage wasn't configured!"), }; - let rate_limit_headers = match matches.value_of("rate_limit_headers").unwrap() { + let rate_limit_headers = match matches + .get_one::("rate_limit_headers") + .unwrap() + .as_str() + { "NONE" => RateLimitHeaders::None, "DRAFT_VERSION_03" => RateLimitHeaders::DraftVersion03, _ => unreachable!("invalid --rate-limit-headers value"), @@ -744,16 +721,16 @@ fn create_config() -> (Configuration, String) { let mut config = Configuration::with( storage, limits_file.to_string(), - matches.value_of("ip").unwrap().into(), - matches.value_of("port").unwrap().parse().unwrap(), - matches.value_of("http_ip").unwrap().into(), - matches.value_of("http_port").unwrap().parse().unwrap(), - matches.value_of("limit_name_in_labels").is_some() + matches.get_one::("ip").unwrap().into(), + *matches.get_one::("port").unwrap(), + matches.get_one::("http_ip").unwrap().into(), + *matches.get_one::("http_port").unwrap(), + matches.get_flag("limit_name_in_labels") || env_option_is_enabled("LIMIT_NAME_IN_PROMETHEUS_LABELS"), rate_limit_headers, ); - config.log_level = match matches.occurrences_of("v") { + config.log_level = match matches.get_count("v") { 0 => None, 1 => Some(LevelFilter::Warn), 2 => Some(LevelFilter::Info),