Skip to content

Commit dee5b0b

Browse files
authored
[SDK] Implement spec: MetricFilter (open-telemetry#3235)
1 parent 64a74bf commit dee5b0b

20 files changed

+638
-22
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ Important changes:
4646

4747
* All the example code has been updated to reflect the new usage.
4848

49+
* [SDK] Implement spec: MetricFilter
50+
[#3235](https://github.com/open-telemetry/opentelemetry-cpp/pull/3235)
51+
4952
## [1.19 2025-01-22]
5053

5154
* [PROMETHEUS_EXPORTER] Fix default for emitting otel_scope attributes
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
#pragma once
5+
6+
#include <functional>
7+
#include <memory>
8+
9+
#include "opentelemetry/nostd/string_view.h"
10+
#include "opentelemetry/sdk/instrumentationscope/instrumentation_scope.h"
11+
#include "opentelemetry/sdk/metrics/data/metric_data.h"
12+
#include "opentelemetry/sdk/metrics/instruments.h"
13+
14+
OPENTELEMETRY_BEGIN_NAMESPACE
15+
namespace sdk
16+
{
17+
namespace metrics
18+
{
19+
20+
/**
21+
* MetricFilter defines the interface which enables the MetricReader’s
22+
* registered MetricProducers or the SDK’s MetricProducer to filter aggregated
23+
* data points (Metric Points) inside its Produce operation. The filtering is
24+
* done at the MetricProducer for performance reasons.
25+
*
26+
* The MetricFilter allows filtering an entire metric stream - dropping or
27+
* allowing all its attribute sets - by its TestMetric operation, which accepts
28+
* the metric stream information (scope, name, kind and unit) and returns an
29+
* enumeration: kAccept, kDrop or kAcceptPartial. If the latter returned, the
30+
* TestAttributes operation is to be called per attribute set of that metric
31+
* stream, returning an enumeration determining if the data point for that
32+
* (metric stream, attributes) pair is to be allowed in the result of the
33+
* MetricProducer Produce operation.
34+
*/
35+
class MetricFilter
36+
{
37+
public:
38+
enum class MetricFilterResult
39+
{
40+
kAccept,
41+
kDrop,
42+
kAcceptPartial,
43+
};
44+
45+
enum class AttributesFilterResult
46+
{
47+
kAccept,
48+
kDrop,
49+
};
50+
51+
using TestMetricFn = std::function<MetricFilterResult(
52+
const opentelemetry::sdk::instrumentationscope::InstrumentationScope &scope,
53+
opentelemetry::nostd::string_view name,
54+
const InstrumentType &type,
55+
opentelemetry::nostd::string_view unit)>;
56+
57+
using TestAttributesFn = std::function<AttributesFilterResult(
58+
const opentelemetry::sdk::instrumentationscope::InstrumentationScope &scope,
59+
opentelemetry::nostd::string_view name,
60+
const InstrumentType &type,
61+
opentelemetry::nostd::string_view unit,
62+
const PointAttributes &attributes)>;
63+
64+
// static
65+
static std::unique_ptr<MetricFilter> Create(TestMetricFn test_metric_fn,
66+
TestAttributesFn test_attributes_fn)
67+
{
68+
return std::make_unique<MetricFilter>(test_metric_fn, test_attributes_fn);
69+
}
70+
71+
MetricFilter(TestMetricFn test_metric_fn, TestAttributesFn test_attributes_fn)
72+
: test_metric_fn_(test_metric_fn), test_attributes_fn_(test_attributes_fn)
73+
{}
74+
75+
/**
76+
* TestMetric is called once for every metric stream, in each MetricProducer
77+
* Produce operation.
78+
*/
79+
MetricFilterResult TestMetric(
80+
const opentelemetry::sdk::instrumentationscope::InstrumentationScope &scope,
81+
opentelemetry::nostd::string_view name,
82+
const InstrumentType &type,
83+
opentelemetry::nostd::string_view unit)
84+
{
85+
return test_metric_fn_(scope, name, type, unit);
86+
}
87+
88+
/**
89+
* TestAttributes determines for a given metric stream and attribute set if
90+
* it should be allowed or filtered out.
91+
*
92+
* This operation should only be called if TestMetric operation returned
93+
* kAcceptPartial for the given metric stream arguments.
94+
*/
95+
AttributesFilterResult TestAttributes(
96+
const opentelemetry::sdk::instrumentationscope::InstrumentationScope &scope,
97+
opentelemetry::nostd::string_view name,
98+
const InstrumentType &type,
99+
opentelemetry::nostd::string_view unit,
100+
const PointAttributes &attributes)
101+
{
102+
return test_attributes_fn_(scope, name, type, unit, attributes);
103+
}
104+
105+
private:
106+
TestMetricFn test_metric_fn_;
107+
TestAttributesFn test_attributes_fn_;
108+
};
109+
110+
} // namespace metrics
111+
} // namespace sdk
112+
OPENTELEMETRY_END_NAMESPACE

sdk/include/opentelemetry/sdk/metrics/export/metric_producer.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33

44
#pragma once
55

6+
#include <memory>
67
#include <utility>
78
#include <vector>
89

910
#include "opentelemetry/nostd/function_ref.h"
1011
#include "opentelemetry/nostd/variant.h"
1112
#include "opentelemetry/sdk/metrics/data/metric_data.h"
13+
#include "opentelemetry/sdk/metrics/export/metric_filter.h"
1214
#include "opentelemetry/version.h"
1315

1416
OPENTELEMETRY_BEGIN_NAMESPACE
@@ -80,7 +82,9 @@ struct ResourceMetrics
8082
class MetricProducer
8183
{
8284
public:
83-
MetricProducer() = default;
85+
MetricProducer(std::unique_ptr<MetricFilter> metric_filter = nullptr)
86+
: metric_filter_(std::move(metric_filter))
87+
{}
8488
virtual ~MetricProducer() = default;
8589

8690
MetricProducer(const MetricProducer &) = delete;
@@ -107,6 +111,8 @@ class MetricProducer
107111
* partial failure.
108112
*/
109113
virtual Result Produce() noexcept = 0;
114+
115+
std::unique_ptr<MetricFilter> metric_filter_;
110116
};
111117

112118
} // namespace metrics

sdk/include/opentelemetry/sdk/metrics/meter_context.h

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "opentelemetry/nostd/span.h"
1515
#include "opentelemetry/nostd/string_view.h"
1616
#include "opentelemetry/sdk/instrumentationscope/scope_configurator.h"
17+
#include "opentelemetry/sdk/metrics/export/metric_filter.h"
1718
#include "opentelemetry/sdk/metrics/meter_config.h"
1819
#include "opentelemetry/sdk/metrics/metric_reader.h"
1920
#include "opentelemetry/sdk/metrics/state/metric_collector.h"
@@ -28,6 +29,11 @@
2829
# include "opentelemetry/sdk/metrics/exemplar/filter_type.h"
2930
#endif
3031

32+
namespace testing
33+
{
34+
class MetricCollectorTest;
35+
}
36+
3137
OPENTELEMETRY_BEGIN_NAMESPACE
3238
namespace sdk
3339
{
@@ -107,14 +113,18 @@ class MeterContext : public std::enable_shared_from_this<MeterContext>
107113
opentelemetry::common::SystemTimestamp GetSDKStartTime() noexcept;
108114

109115
/**
110-
* Attaches a metric reader to list of configured readers for this Meter context.
111-
* @param reader The metric reader for this meter context. This
112-
* must not be a nullptr.
116+
* Create a MetricCollector from a MetricReader using this MeterContext and add it to the list of
117+
* configured collectors.
118+
* @param reader The MetricReader for which a MetricCollector is to be created. This must not be a
119+
* nullptr.
120+
* @param metric_filter The optional MetricFilter used when creating the MetricCollector.
113121
*
114122
* Note: This reader may not receive any in-flight meter data, but will get newly created meter
115-
* data. Note: This method is not thread safe, and should ideally be called from main thread.
123+
* data.
124+
* Note: This method is not thread safe, and should ideally be called from main thread.
116125
*/
117-
void AddMetricReader(std::shared_ptr<MetricReader> reader) noexcept;
126+
void AddMetricReader(std::shared_ptr<MetricReader> reader,
127+
std::unique_ptr<MetricFilter> metric_filter = nullptr) noexcept;
118128

119129
/**
120130
* Attaches a View to list of configured Views for this Meter context.
@@ -161,6 +171,8 @@ class MeterContext : public std::enable_shared_from_this<MeterContext>
161171
bool Shutdown(std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept;
162172

163173
private:
174+
friend class ::testing::MetricCollectorTest;
175+
164176
opentelemetry::sdk::resource::Resource resource_;
165177
std::vector<std::shared_ptr<CollectorHandle>> collectors_;
166178
std::unique_ptr<ViewRegistry> views_;

sdk/include/opentelemetry/sdk/metrics/meter_provider.h

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "opentelemetry/metrics/meter_provider.h"
1212
#include "opentelemetry/nostd/shared_ptr.h"
1313
#include "opentelemetry/nostd/string_view.h"
14+
#include "opentelemetry/sdk/metrics/export/metric_filter.h"
1415
#include "opentelemetry/sdk/metrics/meter_context.h"
1516
#include "opentelemetry/sdk/metrics/metric_reader.h"
1617
#include "opentelemetry/sdk/metrics/view/instrument_selector.h"
@@ -88,14 +89,18 @@ class OPENTELEMETRY_EXPORT MeterProvider final : public opentelemetry::metrics::
8889
const sdk::resource::Resource &GetResource() const noexcept;
8990

9091
/**
91-
* Attaches a metric reader to list of configured readers for this Meter providers.
92-
* @param reader The metric reader for this meter provider. This
93-
* must not be a nullptr.
92+
* Create a MetricCollector from a MetricReader using the MeterContext of this MeterProvider and
93+
* add it to the list of configured collectors.
94+
* @param reader The MetricReader for which a MetricCollector is to be created. This must not be a
95+
* nullptr.
96+
* @param metric_filter The optional MetricFilter used when creating the MetricCollector.
9497
*
9598
* Note: This reader may not receive any in-flight meter data, but will get newly created meter
96-
* data. Note: This method is not thread safe, and should ideally be called from main thread.
99+
* data.
100+
* Note: This method is not thread safe, and should ideally be called from main thread.
97101
*/
98-
void AddMetricReader(std::shared_ptr<MetricReader> reader) noexcept;
102+
void AddMetricReader(std::shared_ptr<MetricReader> reader,
103+
std::unique_ptr<MetricFilter> metric_filter = nullptr) noexcept;
99104

100105
/**
101106
* Attaches a View to list of configured Views for this Meter provider.

sdk/include/opentelemetry/sdk/metrics/state/metric_collector.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <memory>
88

99
#include "opentelemetry/nostd/function_ref.h"
10+
#include "opentelemetry/sdk/metrics/export/metric_filter.h"
1011
#include "opentelemetry/sdk/metrics/export/metric_producer.h"
1112
#include "opentelemetry/sdk/metrics/instruments.h"
1213
#include "opentelemetry/sdk/metrics/metric_reader.h"
@@ -40,7 +41,9 @@ class CollectorHandle
4041
class MetricCollector : public MetricProducer, public CollectorHandle
4142
{
4243
public:
43-
MetricCollector(MeterContext *context, std::shared_ptr<MetricReader> metric_reader);
44+
MetricCollector(MeterContext *context,
45+
std::shared_ptr<MetricReader> metric_reader,
46+
std::unique_ptr<MetricFilter> metric_filter = nullptr);
4447

4548
~MetricCollector() override = default;
4649

@@ -62,6 +65,7 @@ class MetricCollector : public MetricProducer, public CollectorHandle
6265
private:
6366
MeterContext *meter_context_;
6467
std::shared_ptr<MetricReader> metric_reader_;
68+
std::unique_ptr<MetricFilter> metric_filter_;
6569
};
6670
} // namespace metrics
6771
} // namespace sdk

sdk/src/metrics/meter_context.cc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "opentelemetry/sdk/common/global_log_handler.h"
1919
#include "opentelemetry/sdk/instrumentationscope/instrumentation_scope.h"
2020
#include "opentelemetry/sdk/instrumentationscope/scope_configurator.h"
21+
#include "opentelemetry/sdk/metrics/export/metric_filter.h"
2122
#include "opentelemetry/sdk/metrics/meter.h"
2223
#include "opentelemetry/sdk/metrics/meter_config.h"
2324
#include "opentelemetry/sdk/metrics/meter_context.h"
@@ -92,9 +93,11 @@ opentelemetry::common::SystemTimestamp MeterContext::GetSDKStartTime() noexcept
9293
return sdk_start_ts_;
9394
}
9495

95-
void MeterContext::AddMetricReader(std::shared_ptr<MetricReader> reader) noexcept
96+
void MeterContext::AddMetricReader(std::shared_ptr<MetricReader> reader,
97+
std::unique_ptr<MetricFilter> metric_filter) noexcept
9698
{
97-
auto collector = std::shared_ptr<MetricCollector>{new MetricCollector(this, std::move(reader))};
99+
auto collector = std::shared_ptr<MetricCollector>{
100+
new MetricCollector(this, std::move(reader), std::move(metric_filter))};
98101
collectors_.push_back(collector);
99102
}
100103

sdk/src/metrics/meter_provider.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "opentelemetry/sdk/common/global_log_handler.h"
1414
#include "opentelemetry/sdk/instrumentationscope/instrumentation_scope.h"
1515
#include "opentelemetry/sdk/instrumentationscope/scope_configurator.h"
16+
#include "opentelemetry/sdk/metrics/export/metric_filter.h"
1617
#include "opentelemetry/sdk/metrics/meter.h"
1718
#include "opentelemetry/sdk/metrics/meter_config.h"
1819
#include "opentelemetry/sdk/metrics/meter_context.h"
@@ -112,9 +113,10 @@ const resource::Resource &MeterProvider::GetResource() const noexcept
112113
return context_->GetResource();
113114
}
114115

115-
void MeterProvider::AddMetricReader(std::shared_ptr<MetricReader> reader) noexcept
116+
void MeterProvider::AddMetricReader(std::shared_ptr<MetricReader> reader,
117+
std::unique_ptr<MetricFilter> metric_filter) noexcept
116118
{
117-
context_->AddMetricReader(std::move(reader));
119+
context_->AddMetricReader(std::move(reader), std::move(metric_filter));
118120
}
119121

120122
void MeterProvider::AddView(std::unique_ptr<InstrumentSelector> instrument_selector,

0 commit comments

Comments
 (0)