Skip to content

Commit 0421775

Browse files
committed
otel-metricfilter-fn
1 parent edb8937 commit 0421775

File tree

11 files changed

+613
-22
lines changed

11 files changed

+613
-22
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ Increment the:
1818
* [SDK] Add tracer scope configurator
1919
[#3137](https://github.com/open-telemetry/opentelemetry-cpp/pull/3137)
2020

21+
* [SDK] Implement spec: MetricFilter
22+
[#3235](https://github.com/open-telemetry/opentelemetry-cpp/pull/3235)
23+
2124
## [1.19 2025-01-22]
2225

2326
* [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: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "opentelemetry/nostd/function_ref.h"
1414
#include "opentelemetry/nostd/span.h"
1515
#include "opentelemetry/nostd/string_view.h"
16+
#include "opentelemetry/sdk/metrics/export/metric_filter.h"
1617
#include "opentelemetry/sdk/metrics/metric_reader.h"
1718
#include "opentelemetry/sdk/metrics/state/metric_collector.h"
1819
#include "opentelemetry/sdk/metrics/view/instrument_selector.h"
@@ -96,14 +97,20 @@ class MeterContext : public std::enable_shared_from_this<MeterContext>
9697
opentelemetry::common::SystemTimestamp GetSDKStartTime() noexcept;
9798

9899
/**
99-
* Attaches a metric reader to list of configured readers for this Meter context.
100-
* @param reader The metric reader for this meter context. This
101-
* must not be a nullptr.
100+
* Create a MetricCollector from a MetricReader using this MeterContext and add it to the list of
101+
* configured collectors.
102+
* @param reader The MetricReader for which a MetricCollector is to be created. This must not be a
103+
* nullptr.
104+
* @param metric_filter The optional MetricFilter used when creating the MetricCollector.
105+
* @return The MetricCollector created.
102106
*
103107
* Note: This reader may not receive any in-flight meter data, but will get newly created meter
104-
* data. Note: This method is not thread safe, and should ideally be called from main thread.
108+
* data.
109+
* Note: This method is not thread safe, and should ideally be called from main thread.
105110
*/
106-
void AddMetricReader(std::shared_ptr<MetricReader> reader) noexcept;
111+
std::weak_ptr<MetricCollector> AddMetricReader(
112+
std::shared_ptr<MetricReader> reader,
113+
std::unique_ptr<MetricFilter> metric_filter = nullptr) noexcept;
107114

108115
/**
109116
* Attaches a View to list of configured Views for this Meter context.

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

Lines changed: 12 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"
@@ -79,14 +80,20 @@ class OPENTELEMETRY_EXPORT MeterProvider final : public opentelemetry::metrics::
7980
const sdk::resource::Resource &GetResource() const noexcept;
8081

8182
/**
82-
* Attaches a metric reader to list of configured readers for this Meter providers.
83-
* @param reader The metric reader for this meter provider. This
84-
* must not be a nullptr.
83+
* Create a MetricCollector from a MetricReader using the MeterContext of this MeterProvider and
84+
* add it to the list of configured collectors.
85+
* @param reader The MetricReader for which a MetricCollector is to be created. This must not be a
86+
* nullptr.
87+
* @param metric_filter The optional MetricFilter used when creating the MetricCollector.
88+
* @return The MetricCollector created.
8589
*
8690
* Note: This reader may not receive any in-flight meter data, but will get newly created meter
87-
* data. Note: This method is not thread safe, and should ideally be called from main thread.
91+
* data.
92+
* Note: This method is not thread safe, and should ideally be called from main thread.
8893
*/
89-
void AddMetricReader(std::shared_ptr<MetricReader> reader) noexcept;
94+
std::weak_ptr<MetricCollector> AddMetricReader(
95+
std::shared_ptr<MetricReader> reader,
96+
std::unique_ptr<MetricFilter> metric_filter = nullptr) noexcept;
9097

9198
/**
9299
* 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: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "opentelemetry/nostd/string_view.h"
1818
#include "opentelemetry/sdk/common/global_log_handler.h"
1919
#include "opentelemetry/sdk/instrumentationscope/instrumentation_scope.h"
20+
#include "opentelemetry/sdk/metrics/export/metric_filter.h"
2021
#include "opentelemetry/sdk/metrics/meter.h"
2122
#include "opentelemetry/sdk/metrics/meter_context.h"
2223
#include "opentelemetry/sdk/metrics/metric_reader.h"
@@ -79,10 +80,14 @@ opentelemetry::common::SystemTimestamp MeterContext::GetSDKStartTime() noexcept
7980
return sdk_start_ts_;
8081
}
8182

82-
void MeterContext::AddMetricReader(std::shared_ptr<MetricReader> reader) noexcept
83+
std::weak_ptr<MetricCollector> MeterContext::AddMetricReader(
84+
std::shared_ptr<MetricReader> reader,
85+
std::unique_ptr<MetricFilter> metric_filter) noexcept
8386
{
84-
auto collector = std::shared_ptr<MetricCollector>{new MetricCollector(this, std::move(reader))};
87+
auto collector = std::shared_ptr<MetricCollector>{
88+
new MetricCollector(this, std::move(reader), std::move(metric_filter))};
8589
collectors_.push_back(collector);
90+
return std::weak_ptr<MetricCollector>(collector);
8691
}
8792

8893
void MeterContext::AddView(std::unique_ptr<InstrumentSelector> instrument_selector,

sdk/src/metrics/meter_provider.cc

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@
1212
#include "opentelemetry/nostd/string_view.h"
1313
#include "opentelemetry/sdk/common/global_log_handler.h"
1414
#include "opentelemetry/sdk/instrumentationscope/instrumentation_scope.h"
15+
#include "opentelemetry/sdk/metrics/export/metric_filter.h"
1516
#include "opentelemetry/sdk/metrics/meter.h"
1617
#include "opentelemetry/sdk/metrics/meter_context.h"
1718
#include "opentelemetry/sdk/metrics/meter_provider.h"
1819
#include "opentelemetry/sdk/metrics/metric_reader.h"
20+
#include "opentelemetry/sdk/metrics/state/metric_collector.h"
1921
#include "opentelemetry/sdk/metrics/view/instrument_selector.h"
2022
#include "opentelemetry/sdk/metrics/view/meter_selector.h"
2123
#include "opentelemetry/sdk/metrics/view/view.h"
@@ -107,9 +109,11 @@ const resource::Resource &MeterProvider::GetResource() const noexcept
107109
return context_->GetResource();
108110
}
109111

110-
void MeterProvider::AddMetricReader(std::shared_ptr<MetricReader> reader) noexcept
112+
std::weak_ptr<MetricCollector> MeterProvider::AddMetricReader(
113+
std::shared_ptr<MetricReader> reader,
114+
std::unique_ptr<MetricFilter> metric_filter) noexcept
111115
{
112-
context_->AddMetricReader(std::move(reader));
116+
return context_->AddMetricReader(std::move(reader), std::move(metric_filter));
113117
}
114118

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

sdk/src/metrics/state/metric_collector.cc

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@
99
#include <vector>
1010

1111
#include "opentelemetry/nostd/function_ref.h"
12+
#include "opentelemetry/nostd/string_view.h"
1213
#include "opentelemetry/sdk/common/global_log_handler.h"
14+
#include "opentelemetry/sdk/instrumentationscope/instrumentation_scope.h"
1315
#include "opentelemetry/sdk/metrics/data/metric_data.h"
16+
#include "opentelemetry/sdk/metrics/export/metric_filter.h"
1417
#include "opentelemetry/sdk/metrics/export/metric_producer.h"
1518
#include "opentelemetry/sdk/metrics/instruments.h"
1619
#include "opentelemetry/sdk/metrics/meter.h"
@@ -28,8 +31,11 @@ namespace metrics
2831
using opentelemetry::sdk::resource::Resource;
2932

3033
MetricCollector::MetricCollector(opentelemetry::sdk::metrics::MeterContext *context,
31-
std::shared_ptr<MetricReader> metric_reader)
32-
: meter_context_{context}, metric_reader_{std::move(metric_reader)}
34+
std::shared_ptr<MetricReader> metric_reader,
35+
std::unique_ptr<MetricFilter> metric_filter)
36+
: meter_context_{context},
37+
metric_reader_{std::move(metric_reader)},
38+
metric_filter_(std::move(metric_filter))
3339
{
3440
metric_reader_->SetMetricProducer(this);
3541
}
@@ -63,12 +69,61 @@ MetricProducer::Result MetricCollector::Produce() noexcept
6369
meter_context_->ForEachMeter([&](const std::shared_ptr<Meter> &meter) noexcept {
6470
auto collection_ts = std::chrono::system_clock::now();
6571
auto metric_data = meter->Collect(this, collection_ts);
66-
if (!metric_data.empty())
72+
if (metric_data.empty())
73+
{
74+
return true;
75+
}
76+
ScopeMetrics scope_metrics;
77+
scope_metrics.metric_data_ = std::move(metric_data);
78+
scope_metrics.scope_ = meter->GetInstrumentationScope();
79+
if (!this->metric_filter_)
6780
{
68-
ScopeMetrics scope_metrics;
69-
scope_metrics.metric_data_ = std::move(metric_data);
70-
scope_metrics.scope_ = meter->GetInstrumentationScope();
7181
resource_metrics.scope_metric_data_.emplace_back(std::move(scope_metrics));
82+
return true;
83+
}
84+
85+
ScopeMetrics filtered_scope_metrics;
86+
filtered_scope_metrics.scope_ = meter->GetInstrumentationScope();
87+
for (MetricData &metric : scope_metrics.metric_data_)
88+
{
89+
const opentelemetry::sdk::instrumentationscope::InstrumentationScope &scope =
90+
*scope_metrics.scope_;
91+
opentelemetry::nostd::string_view name = metric.instrument_descriptor.name_;
92+
const InstrumentType &type = metric.instrument_descriptor.type_;
93+
opentelemetry::nostd::string_view unit = metric.instrument_descriptor.unit_;
94+
95+
MetricFilter::MetricFilterResult metric_filter_result =
96+
this->metric_filter_->TestMetric(scope, name, type, unit);
97+
if (metric_filter_result == MetricFilter::MetricFilterResult::kAccept)
98+
{
99+
filtered_scope_metrics.metric_data_.emplace_back(std::move(metric));
100+
continue;
101+
}
102+
else if (metric_filter_result == MetricFilter::MetricFilterResult::kDrop)
103+
{
104+
continue;
105+
}
106+
107+
std::vector<PointDataAttributes> filtered_point_data_attrs;
108+
for (PointDataAttributes &point_data_attr : metric.point_data_attr_)
109+
{
110+
const PointAttributes &attributes = point_data_attr.attributes;
111+
MetricFilter::AttributesFilterResult attributes_filter_result =
112+
this->metric_filter_->TestAttributes(scope, name, type, unit, attributes);
113+
if (attributes_filter_result == MetricFilter::AttributesFilterResult::kAccept)
114+
{
115+
filtered_point_data_attrs.emplace_back(std::move(point_data_attr));
116+
}
117+
}
118+
if (!filtered_point_data_attrs.empty())
119+
{
120+
metric.point_data_attr_ = std::move(filtered_point_data_attrs);
121+
filtered_scope_metrics.metric_data_.emplace_back(std::move(metric));
122+
}
123+
}
124+
if (!filtered_scope_metrics.metric_data_.empty())
125+
{
126+
resource_metrics.scope_metric_data_.emplace_back(std::move(filtered_scope_metrics));
72127
}
73128
return true;
74129
});

0 commit comments

Comments
 (0)