diff --git a/exporters/ostream/include/opentelemetry/exporters/ostream/metric_exporter.h b/exporters/ostream/include/opentelemetry/exporters/ostream/metric_exporter.h index e34332d77c..4dc3e1e266 100644 --- a/exporters/ostream/include/opentelemetry/exporters/ostream/metric_exporter.h +++ b/exporters/ostream/include/opentelemetry/exporters/ostream/metric_exporter.h @@ -45,11 +45,11 @@ class OStreamMetricExporter final : public opentelemetry::sdk::metrics::MetricEx /** * Shut down the exporter. - * @param timeout an optional timeout, the default timeout of 0 means that no - * timeout is applied. + * @param timeout an optional timeout. * @return return the status of this operation */ - bool Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept override; + bool Shutdown( + std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept override; private: std::ostream &sout_; diff --git a/exporters/ostream/test/ostream_metric_test.cc b/exporters/ostream/test/ostream_metric_test.cc index 45d6d8f882..8620ed1017 100644 --- a/exporters/ostream/test/ostream_metric_test.cc +++ b/exporters/ostream/test/ostream_metric_test.cc @@ -48,7 +48,8 @@ TEST(OStreamMetricsExporter, ExportSumPointData) metric_sdk::InstrumentDescriptor{"library_name", "description", "unit", metric_sdk::InstrumentType::kCounter, metric_sdk::InstrumentValueType::kDouble}, - opentelemetry::common::SystemTimestamp{}, opentelemetry::common::SystemTimestamp{}, + metric_sdk::AggregationTemporality::kDelta, opentelemetry::common::SystemTimestamp{}, + opentelemetry::common::SystemTimestamp{}, std::vector{ {metric_sdk::PointAttributes{{"a1", "b1"}}, sum_point_data}, {metric_sdk::PointAttributes{{"a1", "b1"}}, sum_point_data2}}}; @@ -111,7 +112,8 @@ TEST(OStreamMetricsExporter, ExportHistogramPointData) metric_sdk::InstrumentDescriptor{"library_name", "description", "unit", metric_sdk::InstrumentType::kCounter, metric_sdk::InstrumentValueType::kDouble}, - opentelemetry::common::SystemTimestamp{}, opentelemetry::common::SystemTimestamp{}, + metric_sdk::AggregationTemporality::kDelta, opentelemetry::common::SystemTimestamp{}, + opentelemetry::common::SystemTimestamp{}, std::vector{ {metric_sdk::PointAttributes{{"a1", "b1"}, {"a2", "b2"}}, histogram_point_data}, {metric_sdk::PointAttributes{{"a1", "b1"}}, histogram_point_data2}}}; @@ -179,7 +181,8 @@ TEST(OStreamMetricsExporter, ExportLastValuePointData) metric_sdk::InstrumentDescriptor{"library_name", "description", "unit", metric_sdk::InstrumentType::kCounter, metric_sdk::InstrumentValueType::kDouble}, - opentelemetry::common::SystemTimestamp{}, opentelemetry::common::SystemTimestamp{}, + metric_sdk::AggregationTemporality::kDelta, opentelemetry::common::SystemTimestamp{}, + opentelemetry::common::SystemTimestamp{}, std::vector{ {metric_sdk::PointAttributes{}, last_value_point_data}, {metric_sdk::PointAttributes{}, last_value_point_data2}}}; @@ -236,7 +239,8 @@ TEST(OStreamMetricsExporter, ExportDropPointData) metric_sdk::InstrumentDescriptor{"library_name", "description", "unit", metric_sdk::InstrumentType::kCounter, metric_sdk::InstrumentValueType::kDouble}, - opentelemetry::common::SystemTimestamp{}, opentelemetry::common::SystemTimestamp{}, + metric_sdk::AggregationTemporality::kDelta, opentelemetry::common::SystemTimestamp{}, + opentelemetry::common::SystemTimestamp{}, std::vector{ {metric_sdk::PointAttributes{}, drop_point_data}, {metric_sdk::PointAttributes{}, drop_point_data2}}}; diff --git a/exporters/otlp/BUILD b/exporters/otlp/BUILD index 4968191385..c8d4c5b546 100644 --- a/exporters/otlp/BUILD +++ b/exporters/otlp/BUILD @@ -20,11 +20,13 @@ cc_library( name = "otlp_recordable", srcs = [ "src/otlp_log_recordable.cc", + "src/otlp_populate_attribute_utils.cc", "src/otlp_recordable.cc", "src/otlp_recordable_utils.cc", ], hdrs = [ "include/opentelemetry/exporters/otlp/otlp_log_recordable.h", + "include/opentelemetry/exporters/otlp/otlp_populate_attribute_utils.h", "include/opentelemetry/exporters/otlp/otlp_recordable.h", "include/opentelemetry/exporters/otlp/otlp_recordable_utils.h", "include/opentelemetry/exporters/otlp/protobuf_include_prefix.h", diff --git a/exporters/otlp/CMakeLists.txt b/exporters/otlp/CMakeLists.txt index b5dfa1e1ab..a7ed795107 100755 --- a/exporters/otlp/CMakeLists.txt +++ b/exporters/otlp/CMakeLists.txt @@ -1,7 +1,8 @@ add_library( opentelemetry_otlp_recordable src/otlp_log_recordable.cc src/otlp_recordable.cc - src/otlp_recordable_utils.cc) + src/otlp_populate_attribute_utils.cc src/otlp_recordable_utils.cc + src/otlp_metrics_utils.cc) set_target_properties(opentelemetry_otlp_recordable PROPERTIES EXPORT_NAME otlp_recordable) @@ -37,6 +38,20 @@ if(WITH_OTLP_GRPC) PUBLIC opentelemetry_otlp_recordable gRPC::grpc++) list(APPEND OPENTELEMETRY_OTLP_TARGETS opentelemetry_exporter_otlp_grpc_log) + + if(NOT WITH_METRICS_PREVIEW) + add_library(opentelemetry_exporter_otlp_grpc_metrics + src/otlp_grpc_metric_exporter.cc) + + set_target_properties(opentelemetry_exporter_otlp_grpc_metrics + PROPERTIES EXPORT_NAME otlp_grpc_metrics_exporter) + + target_link_libraries(opentelemetry_exporter_otlp_grpc_metrics + PUBLIC opentelemetry_otlp_recordable gRPC::grpc++) + + list(APPEND OPENTELEMETRY_OTLP_TARGETS + opentelemetry_exporter_otlp_grpc_metrics) + endif() endif() if(WITH_OTLP_HTTP) @@ -122,6 +137,18 @@ if(BUILD_TESTING) TEST_LIST otlp_log_recordable_test) endif() + if(NOT WITH_METRICS_PREVIEW) + add_executable(otlp_metrics_serialization_test + test/otlp_metrics_serialization_test.cc) + target_link_libraries( + otlp_metrics_serialization_test ${GTEST_BOTH_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} opentelemetry_otlp_recordable) + gtest_add_tests( + TARGET otlp_metrics_serialization_test + TEST_PREFIX exporter.otlp. + TEST_LIST otlp_metrics_serialization_test) + endif() + if(MSVC) # Explicitly specify that we consume GTest from shared library. The rest of # code logic below determines whether we link Release or Debug flavor of the diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_environment.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_environment.h index bf7ea6a61c..52bd111937 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_environment.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_environment.h @@ -266,7 +266,6 @@ inline OtlpHeaders GetOtlpDefaultLogHeaders() return result; } - } // namespace otlp } // namespace exporter OPENTELEMETRY_END_NAMESPACE diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_metric_exporter.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_metric_exporter.h new file mode 100644 index 0000000000..f6df1c3454 --- /dev/null +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_metric_exporter.h @@ -0,0 +1,76 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once +#ifndef ENABLE_METRICS_PREVIEW + +// clang-format off + +# include "opentelemetry/exporters/otlp/protobuf_include_prefix.h" +# include "opentelemetry/proto/collector/metrics/v1/metrics_service.grpc.pb.h" +# include "opentelemetry/common/spin_lock_mutex.h" +# include "opentelemetry/exporters/otlp/protobuf_include_suffix.h" + +// clang-format on + +# include "opentelemetry/exporters/otlp/otlp_environment.h" +# include "opentelemetry/exporters/otlp/otlp_grpc_metric_exporter_options.h" +# include "opentelemetry/sdk/metrics/metric_exporter.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace otlp +{ + +/** + * The OTLP exporter exports metrics data in OpenTelemetry Protocol (OTLP) format in gRPC. + */ +class OtlpGrpcMetricsExporter : public opentelemetry::sdk::metrics::MetricExporter +{ +public: + /** + * Create an OtlpGrpcMetricsExporter using all default options. + */ + OtlpGrpcMetricsExporter(); + + /** + * Create an OtlpGrpcMetricsExporter using the given options. + */ + explicit OtlpGrpcMetricsExporter(const OtlpGrpcMetricsExporterOptions &options); + + opentelemetry::sdk::common::ExportResult Export( + const opentelemetry::sdk::metrics::ResourceMetrics &data) noexcept override; + + bool ForceFlush( + std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept override; + + bool Shutdown( + std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept override; + +private: + // The configuration options associated with this exporter. + const OtlpGrpcMetricsExporterOptions options_; + + // For testing + friend class OtlpGrpcExporterTestPeer; + + // Store service stub internally. Useful for testing. + std::unique_ptr + metrics_service_stub_; + + /** + * Create an OtlpGrpcMetricsExporter using the specified service stub. + * Only tests can call this constructor directly. + * @param stub the service stub to be used for exporting + */ + OtlpGrpcMetricsExporter( + std::unique_ptr stub); + bool is_shutdown_ = false; + mutable opentelemetry::common::SpinLockMutex lock_; + bool isShutdown() const noexcept; +}; +} // namespace otlp +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE +#endif \ No newline at end of file diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_metric_exporter_options.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_metric_exporter_options.h new file mode 100644 index 0000000000..fab2ccc8a9 --- /dev/null +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_metric_exporter_options.h @@ -0,0 +1,28 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "opentelemetry/exporters/otlp/otlp_grpc_exporter_options.h" +#include "opentelemetry/sdk/metrics/instruments.h" + +#include + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace otlp +{ + +/** + * Struct to hold OTLP metrics exporter options. + */ +struct OtlpGrpcMetricsExporterOptions : public OtlpGrpcExporterOptions +{ + opentelemetry::sdk::metrics::AggregationTemporality aggregation_temporality = + opentelemetry::sdk::metrics::AggregationTemporality::kDelta; +}; + +} // namespace otlp +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE \ No newline at end of file diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_metrics_utils.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_metrics_utils.h new file mode 100644 index 0000000000..d1c9f3f1b5 --- /dev/null +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_metrics_utils.h @@ -0,0 +1,58 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "opentelemetry/exporters/otlp/protobuf_include_prefix.h" + +#include "opentelemetry/proto/collector/metrics/v1/metrics_service.pb.h" +#include "opentelemetry/proto/metrics/v1/metrics.pb.h" +#include "opentelemetry/proto/resource/v1/resource.pb.h" + +#include "opentelemetry/exporters/otlp/protobuf_include_suffix.h" + +#include "opentelemetry/sdk/metrics/export/metric_producer.h" + +#ifndef ENABLE_METRICS_PREVIEW + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace otlp +{ +/** + * The OtlpMetricsUtils contains utility functions for OTLP metrics + */ +class OtlpMetricsUtils +{ +public: + static opentelemetry::sdk::metrics::AggregationType GetAggregationType( + const opentelemetry::sdk::metrics::InstrumentType &instrument_type) noexcept; + + static proto::metrics::v1::AggregationTemporality GetProtoAggregationTemporality( + const opentelemetry::sdk::metrics::AggregationTemporality &aggregation_temporality) noexcept; + + static void ConvertSumMetric(const opentelemetry::sdk::metrics::MetricData &metric_data, + proto::metrics::v1::Sum *const sum) noexcept; + + static void ConvertHistogramMetric(const opentelemetry::sdk::metrics::MetricData &metric_data, + proto::metrics::v1::Histogram *const histogram) noexcept; + + static void PopulateInstrumentationInfoMetric( + const opentelemetry::sdk::metrics::MetricData &metric_data, + proto::metrics::v1::Metric *metric) noexcept; + + static void PopulateResourceMetrics( + const opentelemetry::sdk::metrics::ResourceMetrics &data, + proto::metrics::v1::ResourceMetrics *proto_resource_metrics) noexcept; + + static void PopulateRequest( + const opentelemetry::sdk::metrics::ResourceMetrics &data, + proto::collector::metrics::v1::ExportMetricsServiceRequest *request) noexcept; +}; + +} // namespace otlp +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE + +#endif diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_populate_attribute_utils.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_populate_attribute_utils.h new file mode 100644 index 0000000000..c64ca90b43 --- /dev/null +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_populate_attribute_utils.h @@ -0,0 +1,42 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "opentelemetry/exporters/otlp/protobuf_include_prefix.h" +#include "opentelemetry/proto/resource/v1/resource.pb.h" + +#include "opentelemetry/common/attribute_value.h" +#include "opentelemetry/nostd/string_view.h" +#include "opentelemetry/sdk/common/attribute_utils.h" +#include "opentelemetry/sdk/resource/resource.h" +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace otlp +{ +/** + * The OtlpCommoneUtils contains utility functions to populate attributes + */ +class OtlpPopulateAttributeUtils +{ + +public: + static void PopulateAttribute(opentelemetry::proto::resource::v1::Resource *proto, + const opentelemetry::sdk::resource::Resource &resource) noexcept; + + static void PopulateAttribute(opentelemetry::proto::common::v1::KeyValue *attribute, + nostd::string_view key, + const opentelemetry::common::AttributeValue &value) noexcept; + + static void PopulateAttribute( + opentelemetry::proto::common::v1::KeyValue *attribute, + nostd::string_view key, + const opentelemetry::sdk::common::OwnedAttributeValue &value) noexcept; +}; + +} // namespace otlp +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_recordable_utils.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_recordable_utils.h index 0c09bc8717..57dbd3b8b0 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_recordable_utils.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_recordable_utils.h @@ -7,16 +7,9 @@ #include "opentelemetry/proto/collector/logs/v1/logs_service.pb.h" #include "opentelemetry/proto/collector/trace/v1/trace_service.pb.h" -#include "opentelemetry/proto/resource/v1/resource.pb.h" #include "opentelemetry/exporters/otlp/protobuf_include_suffix.h" -#include "opentelemetry/common/attribute_value.h" -#include "opentelemetry/nostd/string_view.h" -#include "opentelemetry/version.h" - -#include "opentelemetry/sdk/common/attribute_utils.h" -#include "opentelemetry/sdk/resource/resource.h" #include "opentelemetry/sdk/trace/recordable.h" #ifdef ENABLE_LOGS_PREVIEW @@ -36,18 +29,6 @@ namespace otlp class OtlpRecordableUtils { public: - static void PopulateAttribute(opentelemetry::proto::common::v1::KeyValue *attribute, - nostd::string_view key, - const opentelemetry::common::AttributeValue &value) noexcept; - - static void PopulateAttribute( - opentelemetry::proto::common::v1::KeyValue *attribute, - nostd::string_view key, - const opentelemetry::sdk::common::OwnedAttributeValue &value) noexcept; - - static void PopulateAttribute(opentelemetry::proto::resource::v1::Resource *proto, - const opentelemetry::sdk::resource::Resource &resource) noexcept; - static void PopulateRequest( const nostd::span> &spans, proto::collector::trace::v1::ExportTraceServiceRequest *request) noexcept; diff --git a/exporters/otlp/src/otlp_grpc_metric_exporter.cc b/exporters/otlp/src/otlp_grpc_metric_exporter.cc new file mode 100644 index 0000000000..187498e01d --- /dev/null +++ b/exporters/otlp/src/otlp_grpc_metric_exporter.cc @@ -0,0 +1,149 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifndef ENABLE_METRICS_PREVIEW + +# include "opentelemetry/exporters/otlp/otlp_grpc_metric_exporter.h" +# include "opentelemetry/exporters/otlp/otlp_metrics_utils.h" + +# include +# include "opentelemetry/ext/http/common/url_parser.h" +# include "opentelemetry/sdk_config.h" + +# include +# include +# include // std::stringstream + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace otlp +{ + +// ----------------------------- Helper functions ------------------------------ +static std::string get_file_contents(const char *fpath) +{ + std::ifstream finstream(fpath); + std::string contents; + contents.assign((std::istreambuf_iterator(finstream)), std::istreambuf_iterator()); + finstream.close(); + return contents; +} + +/** + * Create gRPC channel from the exporter options. + */ +static std::shared_ptr MakeGrpcChannel(const OtlpGrpcMetricsExporterOptions &options) +{ + std::shared_ptr channel; + + // + // Scheme is allowed in OTLP endpoint definition, but is not allowed for creating gRPC channel. + // Passing URI with scheme to grpc::CreateChannel could resolve the endpoint to some unexpected + // address. + // + + ext::http::common::UrlParser url(options.endpoint); + if (!url.success_) + { + OTEL_INTERNAL_LOG_ERROR("[OTLP Exporter] invalid endpoint: " << options.endpoint); + + return nullptr; + } + + std::string grpc_target = url.host_ + ":" + std::to_string(static_cast(url.port_)); + + if (options.use_ssl_credentials) + { + grpc::SslCredentialsOptions ssl_opts; + if (options.ssl_credentials_cacert_path.empty()) + { + ssl_opts.pem_root_certs = options.ssl_credentials_cacert_as_string; + } + else + { + ssl_opts.pem_root_certs = get_file_contents((options.ssl_credentials_cacert_path).c_str()); + } + channel = grpc::CreateChannel(grpc_target, grpc::SslCredentials(ssl_opts)); + } + else + { + channel = grpc::CreateChannel(grpc_target, grpc::InsecureChannelCredentials()); + } + + return channel; +} + +/** + * Create metrics service stub to communicate with the OpenTelemetry Collector. + */ +std::unique_ptr<::opentelemetry::proto::collector::metrics::v1::MetricsService::Stub> +MakeMetricsServiceStub(const OtlpGrpcMetricsExporterOptions &options) +{ + return proto::collector::metrics::v1::MetricsService::NewStub(MakeGrpcChannel(options)); +} + +// -------------------------------- Constructors -------------------------------- + +OtlpGrpcMetricsExporter::OtlpGrpcMetricsExporter() + : OtlpGrpcMetricsExporter(OtlpGrpcMetricsExporterOptions()) +{} + +OtlpGrpcMetricsExporter::OtlpGrpcMetricsExporter(const OtlpGrpcMetricsExporterOptions &options) + : options_(options), metrics_service_stub_(MakeMetricsServiceStub(options)) +{} + +OtlpGrpcMetricsExporter::OtlpGrpcMetricsExporter( + std::unique_ptr stub) + : options_(OtlpGrpcMetricsExporterOptions()), metrics_service_stub_(std::move(stub)) +{} + +// ----------------------------- Exporter methods ------------------------------ + +opentelemetry::sdk::common::ExportResult OtlpGrpcMetricsExporter::Export( + const opentelemetry::sdk::metrics::ResourceMetrics &data) noexcept +{ + + if (isShutdown()) + { + OTEL_INTERNAL_LOG_ERROR("[OTLP METRICS gRPC] Exporting " + << data.instrumentation_info_metric_data_.size() + << " metric(s) failed, exporter is shutdown"); + return sdk::common::ExportResult::kFailure; + } + if (data.instrumentation_info_metric_data_.empty()) + { + return sdk::common::ExportResult::kSuccess; + } + + proto::collector::metrics::v1::ExportMetricsServiceRequest request; + OtlpMetricsUtils::PopulateRequest(data, &request); + + grpc::ClientContext context; + proto::collector::metrics::v1::ExportMetricsServiceResponse response; + + if (options_.timeout.count() > 0) + { + context.set_deadline(std::chrono::system_clock::now() + options_.timeout); + } + + for (auto &header : options_.metadata) + { + context.AddMetadata(header.first, header.second); + } + + grpc::Status status = metrics_service_stub_->Export(&context, request, &response); + + if (!status.ok()) + { + OTEL_INTERNAL_LOG_ERROR( + "[OTLP METRIC GRPC Exporter] Export() failed: " << status.error_message()); + return sdk::common::ExportResult::kFailure; + } + return opentelemetry::sdk::common::ExportResult::kSuccess; +} + +} // namespace otlp +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE +#endif \ No newline at end of file diff --git a/exporters/otlp/src/otlp_log_recordable.cc b/exporters/otlp/src/otlp_log_recordable.cc index d38fe241fa..db9f73d46c 100644 --- a/exporters/otlp/src/otlp_log_recordable.cc +++ b/exporters/otlp/src/otlp_log_recordable.cc @@ -7,6 +7,7 @@ # include "opentelemetry/exporters/otlp/otlp_log_recordable.h" +# include "opentelemetry/exporters/otlp/otlp_populate_attribute_utils.h" # include "opentelemetry/exporters/otlp/otlp_recordable_utils.h" namespace nostd = opentelemetry::nostd; @@ -22,11 +23,11 @@ proto::resource::v1::Resource OtlpLogRecordable::ProtoResource() const noexcept proto::resource::v1::Resource proto; if (nullptr == resource_) { - OtlpRecordableUtils::PopulateAttribute(&proto, sdk::resource::Resource::GetDefault()); + OtlpPopulateAttributeUtils::PopulateAttribute(&proto, sdk::resource::Resource::GetDefault()); } else { - OtlpRecordableUtils::PopulateAttribute(&proto, *resource_); + OtlpPopulateAttributeUtils::PopulateAttribute(&proto, *resource_); } return proto; @@ -189,7 +190,7 @@ const opentelemetry::sdk::resource::Resource &OtlpLogRecordable::GetResource() c void OtlpLogRecordable::SetAttribute(nostd::string_view key, const opentelemetry::common::AttributeValue &value) noexcept { - OtlpRecordableUtils::PopulateAttribute(log_record_.add_attributes(), key, value); + OtlpPopulateAttributeUtils::PopulateAttribute(log_record_.add_attributes(), key, value); } void OtlpLogRecordable::SetTraceId(opentelemetry::trace::TraceId trace_id) noexcept diff --git a/exporters/otlp/src/otlp_metrics_utils.cc b/exporters/otlp/src/otlp_metrics_utils.cc new file mode 100644 index 0000000000..914cfae621 --- /dev/null +++ b/exporters/otlp/src/otlp_metrics_utils.cc @@ -0,0 +1,209 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/exporters/otlp/otlp_metrics_utils.h" +#include "opentelemetry/exporters/otlp/otlp_populate_attribute_utils.h" + +#ifndef ENABLE_METRICS_PREVIEW + +OPENTELEMETRY_BEGIN_NAMESPACE + +namespace exporter +{ +namespace otlp +{ +namespace metric_sdk = opentelemetry::sdk::metrics; + +proto::metrics::v1::AggregationTemporality OtlpMetricsUtils::GetProtoAggregationTemporality( + const opentelemetry::sdk::metrics::AggregationTemporality &aggregation_temporality) noexcept +{ + if (aggregation_temporality == opentelemetry::sdk::metrics::AggregationTemporality::kCumulative) + return proto::metrics::v1::AggregationTemporality::AGGREGATION_TEMPORALITY_CUMULATIVE; + else if (aggregation_temporality == opentelemetry::sdk::metrics::AggregationTemporality::kDelta) + return proto::metrics::v1::AggregationTemporality::AGGREGATION_TEMPORALITY_DELTA; + else + return proto::metrics::v1::AggregationTemporality::AGGREGATION_TEMPORALITY_UNSPECIFIED; +} + +metric_sdk::AggregationType OtlpMetricsUtils::GetAggregationType( + const opentelemetry::sdk::metrics::InstrumentType &instrument_type) noexcept +{ + + if (instrument_type == metric_sdk::InstrumentType::kCounter || + instrument_type == metric_sdk::InstrumentType::kUpDownCounter || + instrument_type == metric_sdk::InstrumentType::kObservableCounter || + instrument_type == metric_sdk::InstrumentType::kObservableUpDownCounter) + { + return metric_sdk::AggregationType::kSum; + } + else if (instrument_type == metric_sdk::InstrumentType::kHistogram) + { + return metric_sdk::AggregationType::kHistogram; + } + else if (instrument_type == metric_sdk::InstrumentType::kObservableGauge) + { + return metric_sdk::AggregationType::kLastValue; + } + return metric_sdk::AggregationType::kDrop; +} + +void OtlpMetricsUtils::ConvertSumMetric(const metric_sdk::MetricData &metric_data, + proto::metrics::v1::Sum *const sum) noexcept +{ + sum->set_aggregation_temporality( + GetProtoAggregationTemporality(metric_data.aggregation_temporality)); + sum->set_is_monotonic(true); + auto start_ts = metric_data.start_ts.time_since_epoch().count(); + 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; + 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); + + if ((nostd::holds_alternative(sum_data.value_))) + { + proto_sum_point_data.set_as_int(nostd::get(sum_data.value_)); + } + else + { + proto_sum_point_data.set_as_double(nostd::get(sum_data.value_)); + } + // set attributes + for (auto &kv_attr : point_data_with_attributes.attributes) + { + OtlpPopulateAttributeUtils::PopulateAttribute(proto_sum_point_data.add_attributes(), + kv_attr.first, kv_attr.second); + } + *sum->add_data_points() = proto_sum_point_data; + } +} + +void OtlpMetricsUtils::ConvertHistogramMetric( + const metric_sdk::MetricData &metric_data, + proto::metrics::v1::Histogram *const histogram) noexcept +{ + histogram->set_aggregation_temporality( + GetProtoAggregationTemporality(metric_data.aggregation_temporality)); + auto start_ts = metric_data.start_ts.time_since_epoch().count(); + auto ts = metric_data.end_ts.time_since_epoch().count(); + for (auto &point_data_with_attributes : metric_data.point_data_attr_) + { + proto::metrics::v1::HistogramDataPoint proto_histogram_point_data; + proto_histogram_point_data.set_start_time_unix_nano(start_ts); + proto_histogram_point_data.set_time_unix_nano(ts); + auto histogram_data = + nostd::get(point_data_with_attributes.point_data); + // sum + if ((nostd::holds_alternative(histogram_data.sum_))) + { + proto_histogram_point_data.set_sum(nostd::get(histogram_data.sum_)); + } + else + { + proto_histogram_point_data.set_sum(nostd::get(histogram_data.sum_)); + } + // count + proto_histogram_point_data.set_count(histogram_data.count_); + // buckets + if ((nostd::holds_alternative>(histogram_data.boundaries_))) + { + auto boundaries = nostd::get>(histogram_data.boundaries_); + for (auto bound : boundaries) + { + proto_histogram_point_data.add_explicit_bounds(bound); + } + } + else + { + auto boundaries = nostd::get>(histogram_data.boundaries_); + for (auto bound : boundaries) + { + proto_histogram_point_data.add_explicit_bounds(bound); + } + } + // bucket counts + for (auto bucket_value : histogram_data.counts_) + { + proto_histogram_point_data.add_bucket_counts(bucket_value); + } + // attributes + for (auto &kv_attr : point_data_with_attributes.attributes) + { + OtlpPopulateAttributeUtils::PopulateAttribute(proto_histogram_point_data.add_attributes(), + kv_attr.first, kv_attr.second); + } + *histogram->add_data_points() = proto_histogram_point_data; + } +} + +void OtlpMetricsUtils::PopulateInstrumentationInfoMetric( + const opentelemetry::sdk::metrics::MetricData &metric_data, + proto::metrics::v1::Metric *metric) noexcept +{ + metric->set_name(metric_data.instrument_descriptor.name_); + metric->set_description(metric_data.instrument_descriptor.description_); + metric->set_unit(metric_data.instrument_descriptor.unit_); + auto kind = GetAggregationType(metric_data.instrument_descriptor.type_); + if (kind == metric_sdk::AggregationType::kSum) + { + proto::metrics::v1::Sum sum; + ConvertSumMetric(metric_data, &sum); + *metric->mutable_sum() = sum; + } + else if (kind == metric_sdk::AggregationType::kHistogram) + { + proto::metrics::v1::Histogram histogram; + ConvertHistogramMetric(metric_data, &histogram); + *metric->mutable_histogram() = histogram; + } +} + +void OtlpMetricsUtils::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; + + for (auto &instrumentation_metrics : data.instrumentation_info_metric_data_) + { + if (instrumentation_metrics.instrumentation_library_ == nullptr) + { + 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( + 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; + } + } +} + +void OtlpMetricsUtils::PopulateRequest( + const opentelemetry::sdk::metrics::ResourceMetrics &data, + proto::collector::metrics::v1::ExportMetricsServiceRequest *request) noexcept +{ + if (request == nullptr || data.resource_ == nullptr) + { + return; + } + + auto resource_metrics = request->add_resource_metrics(); + PopulateResourceMetrics(data, resource_metrics); +} +} // namespace otlp +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE + +#endif diff --git a/exporters/otlp/src/otlp_populate_attribute_utils.cc b/exporters/otlp/src/otlp_populate_attribute_utils.cc new file mode 100644 index 0000000000..e19b6210b4 --- /dev/null +++ b/exporters/otlp/src/otlp_populate_attribute_utils.cc @@ -0,0 +1,245 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/exporters/otlp/otlp_populate_attribute_utils.h" + +namespace nostd = opentelemetry::nostd; + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace otlp +{ + +// +// See `attribute_value.h` for details. +// +const int kAttributeValueSize = 16; +const int kOwnedAttributeValueSize = 15; + +void OtlpPopulateAttributeUtils::PopulateAttribute( + opentelemetry::proto::common::v1::KeyValue *attribute, + nostd::string_view key, + const opentelemetry::common::AttributeValue &value) noexcept +{ + if (nullptr == attribute) + { + return; + } + + // Assert size of variant to ensure that this method gets updated if the variant + // definition changes + static_assert( + nostd::variant_size::value == kAttributeValueSize, + "AttributeValue contains unknown type"); + + attribute->set_key(key.data(), key.size()); + + if (nostd::holds_alternative(value)) + { + attribute->mutable_value()->set_bool_value(nostd::get(value)); + } + else if (nostd::holds_alternative(value)) + { + attribute->mutable_value()->set_int_value(nostd::get(value)); + } + else if (nostd::holds_alternative(value)) + { + attribute->mutable_value()->set_int_value(nostd::get(value)); + } + else if (nostd::holds_alternative(value)) + { + attribute->mutable_value()->set_int_value(nostd::get(value)); + } + else if (nostd::holds_alternative(value)) + { + attribute->mutable_value()->set_int_value(nostd::get(value)); + } + else if (nostd::holds_alternative(value)) + { + attribute->mutable_value()->set_double_value(nostd::get(value)); + } + else if (nostd::holds_alternative(value)) + { + attribute->mutable_value()->set_string_value(nostd::get(value)); + } + else if (nostd::holds_alternative(value)) + { + attribute->mutable_value()->set_string_value(nostd::get(value).data(), + nostd::get(value).size()); + } + else if (nostd::holds_alternative>(value)) + { + for (const auto &val : nostd::get>(value)) + { + attribute->mutable_value()->mutable_array_value()->add_values()->set_int_value(val); + } + } + else if (nostd::holds_alternative>(value)) + { + for (const auto &val : nostd::get>(value)) + { + attribute->mutable_value()->mutable_array_value()->add_values()->set_bool_value(val); + } + } + else if (nostd::holds_alternative>(value)) + { + for (const auto &val : nostd::get>(value)) + { + attribute->mutable_value()->mutable_array_value()->add_values()->set_int_value(val); + } + } + else if (nostd::holds_alternative>(value)) + { + for (const auto &val : nostd::get>(value)) + { + attribute->mutable_value()->mutable_array_value()->add_values()->set_int_value(val); + } + } + else if (nostd::holds_alternative>(value)) + { + for (const auto &val : nostd::get>(value)) + { + attribute->mutable_value()->mutable_array_value()->add_values()->set_int_value(val); + } + } + else if (nostd::holds_alternative>(value)) + { + for (const auto &val : nostd::get>(value)) + { + attribute->mutable_value()->mutable_array_value()->add_values()->set_int_value(val); + } + } + else if (nostd::holds_alternative>(value)) + { + for (const auto &val : nostd::get>(value)) + { + attribute->mutable_value()->mutable_array_value()->add_values()->set_double_value(val); + } + } + else if (nostd::holds_alternative>(value)) + { + for (const auto &val : nostd::get>(value)) + { + attribute->mutable_value()->mutable_array_value()->add_values()->set_string_value(val.data(), + val.size()); + } + } +} + +/** Maps from C++ attribute into OTLP proto attribute. */ +void OtlpPopulateAttributeUtils::PopulateAttribute( + opentelemetry::proto::common::v1::KeyValue *attribute, + nostd::string_view key, + const opentelemetry::sdk::common::OwnedAttributeValue &value) noexcept +{ + if (nullptr == attribute) + { + return; + } + + // Assert size of variant to ensure that this method gets updated if the variant + // definition changes + static_assert(nostd::variant_size::value == + kOwnedAttributeValueSize, + "OwnedAttributeValue contains unknown type"); + + attribute->set_key(key.data(), key.size()); + + if (nostd::holds_alternative(value)) + { + attribute->mutable_value()->set_bool_value(nostd::get(value)); + } + else if (nostd::holds_alternative(value)) + { + attribute->mutable_value()->set_int_value(nostd::get(value)); + } + else if (nostd::holds_alternative(value)) + { + attribute->mutable_value()->set_int_value(nostd::get(value)); + } + else if (nostd::holds_alternative(value)) + { + attribute->mutable_value()->set_int_value(nostd::get(value)); + } + else if (nostd::holds_alternative(value)) + { + attribute->mutable_value()->set_int_value(nostd::get(value)); + } + else if (nostd::holds_alternative(value)) + { + attribute->mutable_value()->set_double_value(nostd::get(value)); + } + else if (nostd::holds_alternative(value)) + { + attribute->mutable_value()->set_string_value(nostd::get(value)); + } + else if (nostd::holds_alternative>(value)) + { + for (const auto &val : nostd::get>(value)) + { + attribute->mutable_value()->mutable_array_value()->add_values()->set_bool_value(val); + } + } + else if (nostd::holds_alternative>(value)) + { + for (const auto &val : nostd::get>(value)) + { + attribute->mutable_value()->mutable_array_value()->add_values()->set_int_value(val); + } + } + else if (nostd::holds_alternative>(value)) + { + for (const auto &val : nostd::get>(value)) + { + attribute->mutable_value()->mutable_array_value()->add_values()->set_int_value(val); + } + } + else if (nostd::holds_alternative>(value)) + { + for (const auto &val : nostd::get>(value)) + { + attribute->mutable_value()->mutable_array_value()->add_values()->set_int_value(val); + } + } + else if (nostd::holds_alternative>(value)) + { + for (const auto &val : nostd::get>(value)) + { + attribute->mutable_value()->mutable_array_value()->add_values()->set_int_value(val); + } + } + else if (nostd::holds_alternative>(value)) + { + for (const auto &val : nostd::get>(value)) + { + attribute->mutable_value()->mutable_array_value()->add_values()->set_double_value(val); + } + } + else if (nostd::holds_alternative>(value)) + { + for (const auto &val : nostd::get>(value)) + { + attribute->mutable_value()->mutable_array_value()->add_values()->set_string_value(val); + } + } +} + +void OtlpPopulateAttributeUtils::PopulateAttribute( + opentelemetry::proto::resource::v1::Resource *proto, + const opentelemetry::sdk::resource::Resource &resource) noexcept +{ + if (nullptr == proto) + { + return; + } + + for (const auto &kv : resource.GetAttributes()) + { + OtlpPopulateAttributeUtils::PopulateAttribute(proto->add_attributes(), kv.first, kv.second); + } +} + +} // namespace otlp +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE \ No newline at end of file diff --git a/exporters/otlp/src/otlp_recordable.cc b/exporters/otlp/src/otlp_recordable.cc index 0e6aa8f8a1..93281c3865 100644 --- a/exporters/otlp/src/otlp_recordable.cc +++ b/exporters/otlp/src/otlp_recordable.cc @@ -3,6 +3,7 @@ #include "opentelemetry/exporters/otlp/otlp_recordable.h" +#include "opentelemetry/exporters/otlp/otlp_populate_attribute_utils.h" #include "opentelemetry/exporters/otlp/otlp_recordable_utils.h" namespace nostd = opentelemetry::nostd; @@ -33,7 +34,7 @@ proto::resource::v1::Resource OtlpRecordable::ProtoResource() const noexcept proto::resource::v1::Resource proto; if (resource_) { - OtlpRecordableUtils::PopulateAttribute(&proto, *resource_); + OtlpPopulateAttributeUtils::PopulateAttribute(&proto, *resource_); } return proto; @@ -82,7 +83,7 @@ void OtlpRecordable::SetAttribute(nostd::string_view key, const common::AttributeValue &value) noexcept { auto *attribute = span_.add_attributes(); - OtlpRecordableUtils::PopulateAttribute(attribute, key, value); + OtlpPopulateAttributeUtils::PopulateAttribute(attribute, key, value); } void OtlpRecordable::AddEvent(nostd::string_view name, @@ -94,7 +95,7 @@ void OtlpRecordable::AddEvent(nostd::string_view name, event->set_time_unix_nano(timestamp.time_since_epoch().count()); attributes.ForEachKeyValue([&](nostd::string_view key, common::AttributeValue value) noexcept { - OtlpRecordableUtils::PopulateAttribute(event->add_attributes(), key, value); + OtlpPopulateAttributeUtils::PopulateAttribute(event->add_attributes(), key, value); return true; }); } @@ -109,7 +110,7 @@ void OtlpRecordable::AddLink(const trace::SpanContext &span_context, trace::SpanId::kSize); link->set_trace_state(span_context.trace_state()->ToHeader()); attributes.ForEachKeyValue([&](nostd::string_view key, common::AttributeValue value) noexcept { - OtlpRecordableUtils::PopulateAttribute(link->add_attributes(), key, value); + OtlpPopulateAttributeUtils::PopulateAttribute(link->add_attributes(), key, value); return true; }); } diff --git a/exporters/otlp/src/otlp_recordable_utils.cc b/exporters/otlp/src/otlp_recordable_utils.cc index bb3c846042..427037034b 100644 --- a/exporters/otlp/src/otlp_recordable_utils.cc +++ b/exporters/otlp/src/otlp_recordable_utils.cc @@ -47,235 +47,6 @@ struct InstrumentationLibraryPointerEqual }; } // namespace -// -// See `attribute_value.h` for details. -// -const int kAttributeValueSize = 16; -const int kOwnedAttributeValueSize = 15; - -void OtlpRecordableUtils::PopulateAttribute( - opentelemetry::proto::common::v1::KeyValue *attribute, - nostd::string_view key, - const opentelemetry::common::AttributeValue &value) noexcept -{ - if (nullptr == attribute) - { - return; - } - - // Assert size of variant to ensure that this method gets updated if the variant - // definition changes - static_assert( - nostd::variant_size::value == kAttributeValueSize, - "AttributeValue contains unknown type"); - - attribute->set_key(key.data(), key.size()); - - if (nostd::holds_alternative(value)) - { - attribute->mutable_value()->set_bool_value(nostd::get(value)); - } - else if (nostd::holds_alternative(value)) - { - attribute->mutable_value()->set_int_value(nostd::get(value)); - } - else if (nostd::holds_alternative(value)) - { - attribute->mutable_value()->set_int_value(nostd::get(value)); - } - else if (nostd::holds_alternative(value)) - { - attribute->mutable_value()->set_int_value(nostd::get(value)); - } - else if (nostd::holds_alternative(value)) - { - attribute->mutable_value()->set_int_value(nostd::get(value)); - } - else if (nostd::holds_alternative(value)) - { - attribute->mutable_value()->set_double_value(nostd::get(value)); - } - else if (nostd::holds_alternative(value)) - { - attribute->mutable_value()->set_string_value(nostd::get(value)); - } - else if (nostd::holds_alternative(value)) - { - attribute->mutable_value()->set_string_value(nostd::get(value).data(), - nostd::get(value).size()); - } - else if (nostd::holds_alternative>(value)) - { - for (const auto &val : nostd::get>(value)) - { - attribute->mutable_value()->mutable_array_value()->add_values()->set_int_value(val); - } - } - else if (nostd::holds_alternative>(value)) - { - for (const auto &val : nostd::get>(value)) - { - attribute->mutable_value()->mutable_array_value()->add_values()->set_bool_value(val); - } - } - else if (nostd::holds_alternative>(value)) - { - for (const auto &val : nostd::get>(value)) - { - attribute->mutable_value()->mutable_array_value()->add_values()->set_int_value(val); - } - } - else if (nostd::holds_alternative>(value)) - { - for (const auto &val : nostd::get>(value)) - { - attribute->mutable_value()->mutable_array_value()->add_values()->set_int_value(val); - } - } - else if (nostd::holds_alternative>(value)) - { - for (const auto &val : nostd::get>(value)) - { - attribute->mutable_value()->mutable_array_value()->add_values()->set_int_value(val); - } - } - else if (nostd::holds_alternative>(value)) - { - for (const auto &val : nostd::get>(value)) - { - attribute->mutable_value()->mutable_array_value()->add_values()->set_int_value(val); - } - } - else if (nostd::holds_alternative>(value)) - { - for (const auto &val : nostd::get>(value)) - { - attribute->mutable_value()->mutable_array_value()->add_values()->set_double_value(val); - } - } - else if (nostd::holds_alternative>(value)) - { - for (const auto &val : nostd::get>(value)) - { - attribute->mutable_value()->mutable_array_value()->add_values()->set_string_value(val.data(), - val.size()); - } - } -} - -/** Maps from C++ attribute into OTLP proto attribute. */ -void OtlpRecordableUtils::PopulateAttribute( - opentelemetry::proto::common::v1::KeyValue *attribute, - nostd::string_view key, - const opentelemetry::sdk::common::OwnedAttributeValue &value) noexcept -{ - if (nullptr == attribute) - { - return; - } - - // Assert size of variant to ensure that this method gets updated if the variant - // definition changes - static_assert(nostd::variant_size::value == - kOwnedAttributeValueSize, - "OwnedAttributeValue contains unknown type"); - - attribute->set_key(key.data(), key.size()); - - if (nostd::holds_alternative(value)) - { - attribute->mutable_value()->set_bool_value(nostd::get(value)); - } - else if (nostd::holds_alternative(value)) - { - attribute->mutable_value()->set_int_value(nostd::get(value)); - } - else if (nostd::holds_alternative(value)) - { - attribute->mutable_value()->set_int_value(nostd::get(value)); - } - else if (nostd::holds_alternative(value)) - { - attribute->mutable_value()->set_int_value(nostd::get(value)); - } - else if (nostd::holds_alternative(value)) - { - attribute->mutable_value()->set_int_value(nostd::get(value)); - } - else if (nostd::holds_alternative(value)) - { - attribute->mutable_value()->set_double_value(nostd::get(value)); - } - else if (nostd::holds_alternative(value)) - { - attribute->mutable_value()->set_string_value(nostd::get(value)); - } - else if (nostd::holds_alternative>(value)) - { - for (const auto &val : nostd::get>(value)) - { - attribute->mutable_value()->mutable_array_value()->add_values()->set_bool_value(val); - } - } - else if (nostd::holds_alternative>(value)) - { - for (const auto &val : nostd::get>(value)) - { - attribute->mutable_value()->mutable_array_value()->add_values()->set_int_value(val); - } - } - else if (nostd::holds_alternative>(value)) - { - for (const auto &val : nostd::get>(value)) - { - attribute->mutable_value()->mutable_array_value()->add_values()->set_int_value(val); - } - } - else if (nostd::holds_alternative>(value)) - { - for (const auto &val : nostd::get>(value)) - { - attribute->mutable_value()->mutable_array_value()->add_values()->set_int_value(val); - } - } - else if (nostd::holds_alternative>(value)) - { - for (const auto &val : nostd::get>(value)) - { - attribute->mutable_value()->mutable_array_value()->add_values()->set_int_value(val); - } - } - else if (nostd::holds_alternative>(value)) - { - for (const auto &val : nostd::get>(value)) - { - attribute->mutable_value()->mutable_array_value()->add_values()->set_double_value(val); - } - } - else if (nostd::holds_alternative>(value)) - { - for (const auto &val : nostd::get>(value)) - { - attribute->mutable_value()->mutable_array_value()->add_values()->set_string_value(val); - } - } -} - -void OtlpRecordableUtils::PopulateAttribute( - opentelemetry::proto::resource::v1::Resource *proto, - const opentelemetry::sdk::resource::Resource &resource) noexcept -{ - if (nullptr == proto) - { - return; - } - - for (const auto &kv : resource.GetAttributes()) - { - OtlpRecordableUtils::PopulateAttribute(proto->add_attributes(), kv.first, kv.second); - } -} - void OtlpRecordableUtils::PopulateRequest( const nostd::span> &spans, proto::collector::trace::v1::ExportTraceServiceRequest *request) noexcept @@ -356,7 +127,6 @@ void OtlpRecordableUtils::PopulateRequest( } } #endif - } // namespace otlp } // namespace exporter OPENTELEMETRY_END_NAMESPACE diff --git a/exporters/otlp/test/otlp_metrics_serialization_test.cc b/exporters/otlp/test/otlp_metrics_serialization_test.cc new file mode 100644 index 0000000000..2e19a86f3d --- /dev/null +++ b/exporters/otlp/test/otlp_metrics_serialization_test.cc @@ -0,0 +1,118 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifndef ENABLE_METRICS_PREVIEW + +# include "opentelemetry/exporters/otlp/otlp_metrics_utils.h" +# include "opentelemetry/proto/metrics/v1/metrics.pb.h" + +# include + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace otlp +{ +namespace resource = opentelemetry::sdk::resource; +namespace proto = opentelemetry::proto; +namespace metrics_sdk = opentelemetry::sdk::metrics; +namespace otlp_exporter = opentelemetry::exporter::otlp; + +metrics_sdk::MetricData CreateSumAggregationData() +{ + metrics_sdk::MetricData data; + data.start_ts = opentelemetry::common::SystemTimestamp(std::chrono::system_clock::now()); + metrics_sdk::InstrumentDescriptor inst_desc = {"Counter", "desc", "unit", + metrics_sdk::InstrumentType::kCounter, + metrics_sdk::InstrumentValueType::kDouble}; + metrics_sdk::SumPointData s_data_1, s_data_2; + s_data_1.value_ = 10.2; + s_data_2.value_ = 20.2; + + data.aggregation_temporality = metrics_sdk::AggregationTemporality::kCumulative; + data.end_ts = opentelemetry::common::SystemTimestamp(std::chrono::system_clock::now()); + data.instrument_descriptor = inst_desc; + metrics_sdk::PointDataAttributes point_data_attr_1, point_data_attr_2; + point_data_attr_1.attributes = {{"k1", "v1"}}; + point_data_attr_1.point_data = s_data_1; + + point_data_attr_2.attributes = {{"k2", "v2"}}; + point_data_attr_2.point_data = s_data_1; + std::vector point_data_attr; + point_data_attr.push_back(point_data_attr_1); + point_data_attr.push_back(point_data_attr_2); + data.point_data_attr_ = std::move(point_data_attr); + return data; +} + +metrics_sdk::MetricData CreateHistogramAggregationData() +{ + metrics_sdk::MetricData data; + data.start_ts = opentelemetry::common::SystemTimestamp(std::chrono::system_clock::now()); + metrics_sdk::InstrumentDescriptor inst_desc = {"Histogram", "desc", "unit", + metrics_sdk::InstrumentType::kCounter, + metrics_sdk::InstrumentValueType::kDouble}; + metrics_sdk::HistogramPointData s_data_1, s_data_2; + s_data_1.sum_ = 100.2; + s_data_1.count_ = 22; + s_data_1.counts_ = {2, 9, 4, 7}; + s_data_1.boundaries_ = std::list({0.0, 10.0, 20.0, 30.0}); + s_data_2.sum_ = 200.2; + s_data_2.count_ = 20; + s_data_2.counts_ = {0, 8, 5, 7}; + s_data_2.boundaries_ = std::list({0.0, 10.0, 20.0, 30.0}); + + data.aggregation_temporality = metrics_sdk::AggregationTemporality::kCumulative; + data.end_ts = opentelemetry::common::SystemTimestamp(std::chrono::system_clock::now()); + data.instrument_descriptor = inst_desc; + metrics_sdk::PointDataAttributes point_data_attr_1, point_data_attr_2; + point_data_attr_1.attributes = {{"k1", "v1"}}; + point_data_attr_1.point_data = s_data_1; + + point_data_attr_2.attributes = {{"k2", "v2"}}; + point_data_attr_2.point_data = s_data_1; + std::vector point_data_attr; + point_data_attr.push_back(point_data_attr_1); + point_data_attr.push_back(point_data_attr_2); + data.point_data_attr_ = std::move(point_data_attr); + return data; +} + +TEST(OtlpMetricsSerializationTest, Counter) +{ + metrics_sdk::MetricData data = CreateSumAggregationData(); + opentelemetry::proto::metrics::v1::Sum sum; + otlp_exporter::OtlpMetricsUtils::ConvertSumMetric(data, &sum); + EXPECT_EQ(sum.aggregation_temporality(), + proto::metrics::v1::AggregationTemporality::AGGREGATION_TEMPORALITY_CUMULATIVE); + EXPECT_EQ(sum.is_monotonic(), true); + for (size_t i = 0; i < 1; i++) + { + auto proto_number_point = sum.data_points(i); + EXPECT_EQ(proto_number_point.as_double(), i == 0 ? 10.2 : 20.2); + } + + EXPECT_EQ(1, 1); +} + +TEST(OtlpMetricsSerializationTest, Histogram) +{ + metrics_sdk::MetricData data = CreateHistogramAggregationData(); + opentelemetry::proto::metrics::v1::Histogram histogram; + otlp_exporter::OtlpMetricsUtils::ConvertHistogramMetric(data, &histogram); + EXPECT_EQ(histogram.aggregation_temporality(), + proto::metrics::v1::AggregationTemporality::AGGREGATION_TEMPORALITY_CUMULATIVE); + for (size_t i = 0; i < 1; i++) + { + auto proto_number_point = histogram.data_points(i); + EXPECT_EQ(proto_number_point.sum(), i == 0 ? 100.2 : 200.2); + } + + EXPECT_EQ(1, 1); +} + +} // namespace otlp +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE + +#endif diff --git a/exporters/otlp/test/otlp_recordable_test.cc b/exporters/otlp/test/otlp_recordable_test.cc index b46802d875..049f3e5aeb 100644 --- a/exporters/otlp/test/otlp_recordable_test.cc +++ b/exporters/otlp/test/otlp_recordable_test.cc @@ -14,6 +14,8 @@ namespace trace_sdk = opentelemetry::sdk::trace; namespace resource = opentelemetry::sdk::resource; namespace proto = opentelemetry::proto; +namespace trace_sdk_2 = opentelemetry::sdk::trace; + TEST(OtlpRecordable, SetIdentity) { constexpr uint8_t trace_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8}; diff --git a/sdk/include/opentelemetry/sdk/metrics/data/metric_data.h b/sdk/include/opentelemetry/sdk/metrics/data/metric_data.h index 738d4540f7..ca0f58f30f 100644 --- a/sdk/include/opentelemetry/sdk/metrics/data/metric_data.h +++ b/sdk/include/opentelemetry/sdk/metrics/data/metric_data.h @@ -31,6 +31,7 @@ class MetricData { public: InstrumentDescriptor instrument_descriptor; + AggregationTemporality aggregation_temporality; opentelemetry::common::SystemTimestamp start_ts; opentelemetry::common::SystemTimestamp end_ts; std::vector point_data_attr_; diff --git a/sdk/src/metrics/state/temporal_metric_storage.cc b/sdk/src/metrics/state/temporal_metric_storage.cc index 55e93e3d46..b208695b8a 100644 --- a/sdk/src/metrics/state/temporal_metric_storage.cc +++ b/sdk/src/metrics/state/temporal_metric_storage.cc @@ -110,9 +110,10 @@ bool TemporalMetricStorage::buildMetrics(CollectorHandle *collector, AttributesHashMap *result_to_export = (last_reported_metrics_[collector]).attributes_map.get(); MetricData metric_data; - metric_data.instrument_descriptor = instrument_descriptor_; - metric_data.start_ts = last_collection_ts; - metric_data.end_ts = collection_ts; + metric_data.instrument_descriptor = instrument_descriptor_; + metric_data.aggregation_temporality = aggregation_temporarily; + metric_data.start_ts = last_collection_ts; + metric_data.end_ts = collection_ts; result_to_export->GetAllEnteries( [&metric_data](const MetricAttributes &attributes, Aggregation &aggregation) { PointDataAttributes point_data_attr;