Skip to content

Commit bb7ad51

Browse files
authored
Merge branch 'main' into use_semantic_crate
2 parents 8cd8635 + 9f0ac7d commit bb7ad51

File tree

20 files changed

+354
-29
lines changed

20 files changed

+354
-29
lines changed

opentelemetry-otlp/src/exporter/tonic/logs.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ impl TonicLogsClient {
3333
) -> Self {
3434
let mut client = LogsServiceClient::new(channel);
3535
if let Some(compression) = compression {
36-
client = client.send_compressed(compression);
36+
client = client
37+
.send_compressed(compression)
38+
.accept_compressed(compression);
3739
}
3840

3941
TonicLogsClient {

opentelemetry-otlp/src/exporter/tonic/metrics.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ impl TonicMetricsClient {
3535
) -> Self {
3636
let mut client = MetricsServiceClient::new(channel);
3737
if let Some(compression) = compression {
38-
client = client.send_compressed(compression);
38+
client = client
39+
.send_compressed(compression)
40+
.accept_compressed(compression);
3941
}
4042

4143
TonicMetricsClient {

opentelemetry-otlp/src/exporter/tonic/trace.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ impl TonicTracesClient {
3333
) -> Self {
3434
let mut client = TraceServiceClient::new(channel);
3535
if let Some(compression) = compression {
36-
client = client.send_compressed(compression);
36+
client = client
37+
.send_compressed(compression)
38+
.accept_compressed(compression);
3739
}
3840

3941
TonicTracesClient {

opentelemetry-prometheus/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## vNext
44

5+
### Added
6+
7+
- Add `ResourceSelector` to allow attaching resource as attributes to metrics [#1608](https://github.com/open-telemetry/opentelemetry-rust/pull/1608)
8+
59
## v0.15.0
610

711
### Changed

opentelemetry-prometheus/src/config.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use opentelemetry_sdk::metrics::{
77
};
88
use std::sync::{Arc, Mutex};
99

10-
use crate::{Collector, PrometheusExporter};
10+
use crate::{Collector, PrometheusExporter, ResourceSelector};
1111

1212
/// [PrometheusExporter] configuration options
1313
#[derive(Default)]
@@ -19,6 +19,7 @@ pub struct ExporterBuilder {
1919
namespace: Option<String>,
2020
disable_scope_info: bool,
2121
reader: ManualReaderBuilder,
22+
resource_selector: ResourceSelector,
2223
}
2324

2425
impl fmt::Debug for ExporterBuilder {
@@ -114,6 +115,19 @@ impl ExporterBuilder {
114115
self
115116
}
116117

118+
/// Configures whether to export resource as attributes with every metric.
119+
///
120+
/// Note that this is orthogonal to the `target_info` metric, which can be disabled using `without_target_info`.
121+
///
122+
/// If you called `without_target_info` and `with_resource_selector` with `ResourceSelector::None`, resource will not be exported at all.
123+
pub fn with_resource_selector(
124+
mut self,
125+
resource_selector: impl Into<ResourceSelector>,
126+
) -> Self {
127+
self.resource_selector = resource_selector.into();
128+
self
129+
}
130+
117131
/// Registers an external [MetricProducer] with this reader.
118132
///
119133
/// The producer is used as a source of aggregated metric data which is
@@ -136,6 +150,8 @@ impl ExporterBuilder {
136150
create_target_info_once: OnceCell::new(),
137151
namespace: self.namespace,
138152
inner: Mutex::new(Default::default()),
153+
resource_selector: self.resource_selector,
154+
resource_labels_once: OnceCell::new(),
139155
};
140156

141157
let registry = self.registry.unwrap_or_default();

opentelemetry-prometheus/src/lib.rs

+12
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,11 @@ const SCOPE_INFO_KEYS: [&str; 2] = ["otel_scope_name", "otel_scope_version"];
132132
const COUNTER_SUFFIX: &str = "_total";
133133

134134
mod config;
135+
mod resource_selector;
135136
mod utils;
136137

137138
pub use config::ExporterBuilder;
139+
pub use resource_selector::ResourceSelector;
138140

139141
/// Creates a builder to configure a [PrometheusExporter]
140142
pub fn exporter() -> ExporterBuilder {
@@ -186,8 +188,10 @@ struct Collector {
186188
without_counter_suffixes: bool,
187189
disable_scope_info: bool,
188190
create_target_info_once: OnceCell<MetricFamily>,
191+
resource_labels_once: OnceCell<Vec<LabelPair>>,
189192
namespace: Option<String>,
190193
inner: Mutex<CollectorInner>,
194+
resource_selector: ResourceSelector,
191195
}
192196

193197
#[derive(Default)]
@@ -299,10 +303,15 @@ impl prometheus::core::Collector for Collector {
299303
// Resource should be immutable, we don't need to compute again
300304
create_info_metric(TARGET_INFO_NAME, TARGET_INFO_DESCRIPTION, &metrics.resource)
301305
});
306+
302307
if !self.disable_target_info && !metrics.resource.is_empty() {
303308
res.push(target_info.clone())
304309
}
305310

311+
let resource_labels = self
312+
.resource_labels_once
313+
.get_or_init(|| self.resource_selector.select(&metrics.resource));
314+
306315
for scope_metrics in metrics.scope_metrics {
307316
let scope_labels = if !self.disable_scope_info {
308317
if !scope_metrics.scope.attributes.is_empty() {
@@ -326,6 +335,9 @@ impl prometheus::core::Collector for Collector {
326335
labels.push(l_version);
327336
}
328337

338+
if !resource_labels.is_empty() {
339+
labels.extend(resource_labels.iter().cloned());
340+
}
329341
labels
330342
} else {
331343
Vec::new()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
use crate::get_attrs;
2+
use opentelemetry::Key;
3+
use opentelemetry_sdk::Resource;
4+
use prometheus::proto::LabelPair;
5+
use std::collections::HashSet;
6+
7+
/// `ResourceSelector` is used to select which resource to export with every metrics.
8+
///
9+
/// By default, the exporter will only export resource as `target_info` metrics but not inline in every
10+
/// metrics. You can disable this behavior by calling [`without_target_info`](crate::ExporterBuilder::without_target_info)
11+
///
12+
/// You can add resource to every metrics by set `ResourceSelector` to anything other than `None`.
13+
///
14+
/// By default, ResourceSelector is `None`, meaning resource will not be attributes of every metrics.
15+
#[derive(Debug, Default)]
16+
#[non_exhaustive]
17+
pub enum ResourceSelector {
18+
/// Export all resource attributes with every metrics.
19+
All,
20+
/// Do not export any resource attributes with every metrics.
21+
#[default]
22+
None,
23+
/// Export only the resource attributes in the allow list with every metrics.
24+
KeyAllowList(HashSet<Key>),
25+
}
26+
27+
impl From<HashSet<Key>> for ResourceSelector {
28+
fn from(keys: HashSet<Key>) -> Self {
29+
ResourceSelector::KeyAllowList(keys)
30+
}
31+
}
32+
33+
impl ResourceSelector {
34+
pub(crate) fn select(&self, resource: &Resource) -> Vec<LabelPair> {
35+
match self {
36+
ResourceSelector::All => get_attrs(&mut resource.iter(), &[]),
37+
ResourceSelector::None => Vec::new(),
38+
ResourceSelector::KeyAllowList(keys) => {
39+
get_attrs(&mut resource.iter().filter(|(k, _)| keys.contains(k)), &[])
40+
}
41+
}
42+
}
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# HELP bar_ratio a fun little gauge
2+
# TYPE bar_ratio gauge
3+
bar_ratio{A="B",C="D",otel_scope_name="testmeter",otel_scope_version="v0.1.0",service_name="prometheus_test",telemetry_sdk_language="rust",telemetry_sdk_name="opentelemetry",telemetry_sdk_version="latest"} 1
4+
# HELP otel_scope_info Instrumentation Scope metadata
5+
# TYPE otel_scope_info gauge
6+
otel_scope_info{otel_scope_name="testmeter",otel_scope_version="v0.1.0"} 1
7+
# HELP target_info Target metadata
8+
# TYPE target_info gauge
9+
target_info{service_name="prometheus_test",telemetry_sdk_language="rust",telemetry_sdk_name="opentelemetry",telemetry_sdk_version="latest"} 1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# HELP bar_ratio a fun little gauge
2+
# TYPE bar_ratio gauge
3+
bar_ratio{A="B",C="D",otel_scope_name="testmeter",otel_scope_version="v0.1.0",service_name="prometheus_test"} 1
4+
# HELP otel_scope_info Instrumentation Scope metadata
5+
# TYPE otel_scope_info gauge
6+
otel_scope_info{otel_scope_name="testmeter",otel_scope_version="v0.1.0"} 1
7+
# HELP target_info Target metadata
8+
# TYPE target_info gauge
9+
target_info{service_name="prometheus_test",telemetry_sdk_language="rust",telemetry_sdk_name="opentelemetry",telemetry_sdk_version="latest"} 1

opentelemetry-prometheus/tests/integration_test.rs

+35-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1+
use std::collections::HashSet;
12
use std::fs;
23
use std::path::Path;
34
use std::time::Duration;
45

56
use opentelemetry::metrics::{Meter, MeterProvider as _, Unit};
67
use opentelemetry::Key;
78
use opentelemetry::KeyValue;
8-
use opentelemetry_prometheus::ExporterBuilder;
9+
use opentelemetry_prometheus::{ExporterBuilder, ResourceSelector};
910
use opentelemetry_sdk::metrics::{new_view, Aggregation, Instrument, SdkMeterProvider, Stream};
1011
use opentelemetry_sdk::resource::{
1112
EnvResourceDetector, SdkProvidedResourceDetector, TelemetryResourceDetector,
@@ -307,6 +308,39 @@ fn prometheus_exporter_integration() {
307308
}),
308309
..Default::default()
309310
},
311+
TestCase {
312+
name: "with resource in every metrics",
313+
builder: ExporterBuilder::default().with_resource_selector(ResourceSelector::All),
314+
expected_file: "resource_in_every_metrics.txt",
315+
record_metrics: Box::new(|meter| {
316+
let attrs = vec![Key::new("A").string("B"), Key::new("C").string("D")];
317+
let gauge = meter
318+
.i64_up_down_counter("bar")
319+
.with_description("a fun little gauge")
320+
.with_unit(Unit::new("1"))
321+
.init();
322+
gauge.add(2, &attrs);
323+
gauge.add(-1, &attrs);
324+
}),
325+
..Default::default()
326+
},
327+
TestCase {
328+
name: "with select resource in every metrics",
329+
builder: ExporterBuilder::default()
330+
.with_resource_selector(HashSet::from([Key::new("service.name")])),
331+
expected_file: "select_resource_in_every_metrics.txt",
332+
record_metrics: Box::new(|meter| {
333+
let attrs = vec![Key::new("A").string("B"), Key::new("C").string("D")];
334+
let gauge = meter
335+
.i64_up_down_counter("bar")
336+
.with_description("a fun little gauge")
337+
.with_unit(Unit::new("1"))
338+
.init();
339+
gauge.add(2, &attrs);
340+
gauge.add(-1, &attrs);
341+
}),
342+
..Default::default()
343+
},
310344
];
311345

312346
for tc in test_cases {

opentelemetry-sdk/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
- Fix SimpleSpanProcessor to be consistent with log counterpart. Also removed
66
dependency on crossbeam-channel.
77
[1612](https://github.com/open-telemetry/opentelemetry-rust/pull/1612/files)
8+
- [#1422](https://github.com/open-telemetry/opentelemetry-rust/pull/1422)
9+
Fix metrics aggregation bug when using Views to drop attributes.
810

911
## v0.22.1
1012

opentelemetry-sdk/src/attributes/set.rs

+15-8
Original file line numberDiff line numberDiff line change
@@ -138,16 +138,20 @@ impl From<&Resource> for AttributeSet {
138138
}
139139
}
140140

141+
fn calculate_hash(values: &[HashKeyValue]) -> u64 {
142+
let mut hasher = DefaultHasher::new();
143+
values.iter().fold(&mut hasher, |mut hasher, item| {
144+
item.hash(&mut hasher);
145+
hasher
146+
});
147+
hasher.finish()
148+
}
149+
141150
impl AttributeSet {
142151
fn new(mut values: Vec<HashKeyValue>) -> Self {
143152
values.sort_unstable();
144-
let mut hasher = DefaultHasher::new();
145-
values.iter().fold(&mut hasher, |mut hasher, item| {
146-
item.hash(&mut hasher);
147-
hasher
148-
});
149-
150-
AttributeSet(values, hasher.finish())
153+
let hash = calculate_hash(&values);
154+
AttributeSet(values, hash)
151155
}
152156

153157
/// Returns the number of elements in the set.
@@ -165,7 +169,10 @@ impl AttributeSet {
165169
where
166170
F: Fn(&KeyValue) -> bool,
167171
{
168-
self.0.retain(|kv| f(&kv.0))
172+
self.0.retain(|kv| f(&kv.0));
173+
174+
// Recalculate the hash as elements are changed.
175+
self.1 = calculate_hash(&self.0);
169176
}
170177

171178
/// Iterate over key value pairs in the set

0 commit comments

Comments
 (0)