Skip to content

Commit

Permalink
feat(encoding): new parts::* functions to compose cross-registry re…
Browse files Browse the repository at this point in the history
…sponses

Signed-off-by: Adam Cimarosti <[email protected]>
  • Loading branch information
amunra committed Nov 8, 2023
1 parent 23c31bd commit 6e3eec1
Showing 1 changed file with 86 additions and 3 deletions.
89 changes: 86 additions & 3 deletions src/encoding/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,98 @@ use std::borrow::Cow;
use std::collections::HashMap;
use std::fmt::Write;

/// Functions to encode metrics to the OpenMetrics text format in parts.
/// Useful when assembling metrics from multiple registries.
/// Prefer calling [`encode`](encode) when encoding a single registry.
///
/// Here is a simple example:
/// ```
/// # use prometheus_client::encoding::text::parts;
/// # use prometheus_client::metrics::counter::Counter;
/// # use prometheus_client::metrics::histogram::{Histogram, exponential_buckets};
/// # use prometheus_client::registry::Registry;
/// #
/// # fn main() -> Result<(), std::fmt::Error> {
/// let mut orders_registry = Registry::default();
/// let total_orders: Counter<u64> = Default::default();
/// let processing_times = Histogram::new(exponential_buckets(1.0, 2.0, 10));
/// orders_registry.register(
/// "total_orders",
/// "Total orders received",
/// total_orders.clone(),
/// );
/// orders_registry.register(
/// "processing_times",
/// "Millisecond order times",
/// processing_times.clone(),
/// );
///
/// total_orders.inc();
/// processing_times.observe(2.4);
///
/// let mut user_auth_registry = Registry::default();
/// let successful_logins: Counter<u64> = Default::default();
/// let failed_logins: Counter<u64> = Default::default();
/// user_auth_registry.register(
/// "successful_logins",
/// "Total successful logins",
/// successful_logins.clone(),
/// );
/// user_auth_registry.register(
/// "failed_logins",
/// "Total failed logins",
/// failed_logins.clone(),
/// );
///
/// successful_logins.inc();
///
/// let mut response = String::new();
/// parts::encode_registry(&mut response, &orders_registry)?;
/// # assert_eq!(&response[response.len() - 20..], "bucket{le=\"+Inf\"} 1\n");
/// parts::encode_registry(&mut response, &user_auth_registry)?;
/// # assert_eq!(&response[response.len() - 20..], "iled_logins_total 0\n");
/// parts::encode_end(&mut response)?;
/// # assert_eq!(&response[response.len() - 20..], "ogins_total 0\n# EOF\n");
/// # Ok(())
/// # }
pub mod parts {
use crate::encoding::text::DescriptorEncoder;
use crate::registry::Registry;
use std::fmt::Write;

/// Encode the metrics registered with the provided
/// [`Registry`] into the provided [`Write`]r using the OpenMetrics text
/// format.
/// Can call repeatedly for the same response, then finish with a
/// call to [`encode_end`](encode_end) to end the response.
pub fn encode_registry<W>(writer: &mut W, registry: &Registry) -> Result<(), std::fmt::Error>
where
W: Write,
{
registry.encode(&mut DescriptorEncoder::new(writer).into())?;
Ok(())
}

/// Encode the end of the response.
/// Must be called after one or more calls to [`encode_registry`](encode_registry)
/// to ensure protocol compliance.
pub fn encode_end<W>(writer: &mut W) -> Result<(), std::fmt::Error>
where
W: Write,
{
writer.write_str("# EOF\n")?;
Ok(())
}
}

/// Encode the metrics registered with the provided [`Registry`] into the
/// provided [`Write`]r using the OpenMetrics text format.
pub fn encode<W>(writer: &mut W, registry: &Registry) -> Result<(), std::fmt::Error>
where
W: Write,
{
registry.encode(&mut DescriptorEncoder::new(writer).into())?;
writer.write_str("# EOF\n")?;
Ok(())
parts::encode_registry(writer, registry)?;
parts::encode_end(writer)
}

pub(crate) struct DescriptorEncoder<'a> {
Expand Down

0 comments on commit 6e3eec1

Please sign in to comment.