Skip to content

Commit de6c3cf

Browse files
authored
Merge branch 'main' into cijothomas/knownbugtest
2 parents 2c3ce0c + 4b56ee3 commit de6c3cf

File tree

24 files changed

+423
-81
lines changed

24 files changed

+423
-81
lines changed

.github/workflows/benchmark.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ jobs:
2222
# If we're running on a PR, use ubuntu-latest - a shared runner. We can't use the self-hosted
2323
# runners on arbitrary PRs, and we don't want to unleash that load on the pool anyway.
2424
# If we're running on main, use the OTEL self-hosted runner pool.
25-
runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-latest' || 'self-hosted' }}
25+
26+
# TODO - temporarily move main to the shared workers, until we've resolved the instance setup issue
27+
# runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-latest' || 'self-hosted' }}
28+
runs-on: 'ubuntu-latest'
2629
if: ${{ (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'performance')) || github.event_name == 'push' }}
2730
env:
2831
# For PRs, compare against the base branch - e.g., 'main'.

.github/workflows/fossa.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
steps:
1515
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
1616

17-
- uses: fossas/fossa-action@93a52ecf7c3ac7eb40f5de77fd69b1a19524de94 # v1.5.0
17+
- uses: fossas/fossa-action@c0a7d013f84c8ee5e910593186598625513cc1e4 # v1.6.0
1818
with:
1919
api-key: ${{secrets.FOSSA_API_KEY}}
2020
team: OpenTelemetry
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: OSSF Scorecard
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
schedule:
8+
- cron: "50 3 * * 0" # once a week
9+
workflow_dispatch:
10+
11+
permissions: read-all
12+
13+
jobs:
14+
analysis:
15+
runs-on: ubuntu-latest
16+
permissions:
17+
# Needed for Code scanning upload
18+
security-events: write
19+
# Needed for GitHub OIDC token if publish_results is true
20+
id-token: write
21+
steps:
22+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
23+
with:
24+
persist-credentials: false
25+
26+
- uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1
27+
with:
28+
results_file: results.sarif
29+
results_format: sarif
30+
publish_results: true
31+
32+
# Upload the results as artifacts (optional). Commenting out will disable
33+
# uploads of run results in SARIF format to the repository Actions tab.
34+
# https://docs.github.com/en/actions/advanced-guides/storing-workflow-data-as-artifacts
35+
- name: "Upload artifact"
36+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
37+
with:
38+
name: SARIF file
39+
path: results.sarif
40+
retention-days: 5
41+
42+
# Upload the results to GitHub's code scanning dashboard (optional).
43+
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
44+
- name: "Upload to code-scanning"
45+
uses: github/codeql-action/upload-sarif@1b549b9259bda1cb5ddde3b41741a82a2d15a841 # v3.28.13
46+
with:
47+
sarif_file: results.sarif

opentelemetry-otlp/src/metric.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use opentelemetry_sdk::metrics::{
2121
data::ResourceMetrics, exporter::PushMetricExporter, Temporality,
2222
};
2323
use std::fmt::{Debug, Formatter};
24+
use std::time::Duration;
2425

2526
/// Target to which the exporter is going to send metrics, defaults to https://localhost:4317/v1/metrics.
2627
/// Learn about the relationship between this constant and default/spans/logs at
@@ -163,6 +164,10 @@ impl PushMetricExporter for MetricExporter {
163164
}
164165

165166
fn shutdown(&self) -> OTelSdkResult {
167+
self.shutdown_with_timeout(Duration::from_secs(5))
168+
}
169+
170+
fn shutdown_with_timeout(&self, _timeout: std::time::Duration) -> OTelSdkResult {
166171
match &self.client {
167172
#[cfg(feature = "grpc-tonic")]
168173
SupportedTransportClient::Tonic(client) => client.shutdown(),

opentelemetry-sdk/CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,15 @@ the suppression flag in their dedicated thread, so that telemetry generated from
1212
those threads will not be fed back into OTel. Similarly, `SimpleLogProcessor`
1313
also modified to suppress telemetry before invoking exporters.
1414

15+
- **Feature**: Implemented and enabled cardinality capping for Metrics by
16+
default.
17+
- The default cardinality limit is 2000 and can be customized using Views.
18+
- This feature was previously removed in version 0.28 due to the lack of
19+
configurability but has now been reintroduced with the ability to configure
20+
the limit.
21+
- TODO/Placeholder: Add ability to configure cardinality limits via Instrument
22+
advisory.
23+
1524
## 0.29.0
1625

1726
Released 2025-Mar-21
@@ -68,6 +77,7 @@ Released 2025-Mar-21
6877

6978
Custom exporters will need to internally synchronize any mutable state, if applicable.
7079

80+
- **Breaking** The `shutdown_with_timeout` method is added to MetricExporter trait. This is breaking change for custom `MetricExporter` authors.
7181
- Bug Fix: `BatchLogProcessor` now correctly calls `shutdown` on the exporter
7282
when its `shutdown` is invoked.
7383

opentelemetry-sdk/src/metrics/exporter.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! Interfaces for exporting metrics
2+
23
use crate::error::OTelSdkResult;
4+
use std::time::Duration;
35

46
use crate::metrics::data::ResourceMetrics;
57

@@ -26,7 +28,12 @@ pub trait PushMetricExporter: Send + Sync + 'static {
2628
///
2729
/// After Shutdown is called, calls to Export will perform no operation and
2830
/// instead will return an error indicating the shutdown state.
29-
fn shutdown(&self) -> OTelSdkResult;
31+
fn shutdown_with_timeout(&self, timeout: Duration) -> OTelSdkResult;
32+
33+
/// Shutdown with the default timeout of 5 seconds.
34+
fn shutdown(&self) -> OTelSdkResult {
35+
self.shutdown_with_timeout(Duration::from_secs(5))
36+
}
3037

3138
/// Access the [Temporality] of the MetricExporter.
3239
fn temporality(&self) -> Temporality;

opentelemetry-sdk/src/metrics/in_memory_exporter.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::InMemoryExporterError;
88
use std::collections::VecDeque;
99
use std::fmt;
1010
use std::sync::{Arc, Mutex};
11+
use std::time::Duration;
1112

1213
use super::data::{AggregatedMetrics, Metric, ScopeMetrics};
1314

@@ -253,6 +254,10 @@ impl PushMetricExporter for InMemoryMetricExporter {
253254
Ok(())
254255
}
255256

257+
fn shutdown_with_timeout(&self, _timeout: Duration) -> OTelSdkResult {
258+
Ok(())
259+
}
260+
256261
fn temporality(&self) -> Temporality {
257262
self.temporality
258263
}

opentelemetry-sdk/src/metrics/instrument.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,10 @@ impl Instrument {
130130

131131
/// empty returns if all fields of i are their default-value.
132132
pub(crate) fn is_empty(&self) -> bool {
133-
self.name == ""
134-
&& self.description == ""
133+
self.name.is_empty()
134+
&& self.description.is_empty()
135135
&& self.kind.is_none()
136-
&& self.unit == ""
136+
&& self.unit.is_empty()
137137
&& self.scope == InstrumentationScope::default()
138138
}
139139

@@ -203,6 +203,9 @@ pub struct Stream {
203203
/// dropped. If the set is empty, all attributes will be dropped, if `None` all
204204
/// attributes will be kept.
205205
pub allowed_attribute_keys: Option<Arc<HashSet<Key>>>,
206+
207+
/// Cardinality limit for the stream.
208+
pub cardinality_limit: Option<usize>,
206209
}
207210

208211
#[cfg(feature = "spec_unstable_metrics_views")]
@@ -245,6 +248,12 @@ impl Stream {
245248

246249
self
247250
}
251+
252+
/// Set the stream cardinality limit.
253+
pub fn cardinality_limit(mut self, limit: usize) -> Self {
254+
self.cardinality_limit = Some(limit);
255+
self
256+
}
248257
}
249258

250259
/// The identifying properties of an instrument.

opentelemetry-sdk/src/metrics/internal/aggregate.rs

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,6 @@ use super::{
1515
precomputed_sum::PrecomputedSum, sum::Sum, Number,
1616
};
1717

18-
pub(crate) const STREAM_CARDINALITY_LIMIT: usize = 2000;
19-
20-
/// Checks whether aggregator has hit cardinality limit for metric streams
21-
pub(crate) fn is_under_cardinality_limit(_size: usize) -> bool {
22-
true
23-
24-
// TODO: Implement this feature, after allowing the ability to customize the cardinality limit.
25-
// size < STREAM_CARDINALITY_LIMIT
26-
}
27-
2818
/// Receives measurements to be aggregated.
2919
pub(crate) trait Measure<T>: Send + Sync + 'static {
3020
fn call(&self, measurement: T, attrs: &[KeyValue]);
@@ -133,14 +123,22 @@ pub(crate) struct AggregateBuilder<T> {
133123
/// measurements.
134124
filter: AttributeSetFilter,
135125

126+
/// Cardinality limit for the metric stream
127+
cardinality_limit: usize,
128+
136129
_marker: marker::PhantomData<T>,
137130
}
138131

139132
impl<T: Number> AggregateBuilder<T> {
140-
pub(crate) fn new(temporality: Temporality, filter: Option<Filter>) -> Self {
133+
pub(crate) fn new(
134+
temporality: Temporality,
135+
filter: Option<Filter>,
136+
cardinality_limit: usize,
137+
) -> Self {
141138
AggregateBuilder {
142139
temporality,
143140
filter: AttributeSetFilter::new(filter),
141+
cardinality_limit,
144142
_marker: marker::PhantomData,
145143
}
146144
}
@@ -150,18 +148,31 @@ impl<T: Number> AggregateBuilder<T> {
150148
LastValue::new(
151149
overwrite_temporality.unwrap_or(self.temporality),
152150
self.filter.clone(),
151+
self.cardinality_limit,
153152
)
154153
.into()
155154
}
156155

157156
/// Builds a precomputed sum aggregate function input and output.
158157
pub(crate) fn precomputed_sum(&self, monotonic: bool) -> AggregateFns<T> {
159-
PrecomputedSum::new(self.temporality, self.filter.clone(), monotonic).into()
158+
PrecomputedSum::new(
159+
self.temporality,
160+
self.filter.clone(),
161+
monotonic,
162+
self.cardinality_limit,
163+
)
164+
.into()
160165
}
161166

162167
/// Builds a sum aggregate function input and output.
163168
pub(crate) fn sum(&self, monotonic: bool) -> AggregateFns<T> {
164-
Sum::new(self.temporality, self.filter.clone(), monotonic).into()
169+
Sum::new(
170+
self.temporality,
171+
self.filter.clone(),
172+
monotonic,
173+
self.cardinality_limit,
174+
)
175+
.into()
165176
}
166177

167178
/// Builds a histogram aggregate function input and output.
@@ -177,6 +188,7 @@ impl<T: Number> AggregateBuilder<T> {
177188
boundaries,
178189
record_min_max,
179190
record_sum,
191+
self.cardinality_limit,
180192
)
181193
.into()
182194
}
@@ -196,6 +208,7 @@ impl<T: Number> AggregateBuilder<T> {
196208
max_scale,
197209
record_min_max,
198210
record_sum,
211+
self.cardinality_limit,
199212
)
200213
.into()
201214
}
@@ -211,10 +224,13 @@ mod tests {
211224

212225
use super::*;
213226

227+
const CARDINALITY_LIMIT_DEFAULT: usize = 2000;
228+
214229
#[test]
215230
fn last_value_aggregation() {
216231
let AggregateFns { measure, collect } =
217-
AggregateBuilder::<u64>::new(Temporality::Cumulative, None).last_value(None);
232+
AggregateBuilder::<u64>::new(Temporality::Cumulative, None, CARDINALITY_LIMIT_DEFAULT)
233+
.last_value(None);
218234
let mut a = MetricData::Gauge(Gauge {
219235
data_points: vec![GaugeDataPoint {
220236
attributes: vec![KeyValue::new("a", 1)],
@@ -244,7 +260,8 @@ mod tests {
244260
fn precomputed_sum_aggregation() {
245261
for temporality in [Temporality::Delta, Temporality::Cumulative] {
246262
let AggregateFns { measure, collect } =
247-
AggregateBuilder::<u64>::new(temporality, None).precomputed_sum(true);
263+
AggregateBuilder::<u64>::new(temporality, None, CARDINALITY_LIMIT_DEFAULT)
264+
.precomputed_sum(true);
248265
let mut a = MetricData::Sum(Sum {
249266
data_points: vec![
250267
SumDataPoint {
@@ -290,7 +307,8 @@ mod tests {
290307
fn sum_aggregation() {
291308
for temporality in [Temporality::Delta, Temporality::Cumulative] {
292309
let AggregateFns { measure, collect } =
293-
AggregateBuilder::<u64>::new(temporality, None).sum(true);
310+
AggregateBuilder::<u64>::new(temporality, None, CARDINALITY_LIMIT_DEFAULT)
311+
.sum(true);
294312
let mut a = MetricData::Sum(Sum {
295313
data_points: vec![
296314
SumDataPoint {
@@ -335,8 +353,9 @@ mod tests {
335353
#[test]
336354
fn explicit_bucket_histogram_aggregation() {
337355
for temporality in [Temporality::Delta, Temporality::Cumulative] {
338-
let AggregateFns { measure, collect } = AggregateBuilder::<u64>::new(temporality, None)
339-
.explicit_bucket_histogram(vec![1.0], true, true);
356+
let AggregateFns { measure, collect } =
357+
AggregateBuilder::<u64>::new(temporality, None, CARDINALITY_LIMIT_DEFAULT)
358+
.explicit_bucket_histogram(vec![1.0], true, true);
340359
let mut a = MetricData::Histogram(Histogram {
341360
data_points: vec![HistogramDataPoint {
342361
attributes: vec![KeyValue::new("a1", 1)],
@@ -382,8 +401,9 @@ mod tests {
382401
#[test]
383402
fn exponential_histogram_aggregation() {
384403
for temporality in [Temporality::Delta, Temporality::Cumulative] {
385-
let AggregateFns { measure, collect } = AggregateBuilder::<u64>::new(temporality, None)
386-
.exponential_bucket_histogram(4, 20, true, true);
404+
let AggregateFns { measure, collect } =
405+
AggregateBuilder::<u64>::new(temporality, None, CARDINALITY_LIMIT_DEFAULT)
406+
.exponential_bucket_histogram(4, 20, true, true);
387407
let mut a = MetricData::ExponentialHistogram(ExponentialHistogram {
388408
data_points: vec![ExponentialHistogramDataPoint {
389409
attributes: vec![KeyValue::new("a1", 1)],

0 commit comments

Comments
 (0)