| Crates.io | simple-metrics |
| lib.rs | simple-metrics |
| version | 0.4.1 |
| created_at | 2025-11-07 23:36:50.371429+00 |
| updated_at | 2025-11-07 23:36:50.371429+00 |
| description | Library to flexibly render Prometheus metrics |
| homepage | |
| repository | https://github.com/qezz/simple-metrics |
| max_upload_size | |
| id | 1922340 |
| size | 221,027 |
The library allows to render Prometheus metrics in a more flexible way compared to other implementations.
Simple metrics library provides a very opinionated way on how things should be or can be done. It comes from author's experience with Prometheus client libraries and various exporters.
Goals:
Non goals:
You might find this library useful if you run multiple independent workers that should serve different sets of metrics. The workers in this case can have domain specific metrics, and are not limited to a single format.
Because there's no global registry, and because the metrics are data-driven, it becomes relatively easy to test your application. See unit tests in the code, examples, or keep reading for a simple demo.
In order to render metrics, you need to have an enum, every variant
of which represents a separate metric group.
#[derive(Eq, Hash, PartialEq, Ord, PartialOrd)]
pub enum ServiceMetric {
WorkerHealth,
ServiceHeight,
}
impl ToMetricDef for ServiceMetric {
fn to_metric_def(&self) -> MetricDef {
match self {
ServiceMetric::WorkerHealth => {
MetricDef::new("worker_health", "worker health", MetricType::Gauge).unwrap()
}
ServiceMetric::ServiceHeight => {
MetricDef::new("service_height", "service height", MetricType::Gauge).unwrap()
}
}
}
}
Since the workers can produce metrics on their own, it's easy to aggregate the result in order to serve all the metrics via an endpoint.
A simple example on how to convert a list of states into metrics:
pub struct State {
name: String,
health: bool,
height: i64,
}
let states = vec![
SimpleState {
name: "a".into(),
health: true,
height: 100,
},
SimpleState {
name: "b".into(),
health: false,
height: 200,
},
];
let mut static_labels = LabelsBuilder::new()
.with("process", "simple-metrics")
.build()
.expect("invalid label names");
let mut store: MetricStore<ServiceMetric> =
MetricStore::new().with_static_labels(static_labels);
for s in states {
let mut common = LabelsBuilder::new()
.with("name", s.name)
.build()
.expect("invalid label names");
store.add_sample(
ServiceMetric::WorkerHealth,
Sample::new(&common, s.health)
);
store.add_value(ServiceMetric::ServiceHeight, &common, s.height);
}
let actual = store.render_into_metrics(Some("namespace"));
println!("{}", actual);
let expected = r#"# HELP worker_health worker health
# TYPE worker_health gauge
namespace_worker_health{name="a",process="simple-metrics"} 1
namespace_worker_health{name="b",process="simple-metrics"} 0
# HELP service_height service height
# TYPE service_height gauge
namespace_service_height{name="a",process="simple-metrics"} 100
namespace_service_height{name="b",process="simple-metrics"} 200
"#;
assert_eq!(actual, expected);
MIT or Apache-2, at your choice.
Sergei Mishin