-
Notifications
You must be signed in to change notification settings - Fork 677
feat: Implement scope_info_enabled #3503
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
7892625
aaac0ea
623c125
979a0d4
b77e988
41d9db6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -65,9 +65,6 @@ | |
| //! // a_histogram_bucket{key="value",otel_scope_name="my-app",le="+Inf"} 1 | ||
| //! // a_histogram_sum{key="value",otel_scope_name="my-app"} 100 | ||
| //! // a_histogram_count{key="value",otel_scope_name="my-app"} 1 | ||
| //! // # HELP otel_scope_info Instrumentation Scope metadata | ||
| //! // # TYPE otel_scope_info gauge | ||
| //! // otel_scope_info{otel_scope_name="my-app"} 1 | ||
| //! // # HELP target_info Target metadata | ||
| //! // # TYPE target_info gauge | ||
| //! // target_info{service_name="unknown_service"} 1 | ||
|
|
@@ -114,10 +111,15 @@ use std::{fmt, sync::Weak}; | |
| const TARGET_INFO_NAME: &str = "target_info"; | ||
| const TARGET_INFO_DESCRIPTION: &str = "Target metadata"; | ||
|
|
||
| const SCOPE_INFO_METRIC_NAME: &str = "otel_scope_info"; | ||
| const SCOPE_INFO_DESCRIPTION: &str = "Instrumentation Scope metadata"; | ||
|
|
||
| const SCOPE_INFO_KEYS: [&str; 2] = ["otel_scope_name", "otel_scope_version"]; | ||
| const SCOPE_NAME_LABEL: &str = "otel_scope_name"; | ||
| const SCOPE_VERSION_LABEL: &str = "otel_scope_version"; | ||
| const SCOPE_SCHEMA_URL_LABEL: &str = "otel_scope_schema_url"; | ||
| const SCOPE_ATTRIBUTE_PREFIX: &str = "otel_scope_"; | ||
| const RESERVED_SCOPE_LABELS: [&str; 3] = [ | ||
| SCOPE_NAME_LABEL, | ||
| SCOPE_VERSION_LABEL, | ||
| SCOPE_SCHEMA_URL_LABEL, | ||
| ]; | ||
|
|
||
| // prometheus counters MUST have a _total suffix by default: | ||
| // https://github.com/open-telemetry/opentelemetry-specification/blob/v1.20.0/specification/compatibility/prometheus_and_openmetrics.md | ||
|
|
@@ -170,7 +172,7 @@ struct Collector { | |
| disable_target_info: bool, | ||
| without_units: bool, | ||
| without_counter_suffixes: bool, | ||
| disable_scope_info: bool, | ||
| scope_info_enabled: bool, | ||
| create_target_info_once: OnceCell<MetricFamily>, | ||
| resource_labels_once: OnceCell<Vec<LabelPair>>, | ||
| namespace: Option<String>, | ||
|
|
@@ -180,7 +182,6 @@ struct Collector { | |
|
|
||
| #[derive(Default)] | ||
| struct CollectorInner { | ||
| scope_infos: HashMap<InstrumentationScope, MetricFamily>, | ||
| metric_families: HashMap<String, MetricFamily>, | ||
| } | ||
|
|
||
|
|
@@ -301,27 +302,8 @@ impl prometheus::core::Collector for Collector { | |
| .get_or_init(|| self.resource_selector.select(metrics.resource())); | ||
|
|
||
| for scope_metrics in metrics.scope_metrics() { | ||
| let scope_labels = if !self.disable_scope_info { | ||
| if scope_metrics.scope().attributes().count() > 0 { | ||
| let scope_info = inner | ||
| .scope_infos | ||
| .entry(scope_metrics.scope().clone()) | ||
| .or_insert_with_key(create_scope_info_metric); | ||
| res.push(scope_info.clone()); | ||
| } | ||
|
|
||
| let mut labels = | ||
| Vec::with_capacity(1 + scope_metrics.scope().version().is_some() as usize); | ||
| let mut name = LabelPair::default(); | ||
| name.set_name(SCOPE_INFO_KEYS[0].into()); | ||
| name.set_value(scope_metrics.scope().name().to_string()); | ||
| labels.push(name); | ||
| if let Some(version) = &scope_metrics.scope().version() { | ||
| let mut l_version = LabelPair::default(); | ||
| l_version.set_name(SCOPE_INFO_KEYS[1].into()); | ||
| l_version.set_value(version.to_string()); | ||
| labels.push(l_version); | ||
| } | ||
| let scope_labels = if self.scope_info_enabled { | ||
| let mut labels = get_scope_labels(scope_metrics.scope()); | ||
|
|
||
| if !resource_labels.is_empty() { | ||
| labels.extend(resource_labels.iter().cloned()); | ||
|
|
@@ -422,6 +404,48 @@ fn get_attrs(kvs: &mut dyn Iterator<Item = (&Key, &Value)>, extra: &[LabelPair]) | |
| res | ||
| } | ||
|
|
||
| fn get_scope_labels(scope: &InstrumentationScope) -> Vec<LabelPair> { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. existing bug - I don't think we are handling the collision when scope_name (etc.) and metric attributes are same. Just noting , not blocker for this PR but a good follow up.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting, I have never seen a metric attribute with the
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the spec calls out this possibility and tells us what to do. We need to follow that. (of course in a future PR) |
||
| let mut labels = Vec::with_capacity( | ||
| 1 + scope.version().is_some() as usize | ||
| + scope.schema_url().is_some() as usize | ||
| + scope.attributes().count(), | ||
| ); | ||
| labels.push(label_pair(SCOPE_NAME_LABEL, scope.name())); | ||
|
|
||
| if let Some(version) = scope.version() { | ||
| labels.push(label_pair(SCOPE_VERSION_LABEL, version)); | ||
| } | ||
|
|
||
| if let Some(schema_url) = scope.schema_url() { | ||
| labels.push(label_pair(SCOPE_SCHEMA_URL_LABEL, schema_url)); | ||
| } | ||
|
|
||
| let mut attr_labels = BTreeMap::<String, Vec<String>>::new(); | ||
| for kv in scope.attributes() { | ||
| let label_name = utils::sanitize_prom_kv(&format!("{SCOPE_ATTRIBUTE_PREFIX}{}", kv.key)); | ||
| if RESERVED_SCOPE_LABELS.contains(&label_name.as_str()) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good for followup - we can check if the attribute is one of name/version/schema_url before allocating the label_name by invoking |
||
| continue; | ||
| } | ||
| attr_labels | ||
| .entry(label_name) | ||
| .and_modify(|values| values.push(kv.value.to_string())) | ||
| .or_insert_with(|| vec![kv.value.to_string()]); | ||
| } | ||
|
|
||
| for (label_name, values) in attr_labels { | ||
| labels.push(label_pair(label_name, values.join(";"))); | ||
| } | ||
|
|
||
| labels | ||
| } | ||
|
|
||
| fn label_pair(name: impl Into<String>, value: impl Into<String>) -> LabelPair { | ||
| let mut label = LabelPair::default(); | ||
| label.set_name(name.into()); | ||
| label.set_value(value.into()); | ||
| label | ||
| } | ||
|
|
||
| fn validate_metrics( | ||
| name: &str, | ||
| description: &str, | ||
|
|
@@ -585,34 +609,6 @@ fn create_info_metric( | |
| mf | ||
| } | ||
|
|
||
| fn create_scope_info_metric(scope: &InstrumentationScope) -> MetricFamily { | ||
| let mut g = prometheus::proto::Gauge::default(); | ||
| g.set_value(1.0); | ||
|
|
||
| let mut labels = Vec::with_capacity(1 + scope.version().is_some() as usize); | ||
| let mut name = LabelPair::default(); | ||
| name.set_name(SCOPE_INFO_KEYS[0].into()); | ||
| name.set_value(scope.name().to_string()); | ||
| labels.push(name); | ||
| if let Some(version) = &scope.version() { | ||
| let mut v_label = LabelPair::default(); | ||
| v_label.set_name(SCOPE_INFO_KEYS[1].into()); | ||
| v_label.set_value(version.to_string()); | ||
| labels.push(v_label); | ||
| } | ||
|
|
||
| let mut m = prometheus::proto::Metric::default(); | ||
| m.set_label(labels); | ||
| m.set_gauge(g); | ||
|
|
||
| let mut mf = MetricFamily::default(); | ||
| mf.set_name(SCOPE_INFO_METRIC_NAME.into()); | ||
| mf.set_help(SCOPE_INFO_DESCRIPTION.into()); | ||
| mf.set_field_type(MetricType::GAUGE); | ||
| mf.set_metric(vec![m]); | ||
| mf | ||
| } | ||
|
|
||
| trait Numeric: fmt::Debug { | ||
| // lossy at large values for u64 and i64 but prometheus only handles floats | ||
| fn as_f64(&self) -> f64; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,7 @@ | ||
| # HELP bar_bytes_total meter a bar | ||
| # TYPE bar_bytes_total counter | ||
| bar_bytes_total{type="bar",otel_scope_name="ma",otel_scope_version="v0.1.0"} 100 | ||
| bar_bytes_total{type="bar",otel_scope_name="mb",otel_scope_version="v0.1.0"} 100 | ||
| # HELP otel_scope_info Instrumentation Scope metadata | ||
| # TYPE otel_scope_info gauge | ||
| otel_scope_info{otel_scope_name="ma",otel_scope_version="v0.1.0"} 1 | ||
| otel_scope_info{otel_scope_name="mb",otel_scope_version="v0.1.0"} 1 | ||
| bar_bytes_total{type="bar",otel_scope_name="ma",otel_scope_version="v0.1.0",otel_scope_schema_url="https://opentelemetry.io/schemas/1.0.0",otel_scope_k="v"} 100 | ||
| bar_bytes_total{type="bar",otel_scope_name="mb",otel_scope_version="v0.1.0",otel_scope_schema_url="https://opentelemetry.io/schemas/1.0.0",otel_scope_k="v"} 100 | ||
| # HELP target_info Target metadata | ||
| # TYPE target_info gauge | ||
| target_info{service_name="prometheus_test",telemetry_sdk_language="rust",telemetry_sdk_name="opentelemetry",telemetry_sdk_version="latest"} 1 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,7 @@ | ||
| # HELP bar_bytes_total meter b bar | ||
| # TYPE bar_bytes_total counter | ||
| bar_bytes_total{type="bar",otel_scope_name="ma",otel_scope_version="v0.1.0"} 100 | ||
| bar_bytes_total{type="bar",otel_scope_name="mb",otel_scope_version="v0.1.0"} 100 | ||
| # HELP otel_scope_info Instrumentation Scope metadata | ||
| # TYPE otel_scope_info gauge | ||
| otel_scope_info{otel_scope_name="ma",otel_scope_version="v0.1.0"} 1 | ||
| otel_scope_info{otel_scope_name="mb",otel_scope_version="v0.1.0"} 1 | ||
| bar_bytes_total{type="bar",otel_scope_name="ma",otel_scope_version="v0.1.0",otel_scope_schema_url="https://opentelemetry.io/schemas/1.0.0",otel_scope_k="v"} 100 | ||
| bar_bytes_total{type="bar",otel_scope_name="mb",otel_scope_version="v0.1.0",otel_scope_schema_url="https://opentelemetry.io/schemas/1.0.0",otel_scope_k="v"} 100 | ||
| # HELP target_info Target metadata | ||
| # TYPE target_info gauge | ||
| target_info{service_name="prometheus_test",telemetry_sdk_language="rust",telemetry_sdk_name="opentelemetry",telemetry_sdk_version="latest"} 1 |
Uh oh!
There was an error while loading. Please reload this page.