Command Line Argument Parser for Rust
Dual-licensed under Apache 2.0 or MIT.
Create your command-line parser, with all of the bells and whistles, declaratively or procedurally.
For more details, see:
Easily add a --verbose flag to CLIs using Clap
Home Page: https://docs.rs/clap-verbosity-flag
License: Apache License 2.0
Command Line Argument Parser for Rust
Dual-licensed under Apache 2.0 or MIT.
Create your command-line parser, with all of the bells and whistles, declaratively or procedurally.
For more details, see:
@killercup you're probably the right person to ask, but: why are we filtering messages in .setup_env_logger()
?
I can imagine it being useful to sometimes log out trace messages from library code (e.g. embedded databases, etc.) Should we perhaps introduce a method / flag that doesn't filter?
The new set_default
mechanism (and the combination with --quiet) allows setting the default level to warn -- something I highly appreciate.
The help text of --verbose
, however, is built earlier than the set_default is evaluated (much earlier, in fact -- at build time). This means that programs that use set_default
with anything but the built-in default Error get inconsistent help messages, ie. always
By default, it'll only report errors. Passing
-v
one time also prints
warnings,-vv
enables info logging,-vvv
debug, and-vvvv
trace.
and not, say
By default, it'll only report errors and warnings. Passing
-v
one time
enables info logging,-vv
debug, and-vvv
trace.
I'm not well enough versed in structopt to propose any thought-through way toward resolution. One possibility would to add a generic argument to Verbosity that'd indicate the default and serve as help text; could look like
#[derive(StructOpt, Debug)]
struct CliArgsWithVerbosity {
...,
#[structopt(flatten)]
verbose: clap_verbosity_flag::Verbosity<DefaultVerbosity=clap_verbosity_flag::DefaultWarning>,
}
and where the DefaultWarning struct provides something like
impl VerbosityDefault for DefaultWarning {
const fn level() -> Option<Level> {
Some(log::Level::Warn)
}
const fn text() -> &'static str {
"By default, it'll only report errors and warnings [...]"
}
}
but as said, I don't know whether using that text would be doable with structopt.
Unsure why the default api to make this value private, but making the value public allows more flexible use of this library. PR submitted for this change.
When using sub-commands it would be good idea to set this flag globally.
#[derive(Parser, Debug)]
pub(crate) struct Args {
#[clap(subcommand)]
command: Commands,
#[clap(flatten, global = true)]
verbose: Verbosity,
}
Above produces an error:
error: methods are not allowed for flattened entry
--> src/cli/args.rs:24:10
|
24 | #[clap(flatten, global = true)]
|
I was wondering what a good approach would be to enable different loggers for production / development. I can't think of any clean approach for automatic switching, so probably the best way to go about it is to add some switches.
Say we were building an HTTP proxy in Rust, similar to Nginx. We would probably want machine-readable log output for production, but in development we would want something that is optimized for human beings.
Also depending on the organizations involved, different people might want to use different loggers. Some might want to run it through syslog
, whereas others might prefer to ingest ndjson from stdin.
I propose we add 2 new flags: one for selecting a log formatter, and one for choosing the "pretty printer" formatter.
USAGE:
main [FLAGS] [OPTIONS]
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
--pretty Log output in a human readable format
-v, --verbosity Pass many times for more log output
OPTIONS:
-o, --output <format> Control the formatting of the log output
--pretty
should have a shorthand. If it does, it should probably be -P
(uppercase) to not conflict with the commonly used -p/--port
.-o/--outfile
is also commonly used as a shorthand for which file to write stdout
output to. This could potentially conflict with applications that have opinions about where to store artifacts. -l/--logger
(or similar) might have fewer potential conflicts, despite not being rooted in prior art (see below).I hope all of this makes sense. I'd be really curious to hear people's thoughts on this!
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
These updates are awaiting their schedule. Click on a checkbox to get an update now.
Cargo.toml
log 0.4.1
clap 4.0.0
clap 4.5.4
env_logger 0.11.3
tracing 0.1
tracing-subscriber 0.3
tracing-log 0.2
.github/workflows/audit.yml
actions/checkout v4
actions-rs/audit-check v1
actions/checkout v4
EmbarkStudios/cargo-deny-action v1
.github/workflows/ci.yml
actions/checkout v4
Swatinem/rust-cache v2
actions/checkout v4
Swatinem/rust-cache v2
actions/checkout v4
actions/checkout v4
Swatinem/rust-cache v2
actions/checkout v4
Swatinem/rust-cache v2
actions/checkout v4
Swatinem/rust-cache v2
actions/checkout v4
Swatinem/rust-cache v2
github/codeql-action v3
actions/checkout v4
Swatinem/rust-cache v2
.github/workflows/committed.yml
actions/checkout v4
.github/workflows/pre-commit.yml
actions/checkout v4
actions/setup-python v5
pre-commit/action v3.0.1
.github/workflows/rust-next.yml
actions/checkout v4
Swatinem/rust-cache v2
actions/checkout v4
Swatinem/rust-cache v2
.github/workflows/spelling.yml
actions/checkout v4
.github/workflows/ci.yml
STABLE 1.80
STABLE 1.80
STABLE 1.80
There's currently no way to get the log level standalone. This means that this crate can currently only be used through the .setup_env_logger()
method. It would probably be good to make the .log_level()
method public, and have it return the level instead of a filter.
There was a straightforward PR thrown up for discussion over at #65, effectively looking for a Serialize
and Deserialize
implementation for this library. The requests from @epage:
I think more of a case is needed for why a CLI flag needs serialization, particularly the fact that this was done in a raw way (separate
verbose
,quiet
asu8
s) - #65 (comment)
More design discussion is needed on this because exposing separate
verbose
andquiet
fields that areu8
does not make sense. - #65 (comment)
If an entire args
object is being passed into tracing
it is quite nice to have a Serialize
so that derive
works. I don't want to have to impl Serialize for Args
for this reason. If I don't do some serialization then I end up with Debug
and that is super-verbose.
use clap::Parser;
use serde::Serialize;
use svix_ksuid::{Ksuid, KsuidLike};
use tracing::instrument;
mod telemetry;
#[derive(Serialize, Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
// #[command(flatten)]
// verbose: clap_verbosity_flag::Verbosity,
#[arg(short, long, default_value_t = 1)]
count: u8,
}
impl Args {
fn to_json(&self) -> String {
return serde_json::to_string(&self).expect("");
}
}
// Main is a very small setup shim, and then gets out of the way.
fn main() -> proc_exit::ExitResult {
let id = Ksuid::new(None, None);
telemetry::init(id);
let args = Args::parse();
let result = run(id, args);
proc_exit::exit(result);
}
#[instrument(name = "run()", fields(args = args.to_json(), id = id.to_string()) ret, err)]
fn run(id: Ksuid, args: Args) -> proc_exit::ExitResult {
proc_exit::Code::SUCCESS.ok()
}
<Elsewhere>
This some-cli gui
command spins up a server and opens a browser to an HTML page. Eventually that HTML page makes a network request back to the server, which contains a serialized form of the arguments that would have been passed in. That's going to be JSON (cause it's coming from the web), deserializing into Args
(from the above example).
Starts the server:
$ some-cli gui
(Complicated configuration happens in a browser.)
Data from a "configuration finished!" network request passed back in to the CLI entry point:
let args: Args = serde_json::from_str(args)?;
let result = run(id, args);
There are basically only two reasonable options here to represent configuration since it is a count
.
u8
sexposing separate
verbose
andquiet
fields that areu8
does not make sense
Given that we have -q
and -v[vvv]
exposed as separate args this separation doesn't seem particularly egregious. Further, since the struct can be constructed with clap_verbosity_flag::Verbosity::new(2, 4)
, any serialization that doesn't give you both of those values is lossy.
Being able to represent the error conditions (error: the argument '--quiet...' cannot be used with '--verbose...'
) that can be triggered by command line usage is reasonable—even though typically it would never get through ::parse()
.
i16
Since we have the conflicts_with
lockout from the primary clap
use case, we could choose to serialize them into a single value, in spite of it being lossy. Take a page from the log
mapping, and do quiet
as -(count)
.
An i16
gives us way more bits than we need, but there isn't an i9
.
...
-4 => -qqqq
-3 => -qqq
-2 => -qq
-1 => -q
0 => None
1 => -v
2 => -vv
3 => -vvv
4 => -vvvv
...
This approach can't support { quiet: 4, verbosity: 4 }
like a manually constructed struct can.
I'm in favor of the separate u8
s for representation fidelity reasons and nominate reopening and accepting #65.
Maybe I am being thick, but it isn't really clear how to customise the help menus.
I know it says in the documentation to implement LogLevel
, but what am I supposed to implement it on?
Maybe an example in the examples directory could be useful for others like me who want to alter the help menu but can't figure it out.
The current example only shows adding a verbose
field to the CLI struct, but doesn't demonstrate its usage. I imagine one could figure it out from the documentation, but it'd be nice if the example was more self-service.
As clap 3 includes derive, can clap-verbosity-flag
also include #[derive(Clap)]
-version of implementation, maybe with a feature flag or something?
I know that you're the author of the quicli
crate, which seems to have a subset of functionality that conflicts with this (since both crates would set up env-logger
, right?). Is the use case to have a more minimal set of dependencies and cut out the main!
macro and its associated failure
dependency? Perhaps you think that this is more appropriate to use generally now that ?
-in-main
is available on stable?
To be perfectly frank, I only know what "More output per occurrence" and "Less output per occurrence" mean because I already know what the options they describe do and how they react to being used more than once.
"per occurrence" is such an opaque choice of phrasing that I'm not even sure they effectively communicate that the somewhat self-documenting --verbose --verbose
will do something different from --verbose
.
May I suggest taking inspiration from this excerpt from the UltiSnips snippet I use for starting Python scripts?
parser.add_argument('-v', '--verbose', action="count",
default=2, help="Increase the verbosity. Use twice for extra effect.")
parser.add_argument('-q', '--quiet', action="count",
default=0, help="Decrease the verbosity. Use twice for extra effect.")
That's not ideal and, to be honest, I think I let a little "Avoid having to wrap it onto the next line of the source code" contaminate it, but it's still much more helpful.
Maybe something like "Make console output more verbose. Can be repeated for greater effect."
This would be a big help for reviewers to avoid nitpicking over little things.
As the title say, I can't find a way to use this with clap. There is only one example, and it concerns structopt, not clap directly. My question is : is there a way to make this crate work with default clap ? If not, why is it named "clap-verbosity-flag" ?
After updating all dependencies, the comment of /// Logging flags to
#[command(flatte)] into your CLI
shows up as the first line in our help text. I don't think that's intended.
Logging flags to `#[command(flatte)]` into your CLI
Usage: rattler-build [OPTIONS] [COMMAND]
Commands:
build Build a package
test Test a package
...
I can send a patch to remove this comment, but also happy to hear other options.
Clap3 is now in the rc stage, so I'm looking to upgrade. Any idea when clap3 might be supported?
Is it possible with flatten
to disable for subcommands?
I'm having the following issue when trying to use clap-verbosity-flag
the trait bound `clap_verbosity_flag::Verbosity: structopt::StructOpt` is not satisfied
the trait `structopt::StructOpt` is not implemented for `clap_verbosity_flag::Verbosity`rustc(E0277)
main.rs(18, 17): the trait `structopt::StructOpt` is not implemented for `clap_verbosity_flag::Verbosity`
the trait bound `clap_verbosity_flag::Verbosity: structopt::StructOptInternal` is not satisfied
the trait `structopt::StructOptInternal` is not implemented for `clap_verbosity_flag::Verbosity`rustc(E0277)
clap-verbosity-flag = "1.0.0"
structopt = "0.3.26"
use structopt::StructOpt;
#[derive(StructOpt)]
struct Cli {
#[structopt(flatten)]
verbosity: clap_verbosity_flag::Verbosity,
}
Guidance would be appreciated. 🙏
There is currently no way to detect if the two internal verbose
and quiet
fields are both zero. When they are both zero, this indicates that nothing related to log level has been specified on the command line. For my use case, I want to fallback to using the environment to determine log level if nothing is specified on the command line.
I will be opening a PR in a couple hours for this feature.
Let me know if you'd like the function called something different besides is_set
.
Right now, only errors are shown by default.
I would assume at least warnings would show up. Probably also info(rmational) messages.
Of course, this requires adding a way to make things quieter (which we might need already, see #9). We'd probably need a --quiet
/ -q
flag to go the other way.
I'm using these implementations personally:
#[derive(Debug, Clone, Default)]
pub struct Verbosity<L: LogLevel>(clap_verbosity_flag::Verbosity<L>);
impl<L: LogLevel> Eq for Verbosity<L> {}
impl<L: LogLevel> PartialEq for Verbosity<L> {
fn eq(&self, other: &Self) -> bool {
self.0.log_level() == other.0.log_level()
}
}
impl<L: LogLevel> Ord for Verbosity<L> {
fn cmp(&self, other: &Self) -> Ordering {
self.0.log_level().cmp(&other.0.log_level())
}
}
impl<L: LogLevel> PartialOrd for Verbosity<L> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
As per #2 (comment), we should probably add an example on how to use setup_env_logger()
. Thanks!
The simple example in the crate docs demonstrates the behaviour:
use structopt::StructOpt;
use clap_verbosity_flag::Verbosity;
#[derive(Debug, StructOpt)]
struct Cli {
#[structopt(flatten)]
verbose: Verbosity,
}
fn main() {
Cli::from_args();
}
Then running:
❯ ./target/debug/examples/simple --help
clap-verbosity-flag 0.3.0
Easily add a `--verbose` flag to CLIs using Structopt
# Examples
```rust use structopt::StructOpt; use clap_verbosity_flag::Verbosity;
/// Le CLI #[derive(Debug, StructOpt)] struct Cli { #[structopt(flatten)] verbose: Verbosity, } # # fn main() {} ```
USAGE:
simple [FLAGS]
FLAGS:
-h, --help
Prints help information
-q, --quiet
Pass many times for less log output
-V, --version
Prints version information
-v, --verbose
Pass many times for more log output
By default, it'll only report errors. Passing `-v` one time also prints warnings, `-vv` enables info
logging, `-vvv` debug, and `-vvvv` trace.
Is this perhaps due to a new version of structopt?
To make the sample code I wrote in #53 work, we need to depend on the log crate.
Fixed sample code:
use log; // Need this and adding the dependency in Cargo.toml
fn foo() {
if opt.verbose.log_level_filter() <= LevelFilter::Warn {
eprintln!("Hide command's stdout");
}
if opt.verbose.log_level_filter() <= LevelFilter::Error {
eprintln!("Hide command's stderr");
}
}
I’m not sure if I want to use the log crate or tracing yet… Since this crate can support both logging frameworks, it feels strange to be forced to depends on the log crate to manually manage the log level.
I think the LevelFilter
could be re-exported (and maybe Level
too).
ansi_term is Unmaintained
Details | |
---|---|
Status | unmaintained |
Package | ansi_term |
Version | 0.12.1 |
URL | ogham/rust-ansi-term#72 |
Date | 2021-08-18 |
The maintainer has adviced that this crate is deprecated and will not receive any maintenance.
The crate does not seem to have much dependencies and may or may not be ok to use as-is.
Last release seems to have been three years ago.
The below list has not been vetted in any way and may or may not contain alternatives;
See advisory page for additional details.
Regarding the discussion in #37 (whether it is sensible to add support for returning tracing
's type.)
I just came across the same issue/question, and I understand @epage's concerns. So while I would hope that you'd find a solution to support that crate, I won't reopen the discussion here. 😉
However I want to advocate for adding a requirement to the usage of the verbosity-field into the minimal example in the README, so that this implicit dependency becomes more explicit.
The crate documentation contains a usage example that kinda hints at that with the instantiation of an env_logger
, but without knowing what to look for it's difficult to spot that the Log*-types are all borrowed from the log
-crate.
A line to the effect of "This crate relies on the log
-crate by returning log::{Level,LevelFilter} values." in the README and/or crate documentation would be great.
As a user, there are times you don't want anything logged, even errors, but instead rely on printed output and exit code.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.