metricus 0.0.16

Low latency metrics framework.
Documentation
//! A `Counter` proxy struct for managing a metrics counter.

use crate::access::get_metrics;
use crate::{Id, MetricsHandle, Tags};
use std::ops::Deref;

/// Provides methods to create a new counter, increment it, and
/// increment it by a specified amount. It automatically deletes the counter
/// when it is dropped.
///
/// ## Examples
///
/// You can create a counter, increment it, and increment it by a specific value.
///
/// ```no_run
/// use metricus::{Counter, CounterOps};
///
/// let tags = [("service", "payment"), ("currency", "USD")];
/// let counter = Counter::new("transaction_count", &tags);
///
/// counter.increment();
/// counter.increment_by(5);
/// ```
///
/// Another option is to use `#[counter]` macro to instrument your code to automatically create
/// a static `Counter` for you.
///
/// ```no_run
/// use metricus_macros::counter;
///
/// #[counter(measurement = "counters", tags(key1 = "value1", key2 = "value2"))]
/// fn my_function_with_tags() {
///     // function body
/// }
///
/// my_function_with_tags();
/// ````
pub struct Counter {
    id: Id,
    handle: &'static MetricsHandle,
}

impl std::fmt::Debug for Counter {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Counter").field("id", &self.id).finish()
    }
}

impl Counter {
    /// Creates a new counter with the specified `name` and `tags`.
    ///
    /// ## Examples
    ///
    /// Create a counter with tags.
    /// ```no_run
    /// use metricus::Counter;
    ///
    /// let tags = [("service", "user"), ("status", "active")];
    /// let counter = Counter::new("user_count", &tags);
    /// ```
    ///
    /// Create a counter without tags.
    /// ```no_run
    /// use metricus::{empty_tags, Counter};
    ///
    /// let counter = Counter::new("user_count", empty_tags());
    /// ```
    pub fn new(name: &str, tags: Tags) -> Self {
        let metrics = get_metrics();
        let counter_id = metrics.new_counter(name, tags);
        Self {
            id: counter_id,
            handle: metrics,
        }
    }

    /// Create a counter object without registering it.
    /// This creates a new counter proxy that assumes the metrics backend has already created the counter.
    ///
    /// ## Examples
    ///
    /// Create a counter with specific id.
    ///
    /// ```no_run
    /// use metricus::Counter;
    ///
    /// let counter = Counter::new_with_id(1);
    /// ```
    pub fn new_with_id(id: Id) -> Self {
        let metrics = get_metrics();
        Self { id, handle: metrics }
    }
}

impl Drop for Counter {
    fn drop(&mut self) {
        self.handle.delete_counter(self.id);
    }
}

/// Defines a series of operations that can be performed on a `Counter`.
pub trait CounterOps {
    /// Increments the counter by 1.
    ///
    /// ## Examples
    ///
    /// ```no_run
    /// use metricus::{Counter, CounterOps};
    ///
    /// let counter = Counter::new("example_counter", &[]);
    /// counter.increment();
    /// ```
    fn increment(&self);

    /// Increments the counter by a specified amount.
    ///
    /// ## Examples
    ///
    /// ```
    /// use metricus::{Counter, CounterOps};
    ///
    /// let counter = Counter::new("example_counter", &[]);
    /// counter.increment_by(5);
    /// ```
    fn increment_by(&self, delta: u64);
}

impl CounterOps for Counter {
    #[inline]
    fn increment(&self) {
        self.handle.increment_counter(self.id);
    }

    #[inline]
    fn increment_by(&self, delta: u64) {
        self.handle.increment_counter_by(self.id, delta);
    }
}

impl<T> CounterOps for T
where
    T: Deref<Target = Counter>,
{
    #[inline]
    fn increment(&self) {
        self.deref().increment()
    }

    #[inline]
    fn increment_by(&self, delta: u64) {
        self.deref().increment_by(delta)
    }
}