#prometheus #metrics

aetos

A Rust proc macro library for generating Prometheus metrics rendering code from annotated structs

2 releases

Uses new Rust 2024

0.1.1 Jan 6, 2026
0.1.0 Nov 25, 2025

#498 in Procedural macros

MIT license

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: K implements Display
  • Multiple labels: K implements Label

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