diff --git a/exporters/otlp/src/otlp_http_exporter.cc b/exporters/otlp/src/otlp_http_exporter.cc index 1616ea3aec..0fa1bf61e8 100644 --- a/exporters/otlp/src/otlp_http_exporter.cc +++ b/exporters/otlp/src/otlp_http_exporter.cc @@ -69,6 +69,9 @@ opentelemetry::sdk::common::ExportResult OtlpHttpExporter::Export( { if (http_client_->IsShutdown()) { + std::size_t span_count = spans.size(); + OTEL_INTERNAL_LOG_ERROR("[OTLP HTTP Client] ERROR: Export " + << span_count << " trace span(s) failed, exporter is shutdown"); return opentelemetry::sdk::common::ExportResult::kFailure; } diff --git a/exporters/otlp/src/otlp_http_log_exporter.cc b/exporters/otlp/src/otlp_http_log_exporter.cc index 11141344c2..24a5b3d0fd 100644 --- a/exporters/otlp/src/otlp_http_log_exporter.cc +++ b/exporters/otlp/src/otlp_http_log_exporter.cc @@ -71,6 +71,9 @@ opentelemetry::sdk::common::ExportResult OtlpHttpLogExporter::Export( { if (http_client_->IsShutdown()) { + std::size_t log_count = logs.size(); + OTEL_INTERNAL_LOG_ERROR("[OTLP HTTP Client] ERROR: Export " + << log_count << " log(s) failed, exporter is shutdown"); return opentelemetry::sdk::common::ExportResult::kFailure; } diff --git a/exporters/otlp/src/otlp_http_metric_exporter.cc b/exporters/otlp/src/otlp_http_metric_exporter.cc index e91a37dff8..90fece02f0 100644 --- a/exporters/otlp/src/otlp_http_metric_exporter.cc +++ b/exporters/otlp/src/otlp_http_metric_exporter.cc @@ -66,6 +66,9 @@ opentelemetry::sdk::common::ExportResult OtlpHttpMetricExporter::Export( { if (http_client_->IsShutdown()) { + std::size_t metric_count = data.instrumentation_info_metric_data_.size(); + OTEL_INTERNAL_LOG_ERROR("[OTLP HTTP Client] ERROR: Export " + << metric_count << " metric(s) failed, exporter is shutdown"); return opentelemetry::sdk::common::ExportResult::kFailure; } diff --git a/exporters/otlp/src/otlp_metric_utils.cc b/exporters/otlp/src/otlp_metric_utils.cc index eb3e72ac3a..c9176aab13 100644 --- a/exporters/otlp/src/otlp_metric_utils.cc +++ b/exporters/otlp/src/otlp_metric_utils.cc @@ -144,23 +144,23 @@ void OtlpMetricUtils::ConvertGaugeMetric(const opentelemetry::sdk::metrics::Metr auto ts = metric_data.end_ts.time_since_epoch().count(); for (auto &point_data_with_attributes : metric_data.point_data_attr_) { - proto::metrics::v1::NumberDataPoint *proto_sum_point_data = gauge->add_data_points(); - proto_sum_point_data->set_start_time_unix_nano(start_ts); - proto_sum_point_data->set_time_unix_nano(ts); - auto sum_data = nostd::get(point_data_with_attributes.point_data); + proto::metrics::v1::NumberDataPoint *proto_gauge_point_data = gauge->add_data_points(); + proto_gauge_point_data->set_start_time_unix_nano(start_ts); + proto_gauge_point_data->set_time_unix_nano(ts); + auto gauge_data = nostd::get(point_data_with_attributes.point_data); - if ((nostd::holds_alternative(sum_data.value_))) + if ((nostd::holds_alternative(gauge_data.value_))) { - proto_sum_point_data->set_as_int(nostd::get(sum_data.value_)); + proto_gauge_point_data->set_as_int(nostd::get(gauge_data.value_)); } else { - proto_sum_point_data->set_as_double(nostd::get(sum_data.value_)); + proto_gauge_point_data->set_as_double(nostd::get(gauge_data.value_)); } // set attributes for (auto &kv_attr : point_data_with_attributes.attributes) { - OtlpPopulateAttributeUtils::PopulateAttribute(proto_sum_point_data->add_attributes(), + OtlpPopulateAttributeUtils::PopulateAttribute(proto_gauge_point_data->add_attributes(), kv_attr.first, kv_attr.second); } } @@ -197,9 +197,7 @@ void OtlpMetricUtils::PopulateResourceMetrics( const opentelemetry::sdk::metrics::ResourceMetrics &data, proto::metrics::v1::ResourceMetrics *resource_metrics) noexcept { - proto::resource::v1::Resource proto; - OtlpPopulateAttributeUtils::PopulateAttribute(&proto, *(data.resource_)); - *resource_metrics->mutable_resource() = proto; + OtlpPopulateAttributeUtils::PopulateAttribute(resource_metrics->mutable_resource(), *(data.resource_)); for (auto &instrumentation_metrics : data.instrumentation_info_metric_data_) { @@ -208,17 +206,14 @@ void OtlpMetricUtils::PopulateResourceMetrics( continue; } auto instrumentation_lib_metrics = resource_metrics->add_instrumentation_library_metrics(); - proto::common::v1::InstrumentationLibrary instrumentation_library; - instrumentation_library.set_name(instrumentation_metrics.instrumentation_library_->GetName()); - instrumentation_library.set_version( + proto::common::v1::InstrumentationLibrary* instrumentation_library = instrumentation_lib_metrics->mutable_instrumentation_library(); + instrumentation_library->set_name(instrumentation_metrics.instrumentation_library_->GetName()); + instrumentation_library->set_version( instrumentation_metrics.instrumentation_library_->GetVersion()); - *instrumentation_lib_metrics->mutable_instrumentation_library() = instrumentation_library; for (auto &metric_data : instrumentation_metrics.metric_data_) { - proto::metrics::v1::Metric metric; - PopulateInstrumentationInfoMetric(metric_data, &metric); - *instrumentation_lib_metrics->add_metrics() = metric; + PopulateInstrumentationInfoMetric(metric_data, instrumentation_lib_metrics->add_metrics()); } } } diff --git a/exporters/otlp/test/otlp_http_metric_exporter_test.cc b/exporters/otlp/test/otlp_http_metric_exporter_test.cc index dbadb7b78e..9c2101f23f 100644 --- a/exporters/otlp/test/otlp_http_metric_exporter_test.cc +++ b/exporters/otlp/test/otlp_http_metric_exporter_test.cc @@ -4,6 +4,7 @@ #ifndef ENABLE_METRICS_PREVIEW # include +# include # include # include "opentelemetry/exporters/otlp/otlp_http_metric_exporter.h" @@ -43,10 +44,15 @@ namespace exporter namespace otlp { -template -static nostd::span MakeSpan(T (&array)[N]) +template +static IntegerType JsonToInteger(nlohmann::json value) { - return nostd::span(array); + if (value.is_string()) + { + return static_cast(strtol(value.get().c_str(), nullptr, 10)); + } + + return value.get(); } OtlpHttpClientOptions MakeOtlpHttpClientOptions(HttpRequestContentType content_type, @@ -139,7 +145,7 @@ class OtlpHttpMetricExporterTestPeer : public ::testing::Test auto mock_session = std::static_pointer_cast(no_send_client->session_); EXPECT_CALL(*mock_session, SendRequest) - .WillOnce([&mock_session, &data, &resource]( + .WillOnce([&mock_session]( std::shared_ptr callback) { auto check_json = nlohmann::json::parse(mock_session->GetRequest()->body_, nullptr, false); @@ -236,7 +242,7 @@ class OtlpHttpMetricExporterTestPeer : public ::testing::Test std::static_pointer_cast(no_send_client->session_); EXPECT_CALL(*mock_session, SendRequest) - .WillOnce([&mock_session, &data, &resource]( + .WillOnce([&mock_session]( std::shared_ptr callback) { opentelemetry::proto::collector::metrics::v1::ExportMetricsServiceRequest request_body; request_body.ParseFromArray(&mock_session->GetRequest()->body_[0], @@ -289,6 +295,503 @@ class OtlpHttpMetricExporterTestPeer : public ::testing::Test exporter->ForceFlush(); } + + void ExportJsonIntegrationTestExportLastValuePointData( +# ifdef ENABLE_ASYNC_EXPORT + bool async_mode +# endif + ) + { + auto mock_otlp_client = + OtlpHttpMetricExporterTestPeer::GetMockOtlpHttpClient(HttpRequestContentType::kJson +# ifdef ENABLE_ASYNC_EXPORT + , + async_mode +# endif + ); + auto mock_otlp_http_client = mock_otlp_client.first; + auto client = mock_otlp_client.second; + auto exporter = GetExporter(std::unique_ptr{mock_otlp_http_client}); + + opentelemetry::sdk::metrics::LastValuePointData last_value_point_data{}; + last_value_point_data.value_ = 10.0; + last_value_point_data.is_lastvalue_valid_ = true; + last_value_point_data.sample_ts_ = opentelemetry::common::SystemTimestamp{}; + opentelemetry::sdk::metrics::LastValuePointData last_value_point_data2{}; + last_value_point_data2.value_ = 20l; + last_value_point_data2.is_lastvalue_valid_ = true; + last_value_point_data2.sample_ts_ = opentelemetry::common::SystemTimestamp{}; + opentelemetry::sdk::metrics::MetricData metric_data{ + opentelemetry::sdk::metrics::InstrumentDescriptor{ + "metrics_library_name", "metrics_description", "metrics_unit", + opentelemetry::sdk::metrics::InstrumentType::kObservableGauge, + opentelemetry::sdk::metrics::InstrumentValueType::kDouble}, + opentelemetry::sdk::metrics::AggregationTemporality::kDelta, + opentelemetry::common::SystemTimestamp{}, opentelemetry::common::SystemTimestamp{}, + std::vector{ + {opentelemetry::sdk::metrics::PointAttributes{{"a1", "b1"}}, last_value_point_data}, + {opentelemetry::sdk::metrics::PointAttributes{{"a2", "b2"}}, last_value_point_data2}}}; + + opentelemetry::sdk::metrics::ResourceMetrics data; + auto resource = opentelemetry::sdk::resource::Resource::Create( + opentelemetry::sdk::resource::ResourceAttributes{}); + data.resource_ = &resource; + auto instrumentation_library = + opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary::Create("library_name", + "1.5.0"); + data.instrumentation_info_metric_data_ = + std::vector{ + {instrumentation_library.get(), + std::vector{metric_data}}}; + + auto no_send_client = std::static_pointer_cast(client); + auto mock_session = + std::static_pointer_cast(no_send_client->session_); + EXPECT_CALL(*mock_session, SendRequest) + .WillOnce([&mock_session]( + std::shared_ptr callback) { + auto check_json = + nlohmann::json::parse(mock_session->GetRequest()->body_, nullptr, false); + + auto resource_metrics = *check_json["resource_metrics"].begin(); + // auto scope_metrics = *resource_metrics["scope_metrics"].begin(); + // auto scope = scope_metrics["scope"]; + auto instrumentation_library_metrics = + *resource_metrics["instrumentation_library_metrics"].begin(); + auto scope = instrumentation_library_metrics["instrumentation_library"]; + EXPECT_EQ("library_name", scope["name"].get()); + EXPECT_EQ("1.5.0", scope["version"].get()); + + // auto metric = *scope_metrics["metrics"].begin(); + auto metric = *instrumentation_library_metrics["metrics"].begin(); + EXPECT_EQ("metrics_library_name", metric["name"].get()); + EXPECT_EQ("metrics_description", metric["description"].get()); + EXPECT_EQ("metrics_unit", metric["unit"].get()); + + auto data_points = metric["gauge"]["data_points"]; + EXPECT_EQ(10.0, data_points[0]["as_double"].get()); + EXPECT_EQ(20l, JsonToInteger(data_points[1]["as_int"])); + + auto custom_header = mock_session->GetRequest()->headers_.find("Custom-Header-Key"); + ASSERT_TRUE(custom_header != mock_session->GetRequest()->headers_.end()); + if (custom_header != mock_session->GetRequest()->headers_.end()) + { + EXPECT_EQ("Custom-Header-Value", custom_header->second); + } + + http_client::nosend::Response response; + response.Finish(*callback.get()); + }); + + auto result = exporter->Export(data); + EXPECT_EQ(result, opentelemetry::sdk::common::ExportResult::kSuccess); + + exporter->ForceFlush(); + } + + void ExportBinaryIntegrationTestExportLastValuePointData( +# ifdef ENABLE_ASYNC_EXPORT + bool async_mode +# endif + ) + { + auto mock_otlp_client = + OtlpHttpMetricExporterTestPeer::GetMockOtlpHttpClient(HttpRequestContentType::kBinary +# ifdef ENABLE_ASYNC_EXPORT + , + async_mode +# endif + ); + auto mock_otlp_http_client = mock_otlp_client.first; + auto client = mock_otlp_client.second; + auto exporter = GetExporter(std::unique_ptr{mock_otlp_http_client}); + + bool attribute_storage_bool_value[] = {true, false, true}; + int32_t attribute_storage_int32_value[] = {1, 2}; + uint32_t attribute_storage_uint32_value[] = {3, 4}; + int64_t attribute_storage_int64_value[] = {5, 6}; + uint64_t attribute_storage_uint64_value[] = {7, 8}; + double attribute_storage_double_value[] = {3.2, 3.3}; + std::string attribute_storage_string_value[] = {"vector", "string"}; + + opentelemetry::sdk::metrics::SumPointData sum_point_data{}; + sum_point_data.value_ = 10.0; + opentelemetry::sdk::metrics::SumPointData sum_point_data2{}; + sum_point_data2.value_ = 20.0; + opentelemetry::sdk::metrics::ResourceMetrics data; + auto resource = opentelemetry::sdk::resource::Resource::Create( + opentelemetry::sdk::resource::ResourceAttributes{}); + data.resource_ = &resource; + auto instrumentation_library = + opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary::Create("library_name", + "1.5.0"); + opentelemetry::sdk::metrics::LastValuePointData last_value_point_data{}; + last_value_point_data.value_ = 10.0; + last_value_point_data.is_lastvalue_valid_ = true; + last_value_point_data.sample_ts_ = opentelemetry::common::SystemTimestamp{}; + opentelemetry::sdk::metrics::LastValuePointData last_value_point_data2{}; + last_value_point_data2.value_ = 20l; + last_value_point_data2.is_lastvalue_valid_ = true; + last_value_point_data2.sample_ts_ = opentelemetry::common::SystemTimestamp{}; + opentelemetry::sdk::metrics::MetricData metric_data{ + opentelemetry::sdk::metrics::InstrumentDescriptor{ + "metrics_library_name", "metrics_description", "metrics_unit", + opentelemetry::sdk::metrics::InstrumentType::kObservableGauge, + opentelemetry::sdk::metrics::InstrumentValueType::kDouble}, + opentelemetry::sdk::metrics::AggregationTemporality::kDelta, + opentelemetry::common::SystemTimestamp{}, opentelemetry::common::SystemTimestamp{}, + std::vector{ + {opentelemetry::sdk::metrics::PointAttributes{{"a1", "b1"}}, last_value_point_data}, + {opentelemetry::sdk::metrics::PointAttributes{{"a2", "b2"}}, last_value_point_data2}}}; + + data.instrumentation_info_metric_data_ = + std::vector{ + {instrumentation_library.get(), + std::vector{metric_data}}}; + + auto no_send_client = std::static_pointer_cast(client); + auto mock_session = + std::static_pointer_cast(no_send_client->session_); + + EXPECT_CALL(*mock_session, SendRequest) + .WillOnce([&mock_session]( + std::shared_ptr callback) { + opentelemetry::proto::collector::metrics::v1::ExportMetricsServiceRequest request_body; + request_body.ParseFromArray(&mock_session->GetRequest()->body_[0], + static_cast(mock_session->GetRequest()->body_.size())); + // auto &scope_metrics = request_body.resource_metrics(0).scope_metrics(0); + // auto &scope = instrumentation_library_metrics.scope(); + auto &instrumentation_library_metrics = + request_body.resource_metrics(0).instrumentation_library_metrics(0); + auto &scope = instrumentation_library_metrics.instrumentation_library(); + EXPECT_EQ("library_name", scope.name()); + EXPECT_EQ("1.5.0", scope.version()); + + // auto metric = *scope_metrics["metrics"].begin(); + auto &metric = instrumentation_library_metrics.metrics(0); + EXPECT_EQ("metrics_library_name", metric.name()); + EXPECT_EQ("metrics_description", metric.description()); + EXPECT_EQ("metrics_unit", metric.unit()); + + auto &data_points = metric.gauge().data_points(); + EXPECT_EQ(10.0, data_points.Get(0).as_double()); + bool has_attributes = false; + for (auto &kv : data_points.Get(0).attributes()) + { + if (kv.key() == "a1") + { + EXPECT_EQ("b1", kv.value().string_value()); + has_attributes = true; + } + } + EXPECT_TRUE(has_attributes); + + EXPECT_EQ(20, data_points.Get(1).as_int()); + has_attributes = false; + for (auto &kv : data_points.Get(1).attributes()) + { + if (kv.key() == "a2") + { + EXPECT_EQ("b2", kv.value().string_value()); + has_attributes = true; + } + } + EXPECT_TRUE(has_attributes); + + http_client::nosend::Response response; + response.Finish(*callback.get()); + }); + + auto result = exporter->Export(data); + EXPECT_EQ(result, opentelemetry::sdk::common::ExportResult::kSuccess); + + exporter->ForceFlush(); + } + + void ExportJsonIntegrationTestExportHistogramPointData( +# ifdef ENABLE_ASYNC_EXPORT + bool async_mode +# endif + ) + { + auto mock_otlp_client = + OtlpHttpMetricExporterTestPeer::GetMockOtlpHttpClient(HttpRequestContentType::kJson +# ifdef ENABLE_ASYNC_EXPORT + , + async_mode +# endif + ); + auto mock_otlp_http_client = mock_otlp_client.first; + auto client = mock_otlp_client.second; + auto exporter = GetExporter(std::unique_ptr{mock_otlp_http_client}); + + opentelemetry::sdk::metrics::HistogramPointData histogram_point_data{}; + histogram_point_data.boundaries_ = std::list{10.1, 20.2, 30.2}; + histogram_point_data.count_ = 3; + histogram_point_data.counts_ = {200, 300, 400, 500}; + histogram_point_data.sum_ = 900.5; + opentelemetry::sdk::metrics::HistogramPointData histogram_point_data2{}; + histogram_point_data2.boundaries_ = std::list{10, 20, 30}; + histogram_point_data2.count_ = 3; + histogram_point_data2.counts_ = {200, 300, 400, 500}; + histogram_point_data2.sum_ = 900l; + + opentelemetry::sdk::metrics::MetricData metric_data{ + opentelemetry::sdk::metrics::InstrumentDescriptor{ + "metrics_library_name", "metrics_description", "metrics_unit", + opentelemetry::sdk::metrics::InstrumentType::kHistogram, + opentelemetry::sdk::metrics::InstrumentValueType::kDouble}, + opentelemetry::sdk::metrics::AggregationTemporality::kDelta, + opentelemetry::common::SystemTimestamp{}, opentelemetry::common::SystemTimestamp{}, + std::vector{ + {opentelemetry::sdk::metrics::PointAttributes{{"a1", "b1"}}, histogram_point_data}, + {opentelemetry::sdk::metrics::PointAttributes{{"a2", "b2"}}, histogram_point_data2}}}; + + opentelemetry::sdk::metrics::ResourceMetrics data; + auto resource = opentelemetry::sdk::resource::Resource::Create( + opentelemetry::sdk::resource::ResourceAttributes{}); + data.resource_ = &resource; + auto instrumentation_library = + opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary::Create("library_name", + "1.5.0"); + data.instrumentation_info_metric_data_ = + std::vector{ + {instrumentation_library.get(), + std::vector{metric_data}}}; + + auto no_send_client = std::static_pointer_cast(client); + auto mock_session = + std::static_pointer_cast(no_send_client->session_); + EXPECT_CALL(*mock_session, SendRequest) + .WillOnce([&mock_session]( + std::shared_ptr callback) { + auto check_json = + nlohmann::json::parse(mock_session->GetRequest()->body_, nullptr, false); + + auto resource_metrics = *check_json["resource_metrics"].begin(); + // auto scope_metrics = *resource_metrics["scope_metrics"].begin(); + // auto scope = scope_metrics["scope"]; + auto instrumentation_library_metrics = + *resource_metrics["instrumentation_library_metrics"].begin(); + auto scope = instrumentation_library_metrics["instrumentation_library"]; + EXPECT_EQ("library_name", scope["name"].get()); + EXPECT_EQ("1.5.0", scope["version"].get()); + + // auto metric = *scope_metrics["metrics"].begin(); + auto metric = *instrumentation_library_metrics["metrics"].begin(); + EXPECT_EQ("metrics_library_name", metric["name"].get()); + EXPECT_EQ("metrics_description", metric["description"].get()); + EXPECT_EQ("metrics_unit", metric["unit"].get()); + + auto data_points = metric["histogram"]["data_points"]; + EXPECT_EQ(3, JsonToInteger(data_points[0]["count"])); + EXPECT_EQ(900.5, data_points[0]["sum"].get()); + EXPECT_EQ(4, data_points[0]["bucket_counts"].size()); + if (4 == data_points[0]["bucket_counts"].size()) + { + EXPECT_EQ(200, JsonToInteger(data_points[0]["bucket_counts"][0])); + EXPECT_EQ(300, JsonToInteger(data_points[0]["bucket_counts"][1])); + EXPECT_EQ(400, JsonToInteger(data_points[0]["bucket_counts"][2])); + EXPECT_EQ(500, JsonToInteger(data_points[0]["bucket_counts"][3])); + } + EXPECT_EQ(3, data_points[0]["explicit_bounds"].size()); + if (3 == data_points[0]["explicit_bounds"].size()) + { + EXPECT_EQ(10.1, data_points[0]["explicit_bounds"][0].get()); + EXPECT_EQ(20.2, data_points[0]["explicit_bounds"][1].get()); + EXPECT_EQ(30.2, data_points[0]["explicit_bounds"][2].get()); + } + + EXPECT_EQ(3, JsonToInteger(data_points[1]["count"])); + EXPECT_EQ(900.0, data_points[1]["sum"].get()); + EXPECT_EQ(4, data_points[1]["bucket_counts"].size()); + if (4 == data_points[1]["bucket_counts"].size()) + { + EXPECT_EQ(200, JsonToInteger(data_points[1]["bucket_counts"][0])); + EXPECT_EQ(300, JsonToInteger(data_points[1]["bucket_counts"][1])); + EXPECT_EQ(400, JsonToInteger(data_points[1]["bucket_counts"][2])); + EXPECT_EQ(500, JsonToInteger(data_points[1]["bucket_counts"][3])); + } + EXPECT_EQ(3, data_points[1]["explicit_bounds"].size()); + if (3 == data_points[1]["explicit_bounds"].size()) + { + EXPECT_EQ(10.0, data_points[1]["explicit_bounds"][0].get()); + EXPECT_EQ(20.0, data_points[1]["explicit_bounds"][1].get()); + EXPECT_EQ(30.0, data_points[1]["explicit_bounds"][2].get()); + } + + auto custom_header = mock_session->GetRequest()->headers_.find("Custom-Header-Key"); + ASSERT_TRUE(custom_header != mock_session->GetRequest()->headers_.end()); + if (custom_header != mock_session->GetRequest()->headers_.end()) + { + EXPECT_EQ("Custom-Header-Value", custom_header->second); + } + + http_client::nosend::Response response; + response.Finish(*callback.get()); + }); + + auto result = exporter->Export(data); + EXPECT_EQ(result, opentelemetry::sdk::common::ExportResult::kSuccess); + + exporter->ForceFlush(); + } + + void ExportBinaryIntegrationTestExportHistogramPointData( +# ifdef ENABLE_ASYNC_EXPORT + bool async_mode +# endif + ) + { + auto mock_otlp_client = + OtlpHttpMetricExporterTestPeer::GetMockOtlpHttpClient(HttpRequestContentType::kBinary +# ifdef ENABLE_ASYNC_EXPORT + , + async_mode +# endif + ); + auto mock_otlp_http_client = mock_otlp_client.first; + auto client = mock_otlp_client.second; + auto exporter = GetExporter(std::unique_ptr{mock_otlp_http_client}); + + bool attribute_storage_bool_value[] = {true, false, true}; + int32_t attribute_storage_int32_value[] = {1, 2}; + uint32_t attribute_storage_uint32_value[] = {3, 4}; + int64_t attribute_storage_int64_value[] = {5, 6}; + uint64_t attribute_storage_uint64_value[] = {7, 8}; + double attribute_storage_double_value[] = {3.2, 3.3}; + std::string attribute_storage_string_value[] = {"vector", "string"}; + + opentelemetry::sdk::metrics::SumPointData sum_point_data{}; + sum_point_data.value_ = 10.0; + opentelemetry::sdk::metrics::SumPointData sum_point_data2{}; + sum_point_data2.value_ = 20.0; + opentelemetry::sdk::metrics::ResourceMetrics data; + auto resource = opentelemetry::sdk::resource::Resource::Create( + opentelemetry::sdk::resource::ResourceAttributes{}); + data.resource_ = &resource; + auto instrumentation_library = + opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary::Create("library_name", + "1.5.0"); + + opentelemetry::sdk::metrics::HistogramPointData histogram_point_data{}; + histogram_point_data.boundaries_ = std::list{10.1, 20.2, 30.2}; + histogram_point_data.count_ = 3; + histogram_point_data.counts_ = {200, 300, 400, 500}; + histogram_point_data.sum_ = 900.5; + opentelemetry::sdk::metrics::HistogramPointData histogram_point_data2{}; + histogram_point_data2.boundaries_ = std::list{10, 20, 30}; + histogram_point_data2.count_ = 3; + histogram_point_data2.counts_ = {200, 300, 400, 500}; + histogram_point_data2.sum_ = 900l; + + opentelemetry::sdk::metrics::MetricData metric_data{ + opentelemetry::sdk::metrics::InstrumentDescriptor{ + "metrics_library_name", "metrics_description", "metrics_unit", + opentelemetry::sdk::metrics::InstrumentType::kHistogram, + opentelemetry::sdk::metrics::InstrumentValueType::kDouble}, + opentelemetry::sdk::metrics::AggregationTemporality::kDelta, + opentelemetry::common::SystemTimestamp{}, opentelemetry::common::SystemTimestamp{}, + std::vector{ + {opentelemetry::sdk::metrics::PointAttributes{{"a1", "b1"}}, histogram_point_data}, + {opentelemetry::sdk::metrics::PointAttributes{{"a2", "b2"}}, histogram_point_data2}}}; + + data.instrumentation_info_metric_data_ = + std::vector{ + {instrumentation_library.get(), + std::vector{metric_data}}}; + + auto no_send_client = std::static_pointer_cast(client); + auto mock_session = + std::static_pointer_cast(no_send_client->session_); + + EXPECT_CALL(*mock_session, SendRequest) + .WillOnce([&mock_session]( + std::shared_ptr callback) { + opentelemetry::proto::collector::metrics::v1::ExportMetricsServiceRequest request_body; + request_body.ParseFromArray(&mock_session->GetRequest()->body_[0], + static_cast(mock_session->GetRequest()->body_.size())); + // auto &scope_metrics = request_body.resource_metrics(0).scope_metrics(0); + // auto &scope = instrumentation_library_metrics.scope(); + auto &instrumentation_library_metrics = + request_body.resource_metrics(0).instrumentation_library_metrics(0); + auto &scope = instrumentation_library_metrics.instrumentation_library(); + EXPECT_EQ("library_name", scope.name()); + EXPECT_EQ("1.5.0", scope.version()); + + // auto metric = *scope_metrics["metrics"].begin(); + auto &metric = instrumentation_library_metrics.metrics(0); + EXPECT_EQ("metrics_library_name", metric.name()); + EXPECT_EQ("metrics_description", metric.description()); + EXPECT_EQ("metrics_unit", metric.unit()); + + auto &data_points = metric.histogram().data_points(); + EXPECT_EQ(3, data_points.Get(0).count()); + EXPECT_EQ(900.5, data_points.Get(0).sum()); + EXPECT_EQ(4, data_points.Get(0).bucket_counts_size()); + if (4 == data_points.Get(0).bucket_counts_size()) + { + EXPECT_EQ(200, data_points.Get(0).bucket_counts(0)); + EXPECT_EQ(300, data_points.Get(0).bucket_counts(1)); + EXPECT_EQ(400, data_points.Get(0).bucket_counts(2)); + EXPECT_EQ(500, data_points.Get(0).bucket_counts(3)); + } + EXPECT_EQ(3, data_points.Get(0).explicit_bounds_size()); + if (3 == data_points.Get(0).explicit_bounds_size()) + { + EXPECT_EQ(10.1, data_points.Get(0).explicit_bounds(0)); + EXPECT_EQ(20.2, data_points.Get(0).explicit_bounds(1)); + EXPECT_EQ(30.2, data_points.Get(0).explicit_bounds(2)); + } + + bool has_attributes = false; + for (auto &kv : data_points.Get(0).attributes()) + { + if (kv.key() == "a1") + { + EXPECT_EQ("b1", kv.value().string_value()); + has_attributes = true; + } + } + EXPECT_TRUE(has_attributes); + + EXPECT_EQ(3, data_points.Get(1).count()); + EXPECT_EQ(900l, data_points.Get(1).sum()); + EXPECT_EQ(4, data_points.Get(1).bucket_counts_size()); + if (4 == data_points.Get(1).bucket_counts_size()) + { + EXPECT_EQ(200, data_points.Get(1).bucket_counts(0)); + EXPECT_EQ(300, data_points.Get(1).bucket_counts(1)); + EXPECT_EQ(400, data_points.Get(1).bucket_counts(2)); + EXPECT_EQ(500, data_points.Get(1).bucket_counts(3)); + } + EXPECT_EQ(3, data_points.Get(1).explicit_bounds_size()); + if (3 == data_points.Get(1).explicit_bounds_size()) + { + EXPECT_EQ(10, data_points.Get(1).explicit_bounds(0)); + EXPECT_EQ(20, data_points.Get(1).explicit_bounds(1)); + EXPECT_EQ(30, data_points.Get(1).explicit_bounds(2)); + } + has_attributes = false; + for (auto &kv : data_points.Get(1).attributes()) + { + if (kv.key() == "a2") + { + EXPECT_EQ("b2", kv.value().string_value()); + has_attributes = true; + } + } + EXPECT_TRUE(has_attributes); + + http_client::nosend::Response response; + response.Finish(*callback.get()); + }); + + auto result = exporter->Export(data); + EXPECT_EQ(result, opentelemetry::sdk::common::ExportResult::kSuccess); + + exporter->ForceFlush(); + } }; TEST(OtlpHttpMetricExporterTest, Shutdown) @@ -317,6 +820,41 @@ TEST_F(OtlpHttpMetricExporterTestPeer, ExportBinaryIntegrationTestSumPointDataSy { ExportBinaryIntegrationTestExportSumPointData(false); } + +TEST_F(OtlpHttpMetricExporterTestPeer, ExportJsonIntegrationTestLastValuePointDataAsync) +{ + ExportJsonIntegrationTestExportLastValuePointData(true); +} +TEST_F(OtlpHttpMetricExporterTestPeer, ExportJsonIntegrationTestLastValuePointDataSync) +{ + ExportJsonIntegrationTestExportLastValuePointData(false); +} +TEST_F(OtlpHttpMetricExporterTestPeer, ExportBinaryIntegrationTestLastValuePointDataAsync) +{ + ExportBinaryIntegrationTestExportLastValuePointData(true); +} +TEST_F(OtlpHttpMetricExporterTestPeer, ExportBinaryIntegrationTestLastValuePointDataSync) +{ + ExportBinaryIntegrationTestExportLastValuePointData(false); +} + +TEST_F(OtlpHttpMetricExporterTestPeer, ExportJsonIntegrationTestHistogramPointDataAsync) +{ + ExportJsonIntegrationTestExportHistogramPointData(true); +} +TEST_F(OtlpHttpMetricExporterTestPeer, ExportJsonIntegrationTestHistogramPointDataSync) +{ + ExportJsonIntegrationTestExportHistogramPointData(false); +} +TEST_F(OtlpHttpMetricExporterTestPeer, ExportBinaryIntegrationTestHistogramPointDataAsync) +{ + ExportBinaryIntegrationTestExportHistogramPointData(true); +} +TEST_F(OtlpHttpMetricExporterTestPeer, ExportBinaryIntegrationTestHistogramPointDataSync) +{ + ExportBinaryIntegrationTestExportHistogramPointData(false); +} + # else TEST_F(OtlpHttpMetricExporterTestPeer, ExportJsonIntegrationTestSumPointData) { @@ -326,6 +864,24 @@ TEST_F(OtlpHttpMetricExporterTestPeer, ExportBinaryIntegrationTestSumPointData) { ExportBinaryIntegrationTestExportSumPointData(); } + +TEST_F(OtlpHttpMetricExporterTestPeer, ExportJsonIntegrationTestLastValuePointData) +{ + ExportJsonIntegrationTestExportLastValuePointData(); +} +TEST_F(OtlpHttpMetricExporterTestPeer, ExportBinaryIntegrationTestLastValuePointData) +{ + ExportBinaryIntegrationTestExportLastValuePointData(); +} + +TEST_F(OtlpHttpMetricExporterTestPeer, ExportJsonIntegrationTestHistogramPointData) +{ + ExportJsonIntegrationTestExportHistogramPointData(); +} +TEST_F(OtlpHttpMetricExporterTestPeer, ExportBinaryIntegrationTestHistogramPointData) +{ + ExportBinaryIntegrationTestExportHistogramPointData(); +} # endif // Test exporter configuration options