diff --git a/CHANGELOG.md b/CHANGELOG.md index e1ee4af753..8ac5e7012d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,9 @@ Increment the: * [SDK] Do not frequently create and destroy http client threads [#3198](https://github.com/open-telemetry/opentelemetry-cpp/pull/3198) +* [SDK] Fix instrumentation scope attributes evaluated in equal method + [#3214](https://github.com/open-telemetry/opentelemetry-cpp/pull/3214) + ## [1.18 2024-11-25] * [EXPORTER] Fix crash in ElasticsearchLogRecordExporter diff --git a/sdk/include/opentelemetry/sdk/common/attribute_utils.h b/sdk/include/opentelemetry/sdk/common/attribute_utils.h index 86b507a66b..c2d0209a7d 100644 --- a/sdk/include/opentelemetry/sdk/common/attribute_utils.h +++ b/sdk/include/opentelemetry/sdk/common/attribute_utils.h @@ -105,6 +105,60 @@ struct AttributeConverter } }; +/** + * Evaluates if an owned value (from an OwnedAttributeValue) is equal to another value (from a + * non-owning AttributeValue). This only supports the checking equality with + * nostd::visit(AttributeEqualToVisitor, OwnedAttributeValue, AttributeValue). + */ +struct AttributeEqualToVisitor +{ + // Different types are not equal including containers of different element types + template + bool operator()(const T &, const U &) const noexcept + { + return false; + } + + // Compare the same arithmetic types + template + bool operator()(const T &owned_value, const T &value) const noexcept + { + return owned_value == value; + } + + // Compare std::string and const char* + bool operator()(const std::string &owned_value, const char *value) const noexcept + { + return owned_value == value; + } + + // Compare std::string and nostd::string_view + bool operator()(const std::string &owned_value, nostd::string_view value) const noexcept + { + return owned_value == value; + } + + // Compare std::vector and nostd::span + bool operator()(const std::vector &owned_value, + const nostd::span &value) const noexcept + { + return owned_value.size() == value.size() && + std::equal(owned_value.begin(), owned_value.end(), value.begin(), + [](const std::string &owned_element, nostd::string_view element) { + return owned_element == element; + }); + } + + // Compare nostd::span and std::vector for arithmetic types + template + bool operator()(const std::vector &owned_value, + const nostd::span &value) const noexcept + { + return owned_value.size() == value.size() && + std::equal(owned_value.begin(), owned_value.end(), value.begin()); + } +}; + /** * Class for storing attributes. */ @@ -162,8 +216,37 @@ class AttributeMap : public std::unordered_map (*this)[std::string(key)] = nostd::visit(converter_, value); } + // Compare the attributes of this map with another KeyValueIterable + bool EqualTo(const opentelemetry::common::KeyValueIterable &attributes) const noexcept + { + if (attributes.size() != this->size()) + { + return false; + } + + const bool is_equal = attributes.ForEachKeyValue( + [this](nostd::string_view key, + const opentelemetry::common::AttributeValue &value) noexcept { + // Perform a linear search to find the key assuming the map is small + // This avoids temporary string creation from this->find(std::string(key)) + for (const auto &kv : *this) + { + if (kv.first == key) + { + // Order of arguments is important here. OwnedAttributeValue is first then + // AttributeValue AttributeEqualToVisitor does not support the reverse order + return nostd::visit(equal_to_visitor_, kv.second, value); + } + } + return false; + }); + + return is_equal; + } + private: AttributeConverter converter_; + AttributeEqualToVisitor equal_to_visitor_; }; /** diff --git a/sdk/include/opentelemetry/sdk/instrumentationscope/instrumentation_scope.h b/sdk/include/opentelemetry/sdk/instrumentationscope/instrumentation_scope.h index 1bf0facaa6..68e9d10d40 100644 --- a/sdk/include/opentelemetry/sdk/instrumentationscope/instrumentation_scope.h +++ b/sdk/include/opentelemetry/sdk/instrumentationscope/instrumentation_scope.h @@ -103,7 +103,8 @@ class InstrumentationScope */ bool operator==(const InstrumentationScope &other) const noexcept { - return equal(other.name_, other.version_, other.schema_url_); + return this->name_ == other.name_ && this->version_ == other.version_ && + this->schema_url_ == other.schema_url_ && this->attributes_ == other.attributes_; } /** @@ -112,14 +113,31 @@ class InstrumentationScope * @param name name of the instrumentation scope to compare. * @param version version of the instrumentation scope to compare. * @param schema_url schema url of the telemetry emitted by the scope. + * @param attributes attributes of the instrumentation scope to compare. * @returns true if name and version in this instrumentation scope are equal with the given name * and version. */ bool equal(const nostd::string_view name, const nostd::string_view version, - const nostd::string_view schema_url = "") const noexcept + const nostd::string_view schema_url = "", + const opentelemetry::common::KeyValueIterable *attributes = nullptr) const noexcept { - return this->name_ == name && this->version_ == version && this->schema_url_ == schema_url; + + if (this->name_ != name || this->version_ != version || this->schema_url_ != schema_url) + { + return false; + } + + if (attributes == nullptr) + { + if (attributes_.empty()) + { + return true; + } + return false; + } + + return attributes_.EqualTo(*attributes); } const std::string &GetName() const noexcept { return name_; } diff --git a/sdk/src/logs/logger_provider.cc b/sdk/src/logs/logger_provider.cc index 14febdf721..da282ab655 100644 --- a/sdk/src/logs/logger_provider.cc +++ b/sdk/src/logs/logger_provider.cc @@ -80,7 +80,7 @@ opentelemetry::nostd::shared_ptr LoggerProvider::Ge { auto &logger_lib = logger->GetInstrumentationScope(); if (logger->GetName() == logger_name && - logger_lib.equal(library_name, library_version, schema_url)) + logger_lib.equal(library_name, library_version, schema_url, &attributes)) { return opentelemetry::nostd::shared_ptr{logger}; } diff --git a/sdk/src/metrics/meter_provider.cc b/sdk/src/metrics/meter_provider.cc index 1c70fc2ed3..6856dac3a1 100644 --- a/sdk/src/metrics/meter_provider.cc +++ b/sdk/src/metrics/meter_provider.cc @@ -71,7 +71,7 @@ nostd::shared_ptr MeterProvider::GetMeter( for (auto &meter : context_->GetMeters()) { auto meter_lib = meter->GetInstrumentationScope(); - if (meter_lib->equal(name, version, schema_url)) + if (meter_lib->equal(name, version, schema_url, attributes)) { return nostd::shared_ptr{meter}; } diff --git a/sdk/src/trace/tracer_provider.cc b/sdk/src/trace/tracer_provider.cc index 6a26e13914..81bd7e6f11 100644 --- a/sdk/src/trace/tracer_provider.cc +++ b/sdk/src/trace/tracer_provider.cc @@ -101,7 +101,7 @@ nostd::shared_ptr TracerProvider::GetTracer( for (auto &tracer : tracers_) { auto &tracer_scope = tracer->GetInstrumentationScope(); - if (tracer_scope.equal(name, version, schema_url)) + if (tracer_scope.equal(name, version, schema_url, attributes)) { return nostd::shared_ptr{tracer}; } diff --git a/sdk/test/common/attribute_utils_test.cc b/sdk/test/common/attribute_utils_test.cc index 9b1f6bd56e..da303643d0 100644 --- a/sdk/test/common/attribute_utils_test.cc +++ b/sdk/test/common/attribute_utils_test.cc @@ -2,11 +2,14 @@ // SPDX-License-Identifier: Apache-2.0 #include +#include #include #include #include #include "opentelemetry/common/key_value_iterable_view.h" +#include "opentelemetry/nostd/span.h" +#include "opentelemetry/nostd/string_view.h" #include "opentelemetry/nostd/variant.h" #include "opentelemetry/sdk/common/attribute_utils.h" @@ -55,3 +58,132 @@ TEST(OrderedAttributeMapTest, AttributesConstruction) EXPECT_EQ(opentelemetry::nostd::get(attribute_map.GetAttributes().at(keys[i])), values[i]); } } + +TEST(AttributeEqualToVisitorTest, AttributeValueEqualTo) +{ + namespace sdk = opentelemetry::sdk::common; + namespace api = opentelemetry::common; + namespace nostd = opentelemetry::nostd; + + using AV = api::AttributeValue; + using OV = sdk::OwnedAttributeValue; + + sdk::AttributeEqualToVisitor equal_to_visitor; + + // arithmetic types + EXPECT_TRUE(opentelemetry::nostd::visit(equal_to_visitor, OV{bool(true)}, AV{bool(true)})); + EXPECT_TRUE(opentelemetry::nostd::visit(equal_to_visitor, OV{int32_t(22)}, AV{int32_t(22)})); + EXPECT_TRUE(opentelemetry::nostd::visit(equal_to_visitor, OV{int64_t(22)}, AV{int64_t(22)})); + EXPECT_TRUE(opentelemetry::nostd::visit(equal_to_visitor, OV{uint32_t(22)}, AV{uint32_t(22)})); + EXPECT_TRUE(opentelemetry::nostd::visit(equal_to_visitor, OV{uint64_t(22)}, AV{uint64_t(22)})); + EXPECT_TRUE(opentelemetry::nostd::visit(equal_to_visitor, OV{double(22.0)}, AV{double(22.0)})); + + // string types + EXPECT_TRUE(opentelemetry::nostd::visit( + equal_to_visitor, OV{std::string("string to const char*")}, AV{"string to const char*"})); + EXPECT_TRUE(opentelemetry::nostd::visit(equal_to_visitor, + OV{std::string("string to string_view")}, + AV{nostd::string_view("string to string_view")})); + + // container types + EXPECT_TRUE(opentelemetry::nostd::visit(equal_to_visitor, OV{std::vector{true, false}}, + AV{std::array{true, false}})); + EXPECT_TRUE(opentelemetry::nostd::visit(equal_to_visitor, OV{std::vector{33, 44}}, + AV{std::array{33, 44}})); + EXPECT_TRUE(opentelemetry::nostd::visit(equal_to_visitor, OV{std::vector{33, 44}}, + AV{std::array{33, 44}})); + EXPECT_TRUE(opentelemetry::nostd::visit(equal_to_visitor, OV{std::vector{33, 44}}, + AV{std::array{33, 44}})); + EXPECT_TRUE(opentelemetry::nostd::visit(equal_to_visitor, OV{std::vector{33, 44}}, + AV{std::array{33, 44}})); + EXPECT_TRUE(opentelemetry::nostd::visit(equal_to_visitor, OV{std::vector{33, 44}}, + AV{std::array{33, 44}})); + EXPECT_TRUE(opentelemetry::nostd::visit(equal_to_visitor, OV{std::vector{33.0, 44.0}}, + AV{std::array{33.0, 44.0}})); + EXPECT_TRUE(opentelemetry::nostd::visit( + equal_to_visitor, OV{std::vector{"a string", "another string"}}, + AV{std::array{"a string", "another string"}})); +} + +TEST(AttributeEqualToVisitorTest, AttributeValueNotEqualTo) +{ + namespace sdk = opentelemetry::sdk::common; + namespace api = opentelemetry::common; + namespace nostd = opentelemetry::nostd; + + using AV = api::AttributeValue; + using OV = sdk::OwnedAttributeValue; + + sdk::AttributeEqualToVisitor equal_to_visitor; + + // check different values of the same type + EXPECT_FALSE(opentelemetry::nostd::visit(equal_to_visitor, OV{bool(true)}, AV{bool(false)})); + EXPECT_FALSE(opentelemetry::nostd::visit(equal_to_visitor, OV{int32_t(22)}, AV{int32_t(33)})); + EXPECT_FALSE(opentelemetry::nostd::visit(equal_to_visitor, OV{int64_t(22)}, AV{int64_t(33)})); + EXPECT_FALSE(opentelemetry::nostd::visit(equal_to_visitor, OV{uint32_t(22)}, AV{uint32_t(33)})); + EXPECT_FALSE(opentelemetry::nostd::visit(equal_to_visitor, OV{double(22.2)}, AV{double(33.3)})); + EXPECT_FALSE(opentelemetry::nostd::visit(equal_to_visitor, OV{std::string("string one")}, + AV{"another string"})); + EXPECT_FALSE(opentelemetry::nostd::visit(equal_to_visitor, OV{std::string("string one")}, + AV{nostd::string_view("another string")})); + + // check different value types + EXPECT_FALSE(opentelemetry::nostd::visit(equal_to_visitor, OV{bool(true)}, AV{uint32_t(1)})); + EXPECT_FALSE(opentelemetry::nostd::visit(equal_to_visitor, OV{int32_t(22)}, AV{uint32_t(22)})); + + // check containers of different element values + EXPECT_FALSE(opentelemetry::nostd::visit(equal_to_visitor, OV{std::vector{true, false}}, + AV{std::array{false, true}})); + EXPECT_FALSE(opentelemetry::nostd::visit(equal_to_visitor, OV{std::vector{22, 33}}, + AV{std::array{33, 44}})); + EXPECT_FALSE(opentelemetry::nostd::visit( + equal_to_visitor, OV{std::vector{"a string", "another string"}}, + AV{std::array{"a string", "a really different string"}})); + + // check containers of different element types + EXPECT_FALSE(opentelemetry::nostd::visit(equal_to_visitor, OV{std::vector{22, 33}}, + AV{std::array{22, 33}})); +} + +TEST(AttributeMapTest, EqualTo) +{ + using Attributes = std::initializer_list< + std::pair>; + + // check for case where both are empty + Attributes attributes_empty = {}; + auto kv_iterable_empty = + opentelemetry::common::MakeKeyValueIterableView(attributes_empty); + opentelemetry::sdk::common::AttributeMap attribute_map_empty(kv_iterable_empty); + EXPECT_TRUE(attribute_map_empty.EqualTo(kv_iterable_empty)); + + // check for equality with a range of attributes and types + Attributes attributes = {{"key0", "some value"}, {"key1", 1}, {"key2", 2.0}, {"key3", true}}; + auto kv_iterable_match = opentelemetry::common::MakeKeyValueIterableView(attributes); + opentelemetry::sdk::common::AttributeMap attribute_map(attributes); + EXPECT_TRUE(attribute_map.EqualTo(kv_iterable_match)); + + // check for several cases where the attributes are different + Attributes attributes_different_value = { + {"key0", "some value"}, {"key1", 1}, {"key2", 2.0}, {"key3", false}}; + Attributes attributes_different_type = { + {"key0", "some value"}, {"key1", 1.0}, {"key2", 2.0}, {"key3", true}}; + Attributes attributes_different_size = {{"key0", "some value"}}; + + // check for the case where the number of attributes is the same but all keys are different + Attributes attributes_different_all = {{"a", "b"}, {"c", "d"}, {"e", 4.0}, {"f", uint8_t(5)}}; + + auto kv_iterable_different_value = + opentelemetry::common::MakeKeyValueIterableView(attributes_different_value); + auto kv_iterable_different_type = + opentelemetry::common::MakeKeyValueIterableView(attributes_different_type); + auto kv_iterable_different_size = + opentelemetry::common::MakeKeyValueIterableView(attributes_different_size); + auto kv_iterable_different_all = + opentelemetry::common::MakeKeyValueIterableView(attributes_different_all); + + EXPECT_FALSE(attribute_map.EqualTo(kv_iterable_different_value)); + EXPECT_FALSE(attribute_map.EqualTo(kv_iterable_different_type)); + EXPECT_FALSE(attribute_map.EqualTo(kv_iterable_different_size)); + EXPECT_FALSE(attribute_map.EqualTo(kv_iterable_different_all)); +} diff --git a/sdk/test/instrumentationscope/instrumentationscope_test.cc b/sdk/test/instrumentationscope/instrumentationscope_test.cc index da00ec8e93..347e107aca 100644 --- a/sdk/test/instrumentationscope/instrumentationscope_test.cc +++ b/sdk/test/instrumentationscope/instrumentationscope_test.cc @@ -208,3 +208,99 @@ TEST(InstrumentationScope, LegacyInstrumentationLibrary) EXPECT_EQ(instrumentation_library->GetVersion(), library_version); EXPECT_EQ(instrumentation_library->GetSchemaURL(), schema_url); } + +TEST(InstrumentationScope, Equal) +{ + using Attributes = std::initializer_list< + std::pair>; + Attributes attributes_empty = {}; + Attributes attributes_match = { + {"key0", "some value"}, {"key1", 1}, {"key2", 2.0}, {"key3", true}}; + Attributes attributes_different = {{"key42", "some other"}}; + + auto kv_iterable_empty = + opentelemetry::common::MakeKeyValueIterableView(attributes_empty); + auto kv_iterable_match = + opentelemetry::common::MakeKeyValueIterableView(attributes_match); + auto kv_iterable_different = + opentelemetry::common::MakeKeyValueIterableView(attributes_different); + + // try with no attributes added to the instrumentation scope + auto instrumentation_scope = + opentelemetry::sdk::instrumentationscope::InstrumentationScope::Create( + "library_name", "library_version", "schema_url"); + + // the instrumentation scope is equal if all parameters are equal (must handle nullptr attributes + // or empty attributes) + EXPECT_TRUE(instrumentation_scope->equal("library_name", "library_version", "schema_url")); + EXPECT_TRUE( + instrumentation_scope->equal("library_name", "library_version", "schema_url", nullptr)); + EXPECT_TRUE(instrumentation_scope->equal("library_name", "library_version", "schema_url", + &kv_iterable_empty)); + + // the instrumentation scope is not equal if any parameter is different + EXPECT_FALSE(instrumentation_scope->equal("library_name", "")); + EXPECT_FALSE(instrumentation_scope->equal("library_name", "library_version", "")); + EXPECT_FALSE(instrumentation_scope->equal("library_name", "library_version", "schema_url", + &kv_iterable_different)); + + // try with attributes added to the instrumentation scope + auto instrumentation_scope_w_attributes = + opentelemetry::sdk::instrumentationscope::InstrumentationScope::Create( + "library_name", "library_version", "schema_url", attributes_match); + + // the instrumentation scope is equal if all parameters including all attribute keys, types, and + // values are equal + EXPECT_TRUE(instrumentation_scope_w_attributes->equal("library_name", "library_version", + "schema_url", &kv_iterable_match)); + EXPECT_FALSE(instrumentation_scope_w_attributes->equal("library_name", "library_version", + "schema_url", nullptr)); + EXPECT_FALSE(instrumentation_scope_w_attributes->equal("library_name", "library_version", + "schema_url", &kv_iterable_empty)); + EXPECT_FALSE(instrumentation_scope_w_attributes->equal("library_name", "library_version", + "schema_url", &kv_iterable_different)); +} + +TEST(InstrumentationScope, OperatorEqual) +{ + using Attributes = std::initializer_list< + std::pair>; + Attributes attributes_empty = {}; + Attributes attributes_match = { + {"key0", "some value"}, {"key1", 1}, {"key2", 2.0}, {"key3", true}}; + Attributes attributes_different = {{"key42", "some other"}}; + + auto instrumentation_scope_1a = + opentelemetry::sdk::instrumentationscope::InstrumentationScope::Create( + "library_name", "library_version", "schema_url"); + + auto instrumentation_scope_1b = + opentelemetry::sdk::instrumentationscope::InstrumentationScope::Create( + "library_name", "library_version", "schema_url"); + + auto instrumentation_scope_2a = + opentelemetry::sdk::instrumentationscope::InstrumentationScope::Create( + "library_name_2", "library_version", "schema_url"); + + auto instrumentation_scope_2b = + opentelemetry::sdk::instrumentationscope::InstrumentationScope::Create( + "library_name_2", "library_version", "schema_url", attributes_empty); + + auto instrumentation_scope_3a = + opentelemetry::sdk::instrumentationscope::InstrumentationScope::Create( + "library_name_2", "library_version", "schema_url", attributes_match); + + auto instrumentation_scope_3b = + opentelemetry::sdk::instrumentationscope::InstrumentationScope::Create( + "library_name_2", "library_version", "schema_url", attributes_match); + + auto instrumentation_scope_4 = + opentelemetry::sdk::instrumentationscope::InstrumentationScope::Create( + "library_name_2", "library_version", "schema_url", attributes_different); + + EXPECT_EQ(*instrumentation_scope_1a, *instrumentation_scope_1b); + EXPECT_FALSE(*instrumentation_scope_1a == *instrumentation_scope_2a); + EXPECT_EQ(*instrumentation_scope_2a, *instrumentation_scope_2b); + EXPECT_EQ(*instrumentation_scope_3a, *instrumentation_scope_3b); + EXPECT_FALSE(*instrumentation_scope_3a == *instrumentation_scope_4); +} diff --git a/sdk/test/logs/logger_provider_sdk_test.cc b/sdk/test/logs/logger_provider_sdk_test.cc index a5a3d3a68a..edddf2ef96 100644 --- a/sdk/test/logs/logger_provider_sdk_test.cc +++ b/sdk/test/logs/logger_provider_sdk_test.cc @@ -129,7 +129,7 @@ TEST(LoggerProviderSDK, EventLoggerProviderFactory) auto event_logger = elp->CreateEventLogger(logger1, "otel-cpp.test"); } -TEST(LoggerPviderSDK, LoggerEquityCheck) +TEST(LoggerProviderSDK, LoggerEqualityCheck) { auto lp = std::shared_ptr(new LoggerProvider()); nostd::string_view schema_url{"https://opentelemetry.io/schemas/1.11.0"}; @@ -141,6 +141,48 @@ TEST(LoggerPviderSDK, LoggerEquityCheck) auto logger3 = lp->GetLogger("logger3"); auto another_logger3 = lp->GetLogger("logger3"); EXPECT_EQ(logger3, another_logger3); + + auto logger4 = lp->GetLogger("logger4", "opentelelemtry_library", "1.0.0", schema_url); + auto another_logger4 = lp->GetLogger("logger4", "opentelelemtry_library", "1.0.0", schema_url); + EXPECT_EQ(logger4, another_logger4); + + auto logger5 = + lp->GetLogger("logger5", "opentelelemtry_library", "1.0.0", schema_url, {{"key", "value"}}); + auto another_logger5 = + lp->GetLogger("logger5", "opentelelemtry_library", "1.0.0", schema_url, {{"key", "value"}}); + EXPECT_EQ(logger5, another_logger5); +} + +TEST(LoggerProviderSDK, GetLoggerInequalityCheck) +{ + auto lp = std::shared_ptr(new LoggerProvider()); + auto logger_library_1 = lp->GetLogger("logger1", "library_1"); + auto logger_library_2 = lp->GetLogger("logger1", "library_2"); + auto logger_version_1 = lp->GetLogger("logger1", "library_1", "1.0.0"); + auto logger_version_2 = lp->GetLogger("logger1", "library_1", "2.0.0"); + auto logger_url_1 = lp->GetLogger("logger1", "library_1", "1.0.0", "url_1"); + auto logger_url_2 = lp->GetLogger("logger1", "library_1", "1.0.0", "url_2"); + auto logger_attribute_1 = + lp->GetLogger("logger1", "library_1", "1.0.0", "url_1", {{"key", "one"}}); + auto logger_attribute_2 = + lp->GetLogger("logger1", "library_1", "1.0.0", "url_1", {{"key", "two"}}); + + // different scope names should return distinct loggers + EXPECT_NE(logger_library_1, logger_library_2); + + // different scope versions should return distinct loggers + EXPECT_NE(logger_version_1, logger_library_1); + EXPECT_NE(logger_version_1, logger_version_2); + + // different scope schema urls should return distinct loggers + EXPECT_NE(logger_url_1, logger_library_1); + EXPECT_NE(logger_url_1, logger_version_1); + EXPECT_NE(logger_url_1, logger_url_2); + + // different scope attributes should return distinct loggers + EXPECT_NE(logger_attribute_1, logger_library_1); + EXPECT_NE(logger_attribute_1, logger_url_1); + EXPECT_NE(logger_attribute_1, logger_attribute_2); } class DummyLogRecordable final : public opentelemetry::sdk::logs::Recordable diff --git a/sdk/test/metrics/meter_provider_sdk_test.cc b/sdk/test/metrics/meter_provider_sdk_test.cc index 36cb28c228..ee8a8a88c6 100644 --- a/sdk/test/metrics/meter_provider_sdk_test.cc +++ b/sdk/test/metrics/meter_provider_sdk_test.cc @@ -12,6 +12,7 @@ #include "opentelemetry/sdk/metrics/instruments.h" #include "opentelemetry/sdk/metrics/meter.h" #include "opentelemetry/sdk/metrics/meter_provider.h" +#include "opentelemetry/sdk/metrics/meter_provider_factory.h" #include "opentelemetry/sdk/metrics/metric_reader.h" #include "opentelemetry/sdk/metrics/push_metric_exporter.h" #include "opentelemetry/sdk/metrics/view/instrument_selector.h" @@ -239,3 +240,74 @@ TEST(MeterProvider, RemoveMeter) mp.Shutdown(); } #endif /* OPENTELEMETRY_ABI_VERSION_NO >= 2 */ + +TEST(MeterProvider, GetMeterEqualityCheck) +{ + auto provider = MeterProviderFactory::Create(); + + // providing the same scope names should return the same Meter + auto meter_library_1a = provider->GetMeter("library_name"); + auto meter_library_1b = provider->GetMeter("library_name"); + EXPECT_EQ(meter_library_1a, meter_library_1b); + + // providing the same scope name and version should return the same meter + auto meter_version_1a = provider->GetMeter("library_name", "v1.0"); + auto meter_version_1b = provider->GetMeter("library_name", "v1.0"); + EXPECT_EQ(meter_version_1a, meter_version_1b); + + // providing the same name, version, and schema urls should return the same meter + auto meter_urla = provider->GetMeter("library_name", "v1.0", "url"); + auto meter_urlb = provider->GetMeter("library_name", "v1.0", "url"); + EXPECT_EQ(meter_urla, meter_urlb); +} + +TEST(MeterProvider, GetMeterInequalityCheck) +{ + auto provider = MeterProviderFactory::Create(); + + auto meter_library_1 = provider->GetMeter("library_1"); + auto meter_library_2 = provider->GetMeter("library_2"); + auto meter_version_1 = provider->GetMeter("library_1", "v1.0"); + auto meter_version_2 = provider->GetMeter("library_1", "v2.0"); + auto meter_url_1 = provider->GetMeter("library_1", "v1.0", "url_1"); + auto meter_url_2 = provider->GetMeter("library_1", "v1.0", "url_2"); + + // different scope names should return distinct meters + EXPECT_NE(meter_library_1, meter_library_2); + + // different scope versions should return distinct meters + EXPECT_NE(meter_version_1, meter_library_1); + EXPECT_NE(meter_version_1, meter_version_2); + + // different scope schema urls should return distinct meters + EXPECT_NE(meter_url_1, meter_library_1); + EXPECT_NE(meter_url_1, meter_version_1); + EXPECT_NE(meter_url_1, meter_url_2); +} + +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + +TEST(MeterProvider, GetMeterEqualityCheckAbiv2) +{ + auto provider = MeterProviderFactory::Create(); + + // providing the same name, version, schema url and attributes should return the same meter + auto meter_attribute1a = provider->GetMeter("library_name", "v1.0", "url", {{"key", "one"}}); + auto meter_attribute1b = provider->GetMeter("library_name", "v1.0", "url", {{"key", "one"}}); + EXPECT_EQ(meter_attribute1a, meter_attribute1b); +} + +TEST(MeterProvider, GetMeterInequalityCheckAbiv2) +{ + auto provider = MeterProviderFactory::Create(); + + auto meter_1 = provider->GetMeter("library_name", "v1.0", "url"); + auto meter_attribute_1 = provider->GetMeter("library_name", "v1.0", "url", {{"key", "one"}}); + auto meter_attribute_2 = provider->GetMeter("library_name", "v1.0", "url", {{"key", "two"}}); + + // different scope attributes should return distinct meters + EXPECT_NE(meter_attribute_1, meter_1); + EXPECT_NE(meter_attribute_1, meter_attribute_2); +} + +#endif /* OPENTELEMETRY_ABI_VERSION_NO >= 2 */ diff --git a/sdk/test/trace/tracer_provider_test.cc b/sdk/test/trace/tracer_provider_test.cc index fa3afa2690..8bdad908ad 100644 --- a/sdk/test/trace/tracer_provider_test.cc +++ b/sdk/test/trace/tracer_provider_test.cc @@ -19,9 +19,11 @@ #include "opentelemetry/sdk/trace/sampler.h" #include "opentelemetry/sdk/trace/samplers/always_off.h" #include "opentelemetry/sdk/trace/simple_processor.h" +#include "opentelemetry/sdk/trace/simple_processor_factory.h" #include "opentelemetry/sdk/trace/tracer.h" #include "opentelemetry/sdk/trace/tracer_context.h" #include "opentelemetry/sdk/trace/tracer_provider.h" +#include "opentelemetry/sdk/trace/tracer_provider_factory.h" using namespace opentelemetry::sdk::trace; using namespace opentelemetry::sdk::resource; @@ -89,7 +91,80 @@ TEST(TracerProvider, GetTracer) ASSERT_EQ(instrumentation_scope3.GetVersion(), "1.0.0"); } +TEST(TracerProvider, GetTracerEqualityCheck) +{ + auto processor = SimpleSpanProcessorFactory::Create(nullptr); + auto provider = TracerProviderFactory::Create(std::move(processor)); + + // providing the same scope names should return the same tracer + auto tracer_1a = provider->GetTracer("library_name"); + auto tracer_1b = provider->GetTracer("library_name"); + EXPECT_EQ(tracer_1a, tracer_1b); + + // providing the same scope name and version should return the same tracer + auto tracer_version1a = provider->GetTracer("library_name", "v1.0"); + auto tracer_version1b = provider->GetTracer("library_name", "v1.0"); + EXPECT_EQ(tracer_version1a, tracer_version1b); + + // providing the same name, version, and schema urls should return the same tracer + auto tracer_urla = provider->GetTracer("library_name", "v1.0", "url"); + auto tracer_urlb = provider->GetTracer("library_name", "v1.0", "url"); + EXPECT_EQ(tracer_urla, tracer_urlb); +} + +TEST(TracerProvider, GetTracerInequalityCheck) +{ + auto processor = SimpleSpanProcessorFactory::Create(nullptr); + auto provider = TracerProviderFactory::Create(std::move(processor)); + + auto tracer_library_1 = provider->GetTracer("library_1"); + auto tracer_library_2 = provider->GetTracer("library_2"); + auto tracer_version_1 = provider->GetTracer("library_1", "v1.0"); + auto tracer_version_2 = provider->GetTracer("library_1", "v2.0"); + auto tracer_url_1 = provider->GetTracer("library_1", "v1.0", "url_1"); + auto tracer_url_2 = provider->GetTracer("library_1", "v1.0", "url_2"); + + // different scope names should return distinct tracers + EXPECT_NE(tracer_library_1, tracer_library_2); + + // different scope versions should return distinct tracers + EXPECT_NE(tracer_version_1, tracer_library_1); + EXPECT_NE(tracer_version_1, tracer_version_2); + + // different scope schema urls should return distinct tracers + EXPECT_NE(tracer_url_1, tracer_library_1); + EXPECT_NE(tracer_url_1, tracer_version_1); + EXPECT_NE(tracer_url_1, tracer_url_2); +} + #if OPENTELEMETRY_ABI_VERSION_NO >= 2 + +TEST(TracerProvider, GetTracerEqualityCheckAbiv2) +{ + auto processor = SimpleSpanProcessorFactory::Create(nullptr); + auto provider = TracerProviderFactory::Create(std::move(processor)); + + auto tracer_attribute1a = provider->GetTracer("library_name", "v1.0", "url", {{"key", "one"}}); + auto tracer_attribute1b = provider->GetTracer("library_name", "v1.0", "url", {{"key", "one"}}); + + // providing the same name, version, schema url and attributes should return the same tracer + EXPECT_EQ(tracer_attribute1a, tracer_attribute1b); +} + +TEST(TracerProvider, GetTracerInequalityCheckAbiv2) +{ + auto processor = SimpleSpanProcessorFactory::Create(nullptr); + auto provider = TracerProviderFactory::Create(std::move(processor)); + + auto tracer_1 = provider->GetTracer("library_name", "v1.0", "url"); + auto tracer_attribute1 = provider->GetTracer("library_name", "v1.0", "url", {{"key", "one"}}); + auto tracer_attribute2 = provider->GetTracer("library_name", "v1.0", "url", {{"key", "two"}}); + + // different scope attributes should return distinct tracers + EXPECT_NE(tracer_attribute1, tracer_1); + EXPECT_NE(tracer_attribute1, tracer_attribute2); +} + TEST(TracerProvider, GetTracerAbiv2) { std::unique_ptr processor(new SimpleSpanProcessor(nullptr));