measured

More efficient prometheus metrics in Rust

https://github.com/conradludgate/measured

              let m_sent = NUM_BYTES_PROXIED.with_label_values(&aux.traffic_labels("tx"));
              let mut client = MeasuredStream::new(
                  client,
                  |cnt| m_sent.inc_by(cnt as u64),
              );
            

              #[derive(Debug, Deserialize, Clone, Default)]
              pub struct MetricsAuxInfo {
                  pub endpoint_id: EndpointId,
                  pub project_id: ProjectId,
                  pub branch_id: BranchId,
              }

              impl MetricsAuxInfo {
                  pub fn traffic_labels(&self, direction: &'static str) -> [&str; 4] {
                      [direction, &self.project_id, &self.endpoint_id, &self.branch_id]
                  }
              }
            

              90000 entries
              - 3 strings of 32 characters = 168 bytes
                - 24 bytes needed for String, 32 bytes for alloc
              - 1 arc of AtomicU64 = 32 bytes

              90000 * (168 + 32) = 18MB
            

              Timer precision: 10 ns
              counters              fastest       │ slowest       │ median        │ mean
              ├─ measured           22.68 ns      │ 27.49 ns      │ 23.93 ns      │ 23.9 ns
              ├─ measured_sparse    22.56 ns      │ 148.5 ns      │ 50.88 ns      │ 61.48 ns
              ├─ metrics            508.3 ns      │ 647.7 ns      │ 605.7 ns      │ 606.4 ns
              ├─ prometheus         1.547 µs      │ 1.7 µs        │ 1.657 µs      │ 1.645 µs
              ╰─ prometheus_client  2.99 µs       │ 3.38 µs       │ 3.317 µs      │ 3.262 µs
            

              enum VecInner<U: Hash + Eq> {
                  Dense(Box<[OnceLock<AtomicU64>]>),
                  Sparse(DashMap<U, AtomicU64>),
              }
            

              enum VecInner<U: Hash + Eq> {
                  Dense(Box<[CachePadded<OnceLock<AtomicU64>>]>),
                  Sparse(DashMap<U, AtomicU64>),
              }
            

              Timer precision: 10 ns
              counters     fastest       │ slowest       │ median        │ mean
              ├─ padded    67.26 ns      │ 152.2 ns      │ 142.6 ns      │ 142.3 ns
              ╰─ unpadded  133.6 ns      │ 278.8 ns      │ 265.6 ns      │ 263.1 ns
            

              enum VecInner<U: Ord + Send> {
                  Dense(Dense),
                  Sparse(DashMap<U, AtomicU64>),
              }

              struct Dense {
                  size: usize,
                  sample: Mutex<Box<[Option<u64>]>>,
                  locals: ThreadLocal<Box<[OnceLock<AtomicU64>]>>,
              }
            

              Timer precision: 10 ns
              counters   fastest       │ slowest       │ median        │ mean
              ├─ padded  67.26 ns      │ 152.2 ns      │ 142.6 ns      │ 142.3 ns
              ╰─ local   22.68 ns      │ 27.49 ns      │ 23.93 ns      │ 23.9 ns
            

              #[derive(FixedCardinalityLabel, Copy, Clone)]
              enum Operation {
                  Create,
                  Update,
                  Delete,
              }
            

              #[derive(LabelGroup)]
              #[label(set = MyLabelGroupSet)]
              struct MyLabelGroup {
                  operation: Operation,
              }
            

              #[derive(MetricGroup)]
              #[metric(new())]
              struct MyMetricGroup {
                  /// counts things
                  my_first_counter: CounterVec<MyLabelGroupSet>,
              }
            

              // create the metrics
              let metrics = MyMetricGroup::new();

              // increment the counter at a given label
              metrics.my_first_counter.inc(MyLabelGroup { operation: Operation::Create });
              metrics.my_first_counter.inc(MyLabelGroup { operation: Operation::Delete });
            

              let mut text_encoder = BufferedTextEncoder::new();
              metrics.collect_group_into(&mut text_encoder);
              let bytes = text_encoder.finish();
            

Thank you

https://github.com/conradludgate/measured