Skip to content

Commit

Permalink
chore: improve Level and update changelog
Browse files Browse the repository at this point in the history
  • Loading branch information
tobz committed Nov 26, 2024
1 parent deaa359 commit f289050
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 4 deletions.
8 changes: 8 additions & 0 deletions metrics/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased] - ReleaseDate

### Added

- Added a section to the crate-level documentation about `Metadata` and how it's used.
- Derived `Copy`, `PartialOrd` and `Ord` for `Metadata` to allow for cheap copies and the ability to compare levels for
filtering purposes.
- Added `TryFrom<&str>` for `Level` to allow parsing levels from strings.
- Updated the documentation for `Metadata` to better explain how it's used.

## [0.24.0] - 2024-10-12

### Added
Expand Down
88 changes: 84 additions & 4 deletions metrics/src/metadata.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/// Describes the level of verbosity of a metric event.
#[derive(Debug, Clone, PartialEq, Eq)]
/// Verbosity of a metric.
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd)]
pub struct Level(LevelInner);

impl Level {
Expand All @@ -19,7 +19,22 @@ impl Level {
pub const ERROR: Self = Self(LevelInner::Error);
}

#[derive(Debug, Clone, PartialEq, Eq)]
impl std::convert::TryFrom<&str> for Level {
type Error = String;

fn try_from(value: &str) -> Result<Self, Self::Error> {
match value.trim() {
"trace" | "TRACE" => Ok(Level::TRACE),
"debug" | "DEBUG" => Ok(Level::DEBUG),
"info" | "INFO" => Ok(Level::INFO),
"warn" | "WARN" => Ok(Level::WARN),
"error" | "ERROR" => Ok(Level::ERROR),
unknown => Err(format!("unknown log level: {} (expected one of 'trace', 'debug', 'info', 'warn', or 'error')", unknown)),
}
}
}

#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
enum LevelInner {
Trace = 0,
Debug = 1,
Expand All @@ -44,7 +59,7 @@ enum LevelInner {
///
/// Metadata usage is exporter-specific, and may be ignored entirely. See the documentation of the specific exporter
/// being used for more information.
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Metadata<'a> {
target: &'a str,
level: Level,
Expand Down Expand Up @@ -77,3 +92,68 @@ impl<'a> Metadata<'a> {
self.module_path
}
}

#[cfg(test)]
mod tests {
use std::convert::TryFrom as _;

use super::*;

#[test]
fn level_try_from_valid() {
let cases = &[
("trace", Level::TRACE), ("TRACE", Level::TRACE),
("debug", Level::DEBUG), ("DEBUG", Level::DEBUG),
("info", Level::INFO), ("INFO", Level::INFO),
("warn", Level::WARN), ("WARN", Level::WARN),
("error", Level::ERROR), ("ERROR", Level::ERROR),
];

for (input, expected) in cases {
assert_eq!(Level::try_from(*input).unwrap(), *expected);

// Now try with some whitespace on either end.
let input_whitespace = format!(" {} ", input);
assert_eq!(Level::try_from(&*input_whitespace).unwrap(), *expected);
}
}

#[test]
fn level_try_from_invalid() {
let cases = &["", "foo", "bar", "baz", "qux", "quux"];

for input in cases {
assert!(Level::try_from(*input).is_err());
}
}

#[test]
fn level_ordering() {
// A few manual comparisons because it makes me feel better:
assert!(Level::TRACE < Level::DEBUG);
assert!(Level::DEBUG < Level::INFO);
assert!(Level::ERROR > Level::DEBUG);
assert!(Level::WARN == Level::WARN);

// Now check each level programmatically.
let levels = &[
Level::TRACE, Level::DEBUG, Level::INFO, Level::WARN, Level::ERROR,
];

for i in 0..levels.len() {
let current_level = levels[i];
let lower_levels = &levels[..i];
let higher_levels = &levels[i + 1..];

for lower_level in lower_levels {
assert!(current_level > *lower_level);
assert!(*lower_level < current_level);
}

for higher_level in higher_levels {
assert!(current_level < *higher_level);
assert!(*higher_level > current_level);
}
}
}
}

0 comments on commit f289050

Please sign in to comment.