Skip to content

Commit 7bf1149

Browse files
ethandmdeuroelessarfelipesantoskThomsonTanlalitb
authored
Base2 exponential histogram aggregation (#3346)
* add base2 expo histo aggregation * add base2 expo histo, test, benchmark * add prom, otlp exporter and example * add ostream exporter and example * update vscode launch * run tools/format.sh * add grpc exporter target switch for unix sockets * Added ConvertExponentialHistogramMetric unit test * Update the osstream_metric_test with ExponentialHistogram * update CHANGELOG.md * markdown lint * Comment non-used function add missing includes * add metrics dependency to otlp exporters test build * run format * remove unused function definition * Added empty line in the end of a test file and removed comments * Fix windows build errors * fix iwyu warnings * add comment to trigger pr update * fix additional iwyu warnings * Fix iwyu warning * Fix include order in base2_exponential_histogram_aggregation.h * Add kcumulative and kdelta aggregation temporality test with collect calls for base2 histogram aggregation * add prelim bucketing checks * Tested the exp2 constructor with point data * Fix missing include in sync histogram test * move diff and merge to use union of all buckets approach * make get a const method * update base2 expo hiso diff test * add base2 expo histo test with sync storage collect * uncomment examples * format * use static_cast * fix comments * update changelog * Fix comments and errors in the pipeline * Update sdk/src/metrics/aggregation/base2_exponential_histogram_aggregation.cc Co-authored-by: Tom Tan <[email protected]> * remove unused code * set max_buckets minimum to 2 * Revert otlp grpc client changes Propose change in follow up PR * [wip] make buckets unique ptr * refactor unique_ptr for buckets with deep copies * format * update otlp serialization test with unique ptr * format * Small pipeline fixes * iwyu fix * remove boundary and format --------- Co-authored-by: Ruslan Nigmatullin <[email protected]> Co-authored-by: Felipe C. Dos Santos <[email protected]> Co-authored-by: Tom Tan <[email protected]> Co-authored-by: Lalit Kumar Bhasin <[email protected]> Co-authored-by: Felipe C. Dos Santos <[email protected]>
1 parent 3e761d0 commit 7bf1149

28 files changed

+1589
-50
lines changed

.vscode/launch.json

+28-19
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,33 @@
11
{
22
"version": "0.2.0",
33
"configurations": [
4-
{
5-
"name": "Debug on Windows",
6-
"type": "cppvsdbg",
7-
"request": "launch",
8-
"program": "${workspaceFolder}/build/<path-to-bin-file>",
9-
"args": [],
10-
"stopAtEntry": false,
11-
"cwd": "${workspaceFolder}",
12-
"environment": [],
13-
"externalConsole": false
14-
},
15-
{
16-
"name": "Debug on Linux",
17-
"type": "gdb",
18-
"request": "launch",
19-
"target": "${workspaceFolder}/bazel-bin/<path to the bin file>",
20-
"cwd": "${workspaceRoot}",
21-
"valuesFormatting": "parseText"
22-
}
4+
{
5+
"name": "(ctest) Launch",
6+
"type": "cppdbg",
7+
"cwd": "${cmake.testWorkingDirectory}",
8+
"request": "launch",
9+
"program": "${cmake.testProgram}",
10+
"args": [ "${cmake.testArgs}" ],
11+
// other options...
12+
},
13+
{
14+
"name": "Debug on Windows",
15+
"type": "cppvsdbg",
16+
"request": "launch",
17+
"program": "${workspaceFolder}/build/<path-to-bin-file>",
18+
"args": [],
19+
"stopAtEntry": false,
20+
"cwd": "${workspaceFolder}",
21+
"environment": [],
22+
"externalConsole": false
23+
},
24+
{
25+
"name": "Debug on Linux",
26+
"type": "gdb",
27+
"request": "launch",
28+
"target": "${workspaceFolder}/bazel-bin/<path to the bin file>",
29+
"cwd": "${workspaceRoot}",
30+
"valuesFormatting": "parseText"
31+
}
2332
]
2433
}

CHANGELOG.md

+9
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@ Increment the:
1515

1616
## [Unreleased]
1717

18+
* [SDK] Base2 exponential histogram aggregation
19+
[#3175](https://github.com/open-telemetry/opentelemetry-cpp/pull/3346)
20+
21+
New Features:
22+
23+
Add base2 exponential histogram aggregation. Includes a new aggregation type,
24+
ostream exporter, and otlp/grpc exporter. Updated histogram aggregation and
25+
benchmark tests.
26+
1827
* [API] Remove `WITH_ABSEIL` and `HAVE_ABSEIL`
1928
[#3318](https://github.com/open-telemetry/opentelemetry-cpp/pull/3318)
2029

examples/common/metrics_foo_library/foo_library.cc

+18-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,24 @@ void foo_library::histogram_example(const std::string &name)
100100
std::string histogram_name = name + "_histogram";
101101
auto provider = metrics_api::Provider::GetMeterProvider();
102102
opentelemetry::nostd::shared_ptr<metrics_api::Meter> meter = provider->GetMeter(name, "1.2.0");
103-
auto histogram_counter = meter->CreateDoubleHistogram(histogram_name, "des", "unit");
103+
auto histogram_counter = meter->CreateDoubleHistogram(histogram_name, "des", "histogram-unit");
104+
auto context = opentelemetry::context::Context{};
105+
for (uint32_t i = 0; i < 20; ++i)
106+
{
107+
double val = (rand() % 700) + 1.1;
108+
std::map<std::string, std::string> labels = get_random_attr();
109+
auto labelkv = opentelemetry::common::KeyValueIterableView<decltype(labels)>{labels};
110+
histogram_counter->Record(val, labelkv, context);
111+
std::this_thread::sleep_for(std::chrono::milliseconds(250));
112+
}
113+
}
114+
115+
void foo_library::histogram_exp_example(const std::string &name)
116+
{
117+
std::string histogram_name = name + "_exponential_histogram";
118+
auto provider = metrics_api::Provider::GetMeterProvider();
119+
auto meter = provider->GetMeter(name, "1.2.0");
120+
auto histogram_counter = meter->CreateDoubleHistogram(histogram_name, "des", "histogram-unit");
104121
auto context = opentelemetry::context::Context{};
105122
for (uint32_t i = 0; i < 20; ++i)
106123
{

examples/common/metrics_foo_library/foo_library.h

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class foo_library
1010
public:
1111
static void counter_example(const std::string &name);
1212
static void histogram_example(const std::string &name);
13+
static void histogram_exp_example(const std::string &name);
1314
static void observable_counter_example(const std::string &name);
1415
#if OPENTELEMETRY_ABI_VERSION_NO >= 2
1516
static void gauge_example(const std::string &name);

examples/metrics_simple/metrics_ostream.cc

+35-3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#include "opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader_factory.h"
1616
#include "opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader_options.h"
1717
#include "opentelemetry/sdk/metrics/instruments.h"
18+
#include "opentelemetry/sdk/metrics/meter_context.h"
19+
#include "opentelemetry/sdk/metrics/meter_context_factory.h"
1820
#include "opentelemetry/sdk/metrics/meter_provider.h"
1921
#include "opentelemetry/sdk/metrics/meter_provider_factory.h"
2022
#include "opentelemetry/sdk/metrics/metric_reader.h"
@@ -56,9 +58,9 @@ void InitMetrics(const std::string &name)
5658
auto reader =
5759
metrics_sdk::PeriodicExportingMetricReaderFactory::Create(std::move(exporter), options);
5860

59-
auto provider = opentelemetry::sdk::metrics::MeterProviderFactory::Create();
60-
61-
provider->AddMetricReader(std::move(reader));
61+
auto context = metrics_sdk::MeterContextFactory::Create();
62+
context->AddMetricReader(std::move(reader));
63+
auto provider = opentelemetry::sdk::metrics::MeterProviderFactory::Create(std::move(context));
6264

6365
// counter view
6466
std::string counter_name = name + "_counter";
@@ -112,6 +114,30 @@ void InitMetrics(const std::string &name)
112114
provider->AddView(std::move(histogram_instrument_selector), std::move(histogram_meter_selector),
113115
std::move(histogram_view));
114116

117+
// hisogram view with base2 exponential aggregation
118+
std::string histogram_base2_name = name + "_exponential_histogram";
119+
unit = "histogram-unit";
120+
auto histogram_base2_instrument_selector = metrics_sdk::InstrumentSelectorFactory::Create(
121+
metrics_sdk::InstrumentType::kHistogram, histogram_base2_name, unit);
122+
auto histogram_base2_meter_selector =
123+
metrics_sdk::MeterSelectorFactory::Create(name, version, schema);
124+
auto histogram_base2_aggregation_config =
125+
std::unique_ptr<metrics_sdk::Base2ExponentialHistogramAggregationConfig>(
126+
new metrics_sdk::Base2ExponentialHistogramAggregationConfig);
127+
histogram_base2_aggregation_config->max_scale_ = 3;
128+
histogram_base2_aggregation_config->record_min_max_ = true;
129+
histogram_base2_aggregation_config->max_buckets_ = 100;
130+
131+
std::shared_ptr<metrics_sdk::AggregationConfig> base2_aggregation_config(
132+
std::move(histogram_base2_aggregation_config));
133+
134+
auto histogram_base2_view = metrics_sdk::ViewFactory::Create(
135+
name, "description", unit, metrics_sdk::AggregationType::kBase2ExponentialHistogram,
136+
base2_aggregation_config);
137+
138+
provider->AddView(std::move(histogram_base2_instrument_selector),
139+
std::move(histogram_base2_meter_selector), std::move(histogram_base2_view));
140+
115141
std::shared_ptr<opentelemetry::metrics::MeterProvider> api_provider(std::move(provider));
116142

117143
metrics_sdk::Provider::SetMeterProvider(api_provider);
@@ -147,6 +173,10 @@ int main(int argc, char **argv)
147173
{
148174
foo_library::histogram_example(name);
149175
}
176+
else if (example_type == "exponential_histogram")
177+
{
178+
foo_library::histogram_exp_example(name);
179+
}
150180
#if OPENTELEMETRY_ABI_VERSION_NO >= 2
151181
else if (example_type == "gauge")
152182
{
@@ -170,6 +200,7 @@ int main(int argc, char **argv)
170200
std::thread counter_example{&foo_library::counter_example, name};
171201
std::thread observable_counter_example{&foo_library::observable_counter_example, name};
172202
std::thread histogram_example{&foo_library::histogram_example, name};
203+
std::thread histogram_exp_example{&foo_library::histogram_exp_example, name};
173204
#if OPENTELEMETRY_ABI_VERSION_NO >= 2
174205
std::thread gauge_example{&foo_library::gauge_example, name};
175206
#endif
@@ -181,6 +212,7 @@ int main(int argc, char **argv)
181212
counter_example.join();
182213
observable_counter_example.join();
183214
histogram_example.join();
215+
histogram_exp_example.join();
184216
#if OPENTELEMETRY_ABI_VERSION_NO >= 2
185217
gauge_example.join();
186218
#endif

examples/otlp/grpc_metric_main.cc

+48-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
// Copyright The OpenTelemetry Authors
22
// SPDX-License-Identifier: Apache-2.0
33

4+
#include "grpcpp/grpcpp.h"
5+
#include "opentelemetry/exporters/otlp/otlp_grpc_exporter.h"
6+
47
#include "opentelemetry/exporters/otlp/otlp_grpc_metric_exporter_factory.h"
58
#include "opentelemetry/metrics/provider.h"
69
#include "opentelemetry/sdk/metrics/aggregation/default_aggregation.h"
@@ -11,6 +14,9 @@
1114
#include "opentelemetry/sdk/metrics/meter_provider.h"
1215
#include "opentelemetry/sdk/metrics/meter_provider_factory.h"
1316
#include "opentelemetry/sdk/metrics/provider.h"
17+
#include "opentelemetry/sdk/metrics/view/instrument_selector_factory.h"
18+
#include "opentelemetry/sdk/metrics/view/meter_selector_factory.h"
19+
#include "opentelemetry/sdk/metrics/view/view_factory.h"
1420

1521
#include <memory>
1622
#include <thread>
@@ -31,7 +37,7 @@ namespace
3137

3238
otlp_exporter::OtlpGrpcMetricExporterOptions exporter_options;
3339

34-
void InitMetrics()
40+
void InitMetrics(std::string &name)
3541
{
3642
auto exporter = otlp_exporter::OtlpGrpcMetricExporterFactory::Create(exporter_options);
3743

@@ -49,10 +55,34 @@ void InitMetrics()
4955
auto context = metric_sdk::MeterContextFactory::Create();
5056
context->AddMetricReader(std::move(reader));
5157

52-
auto u_provider = metric_sdk::MeterProviderFactory::Create(std::move(context));
53-
std::shared_ptr<opentelemetry::metrics::MeterProvider> provider(std::move(u_provider));
58+
auto provider = metric_sdk::MeterProviderFactory::Create(std::move(context));
59+
60+
// histogram view
61+
std::string histogram_name = name + "_exponential_histogram";
62+
std::string unit = "histogram-unit";
63+
64+
auto histogram_instrument_selector = metric_sdk::InstrumentSelectorFactory::Create(
65+
metric_sdk::InstrumentType::kHistogram, histogram_name, unit);
66+
67+
auto histogram_meter_selector = metric_sdk::MeterSelectorFactory::Create(name, version, schema);
68+
69+
auto histogram_aggregation_config =
70+
std::unique_ptr<metric_sdk::Base2ExponentialHistogramAggregationConfig>(
71+
new metric_sdk::Base2ExponentialHistogramAggregationConfig);
72+
73+
std::shared_ptr<metric_sdk::AggregationConfig> aggregation_config(
74+
std::move(histogram_aggregation_config));
75+
76+
auto histogram_view = metric_sdk::ViewFactory::Create(
77+
name, "des", unit, metric_sdk::AggregationType::kBase2ExponentialHistogram,
78+
aggregation_config);
5479

55-
metric_sdk::Provider::SetMeterProvider(provider);
80+
provider->AddView(std::move(histogram_instrument_selector), std::move(histogram_meter_selector),
81+
std::move(histogram_view));
82+
83+
std::shared_ptr<opentelemetry::metrics::MeterProvider> api_provider(std::move(provider));
84+
85+
metric_sdk::Provider::SetMeterProvider(api_provider);
5686
}
5787

5888
void CleanupMetrics()
@@ -78,10 +108,17 @@ int main(int argc, char *argv[])
78108
}
79109
}
80110
}
111+
std::cout << "Using endpoint: " << exporter_options.endpoint << std::endl;
112+
std::cout << "Using example type: " << example_type << std::endl;
113+
std::cout << "Using cacert path: " << exporter_options.ssl_credentials_cacert_path << std::endl;
114+
std::cout << "Using ssl credentials: " << exporter_options.use_ssl_credentials << std::endl;
115+
81116
// Removing this line will leave the default noop MetricProvider in place.
82-
InitMetrics();
117+
83118
std::string name{"otlp_grpc_metric_example"};
84119

120+
InitMetrics(name);
121+
85122
if (example_type == "counter")
86123
{
87124
foo_library::counter_example(name);
@@ -94,6 +131,10 @@ int main(int argc, char *argv[])
94131
{
95132
foo_library::histogram_example(name);
96133
}
134+
else if (example_type == "exponential_histogram")
135+
{
136+
foo_library::histogram_exp_example(name);
137+
}
97138
#if OPENTELEMETRY_ABI_VERSION_NO >= 2
98139
else if (example_type == "gauge")
99140
{
@@ -105,13 +146,15 @@ int main(int argc, char *argv[])
105146
std::thread counter_example{&foo_library::counter_example, name};
106147
std::thread observable_counter_example{&foo_library::observable_counter_example, name};
107148
std::thread histogram_example{&foo_library::histogram_example, name};
149+
std::thread histogram_exp_example{&foo_library::histogram_exp_example, name};
108150
#if OPENTELEMETRY_ABI_VERSION_NO >= 2
109151
std::thread gauge_example{&foo_library::gauge_example, name};
110152
#endif
111153

112154
counter_example.join();
113155
observable_counter_example.join();
114156
histogram_example.join();
157+
histogram_exp_example.join();
115158
#if OPENTELEMETRY_ABI_VERSION_NO >= 2
116159
gauge_example.join();
117160
#endif

exporters/ostream/src/metric_exporter.cc

+39
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <ctime>
99
#include <iterator>
1010
#include <map>
11+
#include <memory>
1112
#include <mutex>
1213
#include <ostream>
1314
#include <string>
@@ -24,6 +25,7 @@
2425
#include "opentelemetry/sdk/common/exporter_utils.h"
2526
#include "opentelemetry/sdk/common/global_log_handler.h"
2627
#include "opentelemetry/sdk/instrumentationscope/instrumentation_scope.h"
28+
#include "opentelemetry/sdk/metrics/data/circular_buffer.h"
2729
#include "opentelemetry/sdk/metrics/data/metric_data.h"
2830
#include "opentelemetry/sdk/metrics/data/point_data.h"
2931
#include "opentelemetry/sdk/metrics/export/metric_producer.h"
@@ -247,6 +249,43 @@ void OStreamMetricExporter::printPointData(const opentelemetry::sdk::metrics::Po
247249
sout_ << nostd::get<int64_t>(last_point_data.value_);
248250
}
249251
}
252+
else if (nostd::holds_alternative<sdk::metrics::Base2ExponentialHistogramPointData>(point_data))
253+
{
254+
auto histogram_point_data =
255+
nostd::get<sdk::metrics::Base2ExponentialHistogramPointData>(point_data);
256+
if (!histogram_point_data.positive_buckets_ && !histogram_point_data.negative_buckets_)
257+
{
258+
return;
259+
}
260+
sout_ << "\n type: Base2ExponentialHistogramPointData";
261+
sout_ << "\n count: " << histogram_point_data.count_;
262+
sout_ << "\n sum: " << histogram_point_data.sum_;
263+
sout_ << "\n zero_count: " << histogram_point_data.zero_count_;
264+
if (histogram_point_data.record_min_max_)
265+
{
266+
sout_ << "\n min: " << histogram_point_data.min_;
267+
sout_ << "\n max: " << histogram_point_data.max_;
268+
}
269+
sout_ << "\n scale: " << histogram_point_data.scale_;
270+
sout_ << "\n positive buckets:";
271+
if (!histogram_point_data.positive_buckets_->Empty())
272+
{
273+
for (auto i = histogram_point_data.positive_buckets_->StartIndex();
274+
i <= histogram_point_data.positive_buckets_->EndIndex(); ++i)
275+
{
276+
sout_ << "\n\t" << i << ": " << histogram_point_data.positive_buckets_->Get(i);
277+
}
278+
}
279+
sout_ << "\n negative buckets:";
280+
if (!histogram_point_data.negative_buckets_->Empty())
281+
{
282+
for (auto i = histogram_point_data.negative_buckets_->StartIndex();
283+
i <= histogram_point_data.negative_buckets_->EndIndex(); ++i)
284+
{
285+
sout_ << "\n\t" << i << ": " << histogram_point_data.negative_buckets_->Get(i);
286+
}
287+
}
288+
}
250289
}
251290

252291
void OStreamMetricExporter::printPointAttributes(

0 commit comments

Comments
 (0)