2 releases
Uses new Rust 2024
| 0.1.1 | Jan 6, 2026 |
|---|---|
| 0.1.0 | Nov 25, 2025 |
#498 in Procedural macros
27KB
475 lines
Aetos
A Rust proc macro library for generating Prometheus metrics rendering code from annotated structs.
Quick Start
use aetos::{metrics, Label};
use std::collections::HashMap;
#[derive(Label)]
struct RequestLabels<'a> {
method: &'a str,
status: u32,
}
#[metrics(prefix = "myapp")] // Optional prefix for all metrics
struct MyMetrics<'a> {
// Scalar metric, no labels
#[counter(name = "requests_total", help = "Total requests")] // name is optional
requests: u64,
// HashMap metric, single label shorthand
#[counter(help = "Events by type", label = "event_type")]
events: HashMap<String, u64>,
// Vec metric, multiple labels requires a Label type
#[counter(help = "HTTP requests by method and status")]
http_requests: Vec<(RequestLabels<'a>, u64)>,
}
let metrics = MyMetrics {
requests: 1000,
events: HashMap::from([
("add".to_string(), 10),
("remove".to_string(), 5),
]),
http_requests: vec![
(RequestLabels { method: "GET", status: 200 }, 150),
(RequestLabels { method: "POST", status: 404 }, 3),
],
};
println!("{}", metrics);
This outputs:
# HELP myapp_requests_total Total requests
# TYPE myapp_requests_total counter
myapp_requests_total 1000
# HELP myapp_events Events by type
# TYPE myapp_events counter
myapp_events{event_type="add"} 10
myapp_events{event_type="remove"} 5
# HELP myapp_http_requests HTTP requests by method and status
# TYPE myapp_http_requests counter
myapp_http_requests{method="GET",status="200"} 150
myapp_http_requests{method="POST",status="404"} 3
Collection Types
Labeled metrics accept anything that implements IntoIterator<&(K, V)> or IntoIterator<(&K, &V)> (Vec, HashMap, BTreeMap, slices, etc.).
- Single label:
KimplementsDisplay - Multiple labels:
KimplementsLabel
Override Metric Names
Use the name attribute to export a different metric name than the field name (see Quick Start example).
Histograms
Histograms track value distributions across predefined buckets:
use aetos::{define_histogram, metrics, Label};
#[derive(Label, Hash, Eq, PartialEq, Clone, Debug)]
struct ResponseLabel {
endpoint: &'static str,
}
// Labeled histogram
define_histogram!(Latency<ResponseLabel> = [0.1, 0.5, 1.0, 5.0]);
// Unlabeled histogram
define_histogram!(QueueTime<()> = [0.01, 0.1, 1.0]);
#[metrics]
struct Metrics {
#[histogram(help = "Response time by endpoint")]
response_time: Latency,
#[histogram(help = "Queue wait time")]
queue_time: QueueTime,
}
let mut m = Metrics {
response_time: Latency::default(),
queue_time: QueueTime::default(),
};
m.response_time.observe(ResponseLabel { endpoint: "/api" }, 0.25);
m.queue_time.observe((), 0.05);
println!("{}", m);
If you don't want to manually specify buckets, you can use these functions to generate them
use aetos::{define_histogram, linear_buckets};
define_histogram!(RequestLatency<()> = linear_buckets::<10>(0.1, 0.1));
// Generates buckets: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
use aetos::{define_histogram, exponential_buckets};
define_histogram!(ResponseSize<()> = exponential_buckets::<8>(0.001, 2.0));
// Generates buckets: [0.001, 0.002, 0.004, 0.008, 0.016, 0.032, 0.064, 0.128]
Dependencies
~115–480KB
~11K SLoC