diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fdec075d..206c0e828 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - Updated to rand 0.10.x +- Added `unique_tag_ratio` field to the OpenTelemetry metrics `Contexts` config, allowing control over attribute cardinality. Defaults to `0.75`; set to `1.0` for fully unique attributes on every emission. ## [0.32.0] ## Changed diff --git a/lading_payload/benches/opentelemetry_metric.rs b/lading_payload/benches/opentelemetry_metric.rs index 587ebeb3a..6e8902e03 100644 --- a/lading_payload/benches/opentelemetry_metric.rs +++ b/lading_payload/benches/opentelemetry_metric.rs @@ -28,6 +28,7 @@ fn opentelemetry_metric_setup(c: &mut Criterion) { attributes_per_scope: ConfRange::Inclusive { min: 0, max: 4 }, metrics_per_scope: ConfRange::Inclusive { min: 1, max: 128 }, attributes_per_metric: ConfRange::Inclusive { min: 0, max: 255 }, + unique_tag_ratio: 0.75, }, }; let _ot = OpentelemetryMetrics::new(config, MIB, &mut rng) @@ -57,6 +58,7 @@ fn opentelemetry_metric_throughput(c: &mut Criterion) { attributes_per_scope: ConfRange::Inclusive { min: 0, max: 4 }, metrics_per_scope: ConfRange::Inclusive { min: 1, max: 128 }, attributes_per_metric: ConfRange::Inclusive { min: 0, max: 255 }, + unique_tag_ratio: 0.75, }, }; let ot = OpentelemetryMetrics::new(config, size, &mut rng) diff --git a/lading_payload/src/opentelemetry/metric.rs b/lading_payload/src/opentelemetry/metric.rs index 609aa5767..b56cf72e6 100644 --- a/lading_payload/src/opentelemetry/metric.rs +++ b/lading_payload/src/opentelemetry/metric.rs @@ -84,6 +84,10 @@ pub struct Contexts { pub metrics_per_scope: ConfRange, /// The range of attributes for each metric. pub attributes_per_metric: ConfRange, + /// Fraction of attributes that are unique vs. reused. 1.0 means every + /// attribute is unique; 0.01 means nearly all attributes are reused from + /// the existing pool. Valid range: 0.01 to 1.0. + pub unique_tag_ratio: f32, } impl Default for Contexts { @@ -95,6 +99,7 @@ impl Default for Contexts { attributes_per_scope: ConfRange::Constant(0), metrics_per_scope: ConfRange::Inclusive { min: 1, max: 20 }, attributes_per_metric: ConfRange::Inclusive { min: 0, max: 10 }, + unique_tag_ratio: 0.75, } } } @@ -220,6 +225,10 @@ impl Config { return Err("attributes_per_metric minimum cannot be greater than maximum".to_string()); } + if !(0.01_f32..=1.0_f32).contains(&self.contexts.unique_tag_ratio) { + return Err("unique_tag_ratio must be between 0.01 and 1.0".to_string()); + } + let min_contexts = match self.contexts.total_contexts { ConfRange::Constant(n) => n, ConfRange::Inclusive { min, .. } => min, @@ -570,6 +579,7 @@ mod test { attributes_per_scope: ConfRange::Constant(attributes_per_scope), metrics_per_scope: ConfRange::Constant(metrics_per_scope), attributes_per_metric: ConfRange::Constant(attributes_per_metric), + unique_tag_ratio: 0.75, }, ..Default::default() }; @@ -614,6 +624,7 @@ mod test { attributes_per_scope: ConfRange::Constant(attributes_per_scope), metrics_per_scope: ConfRange::Constant(metrics_per_scope), attributes_per_metric: ConfRange::Constant(attributes_per_metric), + unique_tag_ratio: 0.75, }, ..Default::default() }; @@ -661,6 +672,7 @@ mod test { attributes_per_scope: ConfRange::Constant(attributes_per_scope), metrics_per_scope: ConfRange::Constant(metrics_per_scope), attributes_per_metric: ConfRange::Constant(attributes_per_metric), + unique_tag_ratio: 0.75, }, ..Default::default() }; @@ -707,6 +719,7 @@ mod test { attributes_per_scope: ConfRange::Constant(attributes_per_scope), metrics_per_scope: ConfRange::Constant(metrics_per_scope), attributes_per_metric: ConfRange::Constant(attributes_per_metric), + unique_tag_ratio: 0.75, }, ..Default::default() }; @@ -739,6 +752,7 @@ mod test { attributes_per_scope: ConfRange::Constant(1), metrics_per_scope: ConfRange::Constant(3), attributes_per_metric: ConfRange::Constant(2), + unique_tag_ratio: 0.75, }, ..Default::default() }; @@ -782,6 +796,7 @@ mod test { attributes_per_scope: ConfRange::Constant(attributes_per_scope), metrics_per_scope: ConfRange::Constant(metrics_per_scope), attributes_per_metric: ConfRange::Constant(attributes_per_metric), + unique_tag_ratio: 0.75, }, ..Default::default() }; @@ -926,6 +941,7 @@ mod test { attributes_per_scope: ConfRange::Constant(attributes_per_scope), metrics_per_scope: ConfRange::Constant(metrics_per_scope), attributes_per_metric: ConfRange::Constant(attributes_per_metric), + unique_tag_ratio: 0.75, }, ..Default::default() }; @@ -973,6 +989,7 @@ mod test { attributes_per_scope: ConfRange::Constant(attributes_per_scope), metrics_per_scope: ConfRange::Constant(metrics_per_scope), attributes_per_metric: ConfRange::Constant(attributes_per_metric), + unique_tag_ratio: 0.75, }, ..Default::default() }; @@ -1055,6 +1072,7 @@ mod test { attributes_per_scope: ConfRange::Constant(attributes_per_scope), metrics_per_scope: ConfRange::Constant(metrics_per_scope), attributes_per_metric: ConfRange::Constant(attributes_per_metric), + unique_tag_ratio: 0.75, }, metric_weights: super::MetricWeights { gauge: 0, // Only generate sum metrics @@ -1095,6 +1113,7 @@ mod test { attributes_per_scope: ConfRange::Constant(attributes_per_scope), metrics_per_scope: ConfRange::Constant(metrics_per_scope), attributes_per_metric: ConfRange::Constant(attributes_per_metric), + unique_tag_ratio: 0.75, }, metric_weights: super::MetricWeights { gauge: 0, // Only generate sum metrics @@ -1217,6 +1236,7 @@ mod test { attributes_per_scope: ConfRange::Constant(0), metrics_per_scope: ConfRange::Inclusive { min: 1, max: 20 }, attributes_per_metric: ConfRange::Inclusive { min: 0, max: 10 }, + unique_tag_ratio: 0.75, }, ..Default::default() }; diff --git a/lading_payload/src/opentelemetry/metric/templates.rs b/lading_payload/src/opentelemetry/metric/templates.rs index 997ef9213..9a9effb37 100644 --- a/lading_payload/src/opentelemetry/metric/templates.rs +++ b/lading_payload/src/opentelemetry/metric/templates.rs @@ -18,7 +18,7 @@ use rand::{ use tracing::debug; use super::{Config, UnitGenerator}; -use crate::opentelemetry::common::{GeneratorError, TagGenerator, UNIQUE_TAG_RATIO, templates}; +use crate::opentelemetry::common::{GeneratorError, TagGenerator, templates}; use crate::{Error, Generator, common::config::ConfRange, common::strings}; pub(crate) type Pool = templates::Pool; @@ -104,7 +104,7 @@ impl MetricTemplateGenerator { ConfRange::Inclusive { min: 3, max: 32 }, config.contexts.total_contexts.end() as usize, str_pool, - UNIQUE_TAG_RATIO, + config.contexts.unique_tag_ratio, )?; Ok(Self { @@ -307,7 +307,7 @@ impl ScopeTemplateGenerator { ConfRange::Inclusive { min: 3, max: 32 }, config.contexts.total_contexts.end() as usize, str_pool, - UNIQUE_TAG_RATIO, + config.contexts.unique_tag_ratio, )?; Ok(Self { @@ -425,7 +425,7 @@ impl ResourceTemplateGenerator { ConfRange::Inclusive { min: 3, max: 32 }, config.contexts.total_contexts.end() as usize, &Rc::clone(str_pool), - UNIQUE_TAG_RATIO, + config.contexts.unique_tag_ratio, )?; Ok(Self {