pub const LOG_ENV: &str = "QUILT_LOG";
pub const OUR_TARGETS: [&str; 4] = ["quilt", "quilt_rs", "quilt_uri", "quilt_sync"];
const DEPENDENCY_LEVEL: &str = "warn";
#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
#[error("{value:?} is not a log level or a list of directives")]
pub struct InvalidLogFilter {
pub value: String,
}
impl InvalidLogFilter {
#[must_use]
pub fn new(value: impl Into<String>) -> Self {
Self {
value: value.into(),
}
}
}
pub fn directives(value: &str) -> Result<Option<String>, InvalidLogFilter> {
let trimmed = value.trim();
if trimmed.is_empty() {
return Ok(None);
}
let level = trimmed.to_ascii_lowercase();
match level.as_str() {
"trace" | "debug" | "info" | "warn" => {
let mut parts: Vec<String> = OUR_TARGETS
.iter()
.map(|target| format!("{target}={level}"))
.collect();
parts.push(DEPENDENCY_LEVEL.to_string());
Ok(Some(parts.join(",")))
}
"error" | "off" => Ok(Some(level)),
_ if trimmed.contains('=') => Ok(Some(trimmed.to_string())),
_ => Err(InvalidLogFilter::new(value)),
}
}
#[cfg(test)]
mod tests {
use super::*;
fn ours_at(level: &str) -> Option<String> {
Some(format!(
"quilt={level},quilt_rs={level},quilt_uri={level},quilt_sync={level},warn"
))
}
fn ok(value: &str) -> Option<String> {
directives(value).unwrap_or_else(|err| panic!("{value:?}: {err}"))
}
#[test]
fn a_bare_level_puts_our_crates_at_it_and_dependencies_at_warn() {
for level in ["trace", "debug", "info", "warn"] {
assert_eq!(ok(level), ours_at(level), "{level}");
}
}
#[test]
fn a_level_quieter_than_warn_applies_to_everything() {
assert_eq!(ok("error").as_deref(), Some("error"));
assert_eq!(ok("off").as_deref(), Some("off"));
}
#[test]
fn a_bare_level_ignores_case_and_surrounding_spaces() {
assert_eq!(ok("DEBUG"), ours_at("debug"));
assert_eq!(ok(" Info \n"), ours_at("info"));
assert_eq!(ok(" OFF ").as_deref(), Some("off"));
}
#[test]
fn directives_are_used_verbatim() {
for value in [
"quilt_rs=trace",
"quilt_rs=trace,aws_smithy_runtime=debug",
"quilt_sync=info,warn",
"debug,hyper=off",
] {
assert_eq!(ok(value).as_deref(), Some(value), "{value}");
}
}
#[test]
fn an_empty_value_counts_as_unset() {
assert_eq!(ok(""), None);
assert_eq!(ok(" "), None);
}
#[test]
fn a_word_that_is_not_a_level_is_an_error() {
for value in ["debgu", "quilt_rs"] {
assert_eq!(
directives(value),
Err(InvalidLogFilter::new(value)),
"{value}"
);
}
}
#[test]
fn the_error_names_the_value_as_given() {
assert_eq!(
InvalidLogFilter::new(" debgu").to_string(),
"\" debgu\" is not a log level or a list of directives"
);
}
}