Skip to content

Commit 1473ebe

Browse files
committed
otel-metricfilter-fn
1 parent d19eb32 commit 1473ebe

File tree

12 files changed

+606
-23
lines changed

12 files changed

+606
-23
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ Increment the:
2121
* [SDK] Fix instrumentation scope attributes evaluated in equal method
2222
[#3214](https://github.com/open-telemetry/opentelemetry-cpp/pull/3214)
2323

24+
* [SDK] Implement spec: MetricFilter
25+
[#3235](https://github.com/open-telemetry/opentelemetry-cpp/pull/3235)
26+
2427
* [EXPORTER] Fix scope attributes missing from otlp traces metrics
2528
[#3185](https://github.com/open-telemetry/opentelemetry-cpp/pull/3185)
2629

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
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> CreateMetricFilter(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+
* TestMetric is called once for every metric stream, in each MetricProducer
76+
* Produce operation.
77+
*/
78+
MetricFilterResult TestMetric(
79+
const opentelemetry::sdk::instrumentationscope::InstrumentationScope &scope,
80+
opentelemetry::nostd::string_view name,
81+
const InstrumentType &type,
82+
opentelemetry::nostd::string_view unit)
83+
{
84+
return test_metric_fn_(scope, name, type, unit);
85+
}
86+
87+
/**
88+
* TestAttributes determines for a given metric stream and attribute set if
89+
* it should be allowed or filtered out.
90+
*
91+
* This operation should only be called if TestMetric operation returned
92+
* kAcceptPartial for the given metric stream arguments.
93+
*/
94+
AttributesFilterResult TestAttributes(
95+
const opentelemetry::sdk::instrumentationscope::InstrumentationScope &scope,
96+
opentelemetry::nostd::string_view name,
97+
const InstrumentType &type,
98+
opentelemetry::nostd::string_view unit,
99+
const PointAttributes &attributes)
100+
{
101+
return test_attributes_fn_(scope, name, type, unit, attributes);
102+
}
103+
104+
private:
105+
TestMetricFn test_metric_fn_;
106+
TestAttributesFn test_attributes_fn_;
107+
};
108+
109+
} // namespace metrics
110+
} // namespace sdk
111+
OPENTELEMETRY_END_NAMESPACE

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

Lines changed: 6 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,8 @@ 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)) {};
8487
virtual ~MetricProducer() = default;
8588

8689
MetricProducer(const MetricProducer &) = delete;
@@ -107,6 +110,8 @@ class MetricProducer
107110
* partial failure.
108111
*/
109112
virtual Result Produce() noexcept = 0;
113+
114+
std::unique_ptr<MetricFilter> metric_filter_;
110115
};
111116

112117
} // 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::shared_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::shared_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: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,14 @@ opentelemetry::common::SystemTimestamp MeterContext::GetSDKStartTime() noexcept
7979
return sdk_start_ts_;
8080
}
8181

82-
void MeterContext::AddMetricReader(std::shared_ptr<MetricReader> reader) noexcept
82+
std::shared_ptr<MetricCollector> MeterContext::AddMetricReader(
83+
std::shared_ptr<MetricReader> reader,
84+
std::unique_ptr<MetricFilter> metric_filter) noexcept
8385
{
84-
auto collector = std::shared_ptr<MetricCollector>{new MetricCollector(this, std::move(reader))};
86+
auto collector = std::shared_ptr<MetricCollector>{
87+
new MetricCollector(this, std::move(reader), std::move(metric_filter))};
8588
collectors_.push_back(collector);
89+
return collector;
8690
}
8791

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

sdk/src/metrics/meter_provider.cc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
#include <chrono>
5+
#include <memory>
56
#include <mutex>
67
#include <utility>
78

@@ -12,6 +13,8 @@
1213
#include "opentelemetry/nostd/string_view.h"
1314
#include "opentelemetry/sdk/common/global_log_handler.h"
1415
#include "opentelemetry/sdk/instrumentationscope/instrumentation_scope.h"
16+
#include "opentelemetry/sdk/metrics/export/metric_filter.h"
17+
#include "opentelemetry/sdk/metrics/export/metric_producer.h"
1518
#include "opentelemetry/sdk/metrics/meter.h"
1619
#include "opentelemetry/sdk/metrics/meter_context.h"
1720
#include "opentelemetry/sdk/metrics/meter_provider.h"
@@ -107,9 +110,11 @@ const resource::Resource &MeterProvider::GetResource() const noexcept
107110
return context_->GetResource();
108111
}
109112

110-
void MeterProvider::AddMetricReader(std::shared_ptr<MetricReader> reader) noexcept
113+
std::shared_ptr<MetricCollector> MeterProvider::AddMetricReader(
114+
std::shared_ptr<MetricReader> reader,
115+
std::unique_ptr<MetricFilter> metric_filter) noexcept
111116
{
112-
context_->AddMetricReader(std::move(reader));
117+
return context_->AddMetricReader(std::move(reader), std::move(metric_filter));
113118
}
114119

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

sdk/src/metrics/state/metric_collector.cc

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "opentelemetry/nostd/function_ref.h"
1212
#include "opentelemetry/sdk/common/global_log_handler.h"
1313
#include "opentelemetry/sdk/metrics/data/metric_data.h"
14+
#include "opentelemetry/sdk/metrics/export/metric_filter.h"
1415
#include "opentelemetry/sdk/metrics/export/metric_producer.h"
1516
#include "opentelemetry/sdk/metrics/instruments.h"
1617
#include "opentelemetry/sdk/metrics/meter.h"
@@ -28,8 +29,11 @@ namespace metrics
2829
using opentelemetry::sdk::resource::Resource;
2930

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

sdk/test/metrics/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ foreach(
2727
observer_result_test
2828
sync_instruments_test
2929
async_instruments_test
30+
metric_collector_test
3031
metric_reader_test
3132
observable_registry_test
3233
periodic_exporting_metric_reader_test

0 commit comments

Comments
 (0)