6565//! // a_histogram_bucket{key="value",otel_scope_name="my-app",le="+Inf"} 1
6666//! // a_histogram_sum{key="value",otel_scope_name="my-app"} 100
6767//! // a_histogram_count{key="value",otel_scope_name="my-app"} 1
68- //! // # HELP otel_scope_info Instrumentation Scope metadata
69- //! // # TYPE otel_scope_info gauge
70- //! // otel_scope_info{otel_scope_name="my-app"} 1
7168//! // # HELP target_info Target metadata
7269//! // # TYPE target_info gauge
7370//! // target_info{service_name="unknown_service"} 1
@@ -114,10 +111,15 @@ use std::{fmt, sync::Weak};
114111const TARGET_INFO_NAME : & str = "target_info" ;
115112const TARGET_INFO_DESCRIPTION : & str = "Target metadata" ;
116113
117- const SCOPE_INFO_METRIC_NAME : & str = "otel_scope_info" ;
118- const SCOPE_INFO_DESCRIPTION : & str = "Instrumentation Scope metadata" ;
119-
120- const SCOPE_INFO_KEYS : [ & str ; 2 ] = [ "otel_scope_name" , "otel_scope_version" ] ;
114+ const SCOPE_NAME_LABEL : & str = "otel_scope_name" ;
115+ const SCOPE_VERSION_LABEL : & str = "otel_scope_version" ;
116+ const SCOPE_SCHEMA_URL_LABEL : & str = "otel_scope_schema_url" ;
117+ const SCOPE_ATTRIBUTE_PREFIX : & str = "otel_scope_" ;
118+ const RESERVED_SCOPE_LABELS : [ & str ; 3 ] = [
119+ SCOPE_NAME_LABEL ,
120+ SCOPE_VERSION_LABEL ,
121+ SCOPE_SCHEMA_URL_LABEL ,
122+ ] ;
121123
122124// prometheus counters MUST have a _total suffix by default:
123125// https://github.com/open-telemetry/opentelemetry-specification/blob/v1.20.0/specification/compatibility/prometheus_and_openmetrics.md
@@ -170,7 +172,7 @@ struct Collector {
170172 disable_target_info : bool ,
171173 without_units : bool ,
172174 without_counter_suffixes : bool ,
173- disable_scope_info : bool ,
175+ scope_info_enabled : bool ,
174176 create_target_info_once : OnceCell < MetricFamily > ,
175177 resource_labels_once : OnceCell < Vec < LabelPair > > ,
176178 namespace : Option < String > ,
@@ -180,7 +182,6 @@ struct Collector {
180182
181183#[ derive( Default ) ]
182184struct CollectorInner {
183- scope_infos : HashMap < InstrumentationScope , MetricFamily > ,
184185 metric_families : HashMap < String , MetricFamily > ,
185186}
186187
@@ -301,27 +302,8 @@ impl prometheus::core::Collector for Collector {
301302 . get_or_init ( || self . resource_selector . select ( metrics. resource ( ) ) ) ;
302303
303304 for scope_metrics in metrics. scope_metrics ( ) {
304- let scope_labels = if !self . disable_scope_info {
305- if scope_metrics. scope ( ) . attributes ( ) . count ( ) > 0 {
306- let scope_info = inner
307- . scope_infos
308- . entry ( scope_metrics. scope ( ) . clone ( ) )
309- . or_insert_with_key ( create_scope_info_metric) ;
310- res. push ( scope_info. clone ( ) ) ;
311- }
312-
313- let mut labels =
314- Vec :: with_capacity ( 1 + scope_metrics. scope ( ) . version ( ) . is_some ( ) as usize ) ;
315- let mut name = LabelPair :: default ( ) ;
316- name. set_name ( SCOPE_INFO_KEYS [ 0 ] . into ( ) ) ;
317- name. set_value ( scope_metrics. scope ( ) . name ( ) . to_string ( ) ) ;
318- labels. push ( name) ;
319- if let Some ( version) = & scope_metrics. scope ( ) . version ( ) {
320- let mut l_version = LabelPair :: default ( ) ;
321- l_version. set_name ( SCOPE_INFO_KEYS [ 1 ] . into ( ) ) ;
322- l_version. set_value ( version. to_string ( ) ) ;
323- labels. push ( l_version) ;
324- }
305+ let scope_labels = if self . scope_info_enabled {
306+ let mut labels = get_scope_labels ( scope_metrics. scope ( ) ) ;
325307
326308 if !resource_labels. is_empty ( ) {
327309 labels. extend ( resource_labels. iter ( ) . cloned ( ) ) ;
@@ -422,6 +404,48 @@ fn get_attrs(kvs: &mut dyn Iterator<Item = (&Key, &Value)>, extra: &[LabelPair])
422404 res
423405}
424406
407+ fn get_scope_labels ( scope : & InstrumentationScope ) -> Vec < LabelPair > {
408+ let mut labels = Vec :: with_capacity (
409+ 1 + scope. version ( ) . is_some ( ) as usize
410+ + scope. schema_url ( ) . is_some ( ) as usize
411+ + scope. attributes ( ) . count ( ) ,
412+ ) ;
413+ labels. push ( label_pair ( SCOPE_NAME_LABEL , scope. name ( ) ) ) ;
414+
415+ if let Some ( version) = scope. version ( ) {
416+ labels. push ( label_pair ( SCOPE_VERSION_LABEL , version) ) ;
417+ }
418+
419+ if let Some ( schema_url) = scope. schema_url ( ) {
420+ labels. push ( label_pair ( SCOPE_SCHEMA_URL_LABEL , schema_url) ) ;
421+ }
422+
423+ let mut attr_labels = BTreeMap :: < String , Vec < String > > :: new ( ) ;
424+ for kv in scope. attributes ( ) {
425+ let label_name = utils:: sanitize_prom_kv ( & format ! ( "{SCOPE_ATTRIBUTE_PREFIX}{}" , kv. key) ) ;
426+ if RESERVED_SCOPE_LABELS . contains ( & label_name. as_str ( ) ) {
427+ continue ;
428+ }
429+ attr_labels
430+ . entry ( label_name)
431+ . and_modify ( |values| values. push ( kv. value . to_string ( ) ) )
432+ . or_insert_with ( || vec ! [ kv. value. to_string( ) ] ) ;
433+ }
434+
435+ for ( label_name, values) in attr_labels {
436+ labels. push ( label_pair ( label_name, values. join ( ";" ) ) ) ;
437+ }
438+
439+ labels
440+ }
441+
442+ fn label_pair ( name : impl Into < String > , value : impl Into < String > ) -> LabelPair {
443+ let mut label = LabelPair :: default ( ) ;
444+ label. set_name ( name. into ( ) ) ;
445+ label. set_value ( value. into ( ) ) ;
446+ label
447+ }
448+
425449fn validate_metrics (
426450 name : & str ,
427451 description : & str ,
@@ -585,34 +609,6 @@ fn create_info_metric(
585609 mf
586610}
587611
588- fn create_scope_info_metric ( scope : & InstrumentationScope ) -> MetricFamily {
589- let mut g = prometheus:: proto:: Gauge :: default ( ) ;
590- g. set_value ( 1.0 ) ;
591-
592- let mut labels = Vec :: with_capacity ( 1 + scope. version ( ) . is_some ( ) as usize ) ;
593- let mut name = LabelPair :: default ( ) ;
594- name. set_name ( SCOPE_INFO_KEYS [ 0 ] . into ( ) ) ;
595- name. set_value ( scope. name ( ) . to_string ( ) ) ;
596- labels. push ( name) ;
597- if let Some ( version) = & scope. version ( ) {
598- let mut v_label = LabelPair :: default ( ) ;
599- v_label. set_name ( SCOPE_INFO_KEYS [ 1 ] . into ( ) ) ;
600- v_label. set_value ( version. to_string ( ) ) ;
601- labels. push ( v_label) ;
602- }
603-
604- let mut m = prometheus:: proto:: Metric :: default ( ) ;
605- m. set_label ( labels) ;
606- m. set_gauge ( g) ;
607-
608- let mut mf = MetricFamily :: default ( ) ;
609- mf. set_name ( SCOPE_INFO_METRIC_NAME . into ( ) ) ;
610- mf. set_help ( SCOPE_INFO_DESCRIPTION . into ( ) ) ;
611- mf. set_field_type ( MetricType :: GAUGE ) ;
612- mf. set_metric ( vec ! [ m] ) ;
613- mf
614- }
615-
616612trait Numeric : fmt:: Debug {
617613 // lossy at large values for u64 and i64 but prometheus only handles floats
618614 fn as_f64 ( & self ) -> f64 ;
0 commit comments