diff --git a/examples/multithreaded/main.cc b/examples/multithreaded/main.cc index f4d7726ccc..1a756c973b 100644 --- a/examples/multithreaded/main.cc +++ b/examples/multithreaded/main.cc @@ -1,3 +1,4 @@ +#include "opentelemetry/sdk/resource/resource.h" #include "opentelemetry/sdk/trace/simple_processor.h" #include "opentelemetry/sdk/trace/tracer_provider.h" #include "opentelemetry/trace/provider.h" @@ -18,7 +19,7 @@ void initTracer() auto processor = std::shared_ptr( new sdktrace::SimpleSpanProcessor(std::move(exporter))); auto provider = nostd::shared_ptr( - new sdktrace::TracerProvider(processor)); + new sdktrace::TracerProvider(processor, opentelemetry::sdk::resource::Resource::Create({}))); // Set the global trace provider opentelemetry::trace::Provider::SetTracerProvider(provider); } diff --git a/examples/simple/main.cc b/examples/simple/main.cc index 485d31c2ec..5d22c6b155 100644 --- a/examples/simple/main.cc +++ b/examples/simple/main.cc @@ -15,7 +15,9 @@ void initTracer() auto processor = std::shared_ptr( new sdktrace::SimpleSpanProcessor(std::move(exporter))); auto provider = nostd::shared_ptr( - new sdktrace::TracerProvider(processor)); + new sdktrace::TracerProvider(processor, opentelemetry::sdk::resource::Resource::Create({}), + std::make_shared())); + // Set the global trace provider opentelemetry::trace::Provider::SetTracerProvider(provider); } diff --git a/ext/test/zpages/tracez_data_aggregator_test.cc b/ext/test/zpages/tracez_data_aggregator_test.cc index a5240257cb..b15d38873e 100644 --- a/ext/test/zpages/tracez_data_aggregator_test.cc +++ b/ext/test/zpages/tracez_data_aggregator_test.cc @@ -3,6 +3,7 @@ #include #include "opentelemetry/ext/zpages/tracez_processor.h" +#include "opentelemetry/sdk/resource/resource.h" #include "opentelemetry/sdk/trace/recordable.h" #include "opentelemetry/sdk/trace/tracer.h" @@ -34,7 +35,8 @@ class TracezDataAggregatorTest : public ::testing::Test void SetUp() override { std::shared_ptr processor(new TracezSpanProcessor()); - tracer = std::shared_ptr(new Tracer(processor)); + auto resource = opentelemetry::sdk::resource::Resource::Create({}); + tracer = std::shared_ptr(new Tracer(processor, resource)); tracez_data_aggregator = std::unique_ptr( new TracezDataAggregator(processor, milliseconds(10))); } diff --git a/ext/test/zpages/tracez_processor_test.cc b/ext/test/zpages/tracez_processor_test.cc index 65acddd807..2d9246495a 100644 --- a/ext/test/zpages/tracez_processor_test.cc +++ b/ext/test/zpages/tracez_processor_test.cc @@ -6,6 +6,7 @@ #include "opentelemetry/ext/zpages/threadsafe_span_data.h" #include "opentelemetry/nostd/span.h" +#include "opentelemetry/sdk/resource/resource.h" #include "opentelemetry/sdk/trace/tracer.h" using namespace opentelemetry::sdk::trace; @@ -174,8 +175,10 @@ class TracezProcessor : public ::testing::Test protected: void SetUp() override { - processor = std::shared_ptr(new TracezSpanProcessor()); - tracer = std::shared_ptr(new Tracer(processor)); + processor = std::shared_ptr(new TracezSpanProcessor()); + auto resource = opentelemetry::sdk::resource::Resource::Create({}); + + tracer = std::shared_ptr(new Tracer(processor, resource)); auto spans = processor->GetSpanSnapshot(); running = spans.running; completed = std::move(spans.completed); diff --git a/sdk/include/opentelemetry/sdk/resource/resource.h b/sdk/include/opentelemetry/sdk/resource/resource.h new file mode 100644 index 0000000000..3efecff255 --- /dev/null +++ b/sdk/include/opentelemetry/sdk/resource/resource.h @@ -0,0 +1,77 @@ +#pragma once + +#include "opentelemetry/sdk/common/attribute_utils.h" +#include "opentelemetry/sdk/resource/resource_detector.h" +#include "opentelemetry/sdk/version/version.h" +#include "opentelemetry/version.h" + +#include +#include +#include + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace resource +{ + +using ResourceAttributes = + std::unordered_map; + +class Resource +{ +public: + Resource(const Resource &) = default; + + const ResourceAttributes &GetAttributes() const noexcept; + + /** + * Returns a new, merged {@link Resource} by merging the current Resource + * with the other Resource. In case of a collision, current Resource takes + * precedence. + * + * @param other the Resource that will be merged with this. + * @returns the newly merged Resource. + */ + + Resource Merge(const Resource &other) noexcept; + + /** + * Returns a newly created Resource with the specified attributes. + * It adds (merge) SDK attributes and OTEL attributes before returning. + * @param attributes for this resource + * @returns the newly created Resource. + */ + + static Resource Create(const ResourceAttributes &attributes); + + /** + * Returns an Empty resource. + */ + + static Resource &GetEmpty(); + + /** + * Returns a Resource that indentifies the SDK in use. + */ + + static Resource &GetDefault(); + +protected: + /** + * The constructor is protected and only for use internally by the class and + * inside ResourceDetector class. + * Users should use the Create factory method to obtain a Resource + * instance. + */ + Resource(const ResourceAttributes &attributes = ResourceAttributes()) noexcept; + +private: + ResourceAttributes attributes_; + + friend class OTELResourceDetector; +}; + +} // namespace resource +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE \ No newline at end of file diff --git a/sdk/include/opentelemetry/sdk/resource/resource_detector.h b/sdk/include/opentelemetry/sdk/resource/resource_detector.h new file mode 100644 index 0000000000..76a38d60b7 --- /dev/null +++ b/sdk/include/opentelemetry/sdk/resource/resource_detector.h @@ -0,0 +1,35 @@ +#pragma once + +#include "opentelemetry/nostd/unique_ptr.h" +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace resource +{ + +class Resource; + +/** + * Interface for a Resource Detector + */ +class ResourceDetector +{ +public: + virtual Resource Detect() = 0; +}; + +/** + * OTelResourceDetector to detect the presence of and create a Resource + * from the OTEL_RESOURCE_ATTRIBUTES environment variable. + */ +class OTELResourceDetector : public ResourceDetector +{ +public: + Resource Detect() noexcept override; +}; + +} // namespace resource +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE \ No newline at end of file diff --git a/sdk/include/opentelemetry/sdk/trace/tracer.h b/sdk/include/opentelemetry/sdk/trace/tracer.h index f633c8ed67..8a9d955b67 100644 --- a/sdk/include/opentelemetry/sdk/trace/tracer.h +++ b/sdk/include/opentelemetry/sdk/trace/tracer.h @@ -1,6 +1,7 @@ #pragma once #include "opentelemetry/sdk/common/atomic_shared_ptr.h" +#include "opentelemetry/sdk/resource/resource.h" #include "opentelemetry/sdk/trace/processor.h" #include "opentelemetry/sdk/trace/samplers/always_on.h" #include "opentelemetry/trace/noop.h" @@ -23,6 +24,7 @@ class Tracer final : public trace_api::Tracer, public std::enable_shared_from_th * nullptr. */ explicit Tracer(std::shared_ptr processor, + const opentelemetry::sdk::resource::Resource &resource, std::shared_ptr sampler = std::make_shared()) noexcept; /** @@ -57,6 +59,7 @@ class Tracer final : public trace_api::Tracer, public std::enable_shared_from_th private: opentelemetry::sdk::AtomicSharedPtr processor_; const std::shared_ptr sampler_; + const opentelemetry::sdk::resource::Resource &resource_; }; } // namespace trace } // namespace sdk diff --git a/sdk/include/opentelemetry/sdk/trace/tracer_provider.h b/sdk/include/opentelemetry/sdk/trace/tracer_provider.h index 6e4c7b81ab..a6de0a998d 100644 --- a/sdk/include/opentelemetry/sdk/trace/tracer_provider.h +++ b/sdk/include/opentelemetry/sdk/trace/tracer_provider.h @@ -5,6 +5,7 @@ #include #include "opentelemetry/nostd/shared_ptr.h" +#include "opentelemetry/sdk/resource/resource.h" #include "opentelemetry/sdk/trace/processor.h" #include "opentelemetry/sdk/trace/samplers/always_on.h" #include "opentelemetry/sdk/trace/tracer.h" @@ -27,6 +28,8 @@ class TracerProvider final : public opentelemetry::trace::TracerProvider */ explicit TracerProvider( std::shared_ptr processor, + opentelemetry::sdk::resource::Resource &&resource = + opentelemetry::sdk::resource::Resource::Create({}), std::shared_ptr sampler = std::make_shared()) noexcept; opentelemetry::nostd::shared_ptr GetTracer( @@ -48,10 +51,16 @@ class TracerProvider final : public opentelemetry::trace::TracerProvider /** * Obtain the sampler associated with this tracer provider. - * @return The span processor for this tracer provider. + * @return The sampler for this tracer provider. */ std::shared_ptr GetSampler() const noexcept; + /** + * Obtain the resource associated with this tracer provider. + * @return The resource for this tracer provider. + */ + const opentelemetry::sdk::resource::Resource &GetResource() const noexcept; + /** * Shutdown the span processor associated with this tracer provider. */ @@ -61,6 +70,7 @@ class TracerProvider final : public opentelemetry::trace::TracerProvider opentelemetry::sdk::AtomicSharedPtr processor_; std::shared_ptr tracer_; const std::shared_ptr sampler_; + const opentelemetry::sdk::resource::Resource resource_; }; } // namespace trace } // namespace sdk diff --git a/sdk/src/CMakeLists.txt b/sdk/src/CMakeLists.txt index 8e0a99edc0..56adec57d5 100644 --- a/sdk/src/CMakeLists.txt +++ b/sdk/src/CMakeLists.txt @@ -3,3 +3,4 @@ add_subdirectory(trace) add_subdirectory(metrics) add_subdirectory(logs) add_subdirectory(version) +add_subdirectory(resource) diff --git a/sdk/src/resource/BUILD b/sdk/src/resource/BUILD new file mode 100644 index 0000000000..e42948b7eb --- /dev/null +++ b/sdk/src/resource/BUILD @@ -0,0 +1,26 @@ +# Copyright 2020, OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "resource", + srcs = glob(["**/*.cc"]), + hdrs = glob(["**/*.h"]), + include_prefix = "src/resource", + deps = [ + "//api", + "//sdk:headers", + ], +) diff --git a/sdk/src/resource/CMakeLists.txt b/sdk/src/resource/CMakeLists.txt new file mode 100644 index 0000000000..f8e8267dc2 --- /dev/null +++ b/sdk/src/resource/CMakeLists.txt @@ -0,0 +1,16 @@ +add_library(opentelemetry_resources resource.cc resource_detector.cc) + +set_target_properties(opentelemetry_resources PROPERTIES EXPORT_NAME resources) + +target_link_libraries(opentelemetry_resources opentelemetry_common) + +target_include_directories( + opentelemetry_resources + PUBLIC "$") + +install( + TARGETS opentelemetry_resources + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/sdk/src/resource/resource.cc b/sdk/src/resource/resource.cc new file mode 100644 index 0000000000..7df4b6a668 --- /dev/null +++ b/sdk/src/resource/resource.cc @@ -0,0 +1,60 @@ +#include "opentelemetry/sdk/resource/resource.h" +#include "opentelemetry/nostd/span.h" +#include "opentelemetry/sdk/resource/resource_detector.h" +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace resource +{ + +const std::string kTelemetrySdkLanguage = "telemetry.sdk.language"; +const std::string kTelemetrySdkName = "telemetry.sdk.name"; +const std::string kTelemetrySdkVersion = "telemetry.sdk.version"; + +Resource::Resource(const ResourceAttributes &attributes) noexcept : attributes_(attributes) {} + +Resource Resource::Merge(const Resource &other) noexcept +{ + ResourceAttributes merged_resource_attributes(other.attributes_); + merged_resource_attributes.insert(attributes_.begin(), attributes_.end()); + return Resource(merged_resource_attributes); +} + +Resource Resource::Create(const ResourceAttributes &attributes) +{ + static auto otel_resource = OTELResourceDetector().Detect(); + auto default_resource = Resource::GetDefault(); + + if (attributes.size() > 0) + { + Resource tmp_resource(attributes); + auto merged_resource = tmp_resource.Merge(default_resource); + return merged_resource.Merge(otel_resource); + } + return default_resource.Merge(otel_resource); +} + +Resource &Resource::GetEmpty() +{ + static Resource empty_resource; + return empty_resource; +} + +Resource &Resource::GetDefault() +{ + static Resource default_resource({{kTelemetrySdkLanguage, "cpp"}, + {kTelemetrySdkName, "opentelemetry"}, + {kTelemetrySdkVersion, OPENTELEMETRY_SDK_VERSION}}); + return default_resource; +} + +const ResourceAttributes &Resource::GetAttributes() const noexcept +{ + return attributes_; +} + +} // namespace resource +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/src/resource/resource_detector.cc b/sdk/src/resource/resource_detector.cc new file mode 100644 index 0000000000..1f52680b14 --- /dev/null +++ b/sdk/src/resource/resource_detector.cc @@ -0,0 +1,34 @@ +#include "opentelemetry/sdk/resource/resource_detector.h" +#include +#include "opentelemetry/sdk/resource/resource.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace resource +{ + +const char *OTEL_RESOURCE_ATTRIBUTES = "OTEL_RESOURCE_ATTRIBUTES"; + +Resource OTELResourceDetector::Detect() noexcept +{ + char *attributes_str = std::getenv(OTEL_RESOURCE_ATTRIBUTES); + if (attributes_str == nullptr) + return Resource(); + // return Resource::GetEmpty(); + ResourceAttributes attributes; + std::istringstream iss(attributes_str); + std::string token; + while (std::getline(iss, token, ',')) + { + size_t pos = token.find('='); + std::string key = token.substr(0, pos); + std::string value = token.substr(pos + 1); + attributes[key] = value; + } + return Resource(attributes); +} + +} // namespace resource +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/src/trace/BUILD b/sdk/src/trace/BUILD index 221066076b..34ec5108d2 100644 --- a/sdk/src/trace/BUILD +++ b/sdk/src/trace/BUILD @@ -23,5 +23,6 @@ cc_library( "//api", "//sdk:headers", "//sdk/src/common:random", + "//sdk/src/resource", ], ) diff --git a/sdk/src/trace/CMakeLists.txt b/sdk/src/trace/CMakeLists.txt index 2ae5ef7bb6..d4ff82f63e 100644 --- a/sdk/src/trace/CMakeLists.txt +++ b/sdk/src/trace/CMakeLists.txt @@ -5,7 +5,8 @@ add_library( set_target_properties(opentelemetry_trace PROPERTIES EXPORT_NAME trace) -target_link_libraries(opentelemetry_trace PUBLIC opentelemetry_common) +target_link_libraries(opentelemetry_trace PUBLIC opentelemetry_common + opentelemetry_resources) target_include_directories( opentelemetry_trace diff --git a/sdk/src/trace/span.cc b/sdk/src/trace/span.cc index a9b1851c5c..e37f3bc40a 100644 --- a/sdk/src/trace/span.cc +++ b/sdk/src/trace/span.cc @@ -63,7 +63,8 @@ Span::Span(std::shared_ptr &&tracer, const opentelemetry::common::KeyValueIterable &attributes, const trace_api::SpanContextKeyValueIterable &links, const trace_api::StartSpanOptions &options, - const trace_api::SpanContext &parent_span_context) noexcept + const trace_api::SpanContext &parent_span_context, + const opentelemetry::sdk::resource::Resource &resource) noexcept : tracer_{std::move(tracer)}, processor_{processor}, recordable_{processor_->MakeRecordable()}, @@ -108,6 +109,7 @@ Span::Span(std::shared_ptr &&tracer, recordable_->SetSpanKind(options.kind); recordable_->SetStartTime(NowOr(options.start_system_time)); start_steady_time = NowOr(options.start_steady_time); + // recordable_->SetResource(resource_); TODO processor_->OnStart(*recordable_); } diff --git a/sdk/src/trace/span.h b/sdk/src/trace/span.h index d4499985fb..d42e9f61ff 100644 --- a/sdk/src/trace/span.h +++ b/sdk/src/trace/span.h @@ -21,12 +21,14 @@ class Span final : public trace_api::Span const opentelemetry::common::KeyValueIterable &attributes, const trace_api::SpanContextKeyValueIterable &links, const trace_api::StartSpanOptions &options, - const trace_api::SpanContext &parent_span_context) noexcept; + const trace_api::SpanContext &parent_span_context, + const opentelemetry::sdk::resource::Resource &resource) noexcept; ~Span() override; // trace_api::Span - void SetAttribute(nostd::string_view key, const common::AttributeValue &value) noexcept override; + void SetAttribute(nostd::string_view key, + const opentelemetry::common::AttributeValue &value) noexcept override; void AddEvent(nostd::string_view name) noexcept override; diff --git a/sdk/src/trace/tracer.cc b/sdk/src/trace/tracer.cc index 5bfac6bc55..27e3aad58c 100644 --- a/sdk/src/trace/tracer.cc +++ b/sdk/src/trace/tracer.cc @@ -10,8 +10,10 @@ namespace sdk { namespace trace { -Tracer::Tracer(std::shared_ptr processor, std::shared_ptr sampler) noexcept - : processor_{processor}, sampler_{sampler} +Tracer::Tracer(std::shared_ptr processor, + const opentelemetry::sdk::resource::Resource &resource, + std::shared_ptr sampler) noexcept + : processor_{processor}, sampler_{sampler}, resource_{resource} {} void Tracer::SetProcessor(std::shared_ptr processor) noexcept @@ -71,8 +73,9 @@ nostd::shared_ptr Tracer::StartSpan( } else { - auto span = nostd::shared_ptr{new (std::nothrow) Span{ - this->shared_from_this(), processor_.load(), name, attributes, links, options, parent}}; + auto span = nostd::shared_ptr{ + new (std::nothrow) Span{this->shared_from_this(), processor_.load(), name, attributes, + links, options, parent, resource_}}; // if the attributes is not nullptr, add attributes to the span. if (sampling_result.attributes) diff --git a/sdk/src/trace/tracer_provider.cc b/sdk/src/trace/tracer_provider.cc index 4040ea0226..b37ae5de56 100644 --- a/sdk/src/trace/tracer_provider.cc +++ b/sdk/src/trace/tracer_provider.cc @@ -6,8 +6,12 @@ namespace sdk namespace trace { TracerProvider::TracerProvider(std::shared_ptr processor, + opentelemetry::sdk::resource::Resource &&resource, std::shared_ptr sampler) noexcept - : processor_{processor}, tracer_(new Tracer(std::move(processor), sampler)), sampler_(sampler) + : processor_{processor}, + tracer_(new Tracer(std::move(processor), resource, sampler)), + sampler_(sampler), + resource_(resource) {} opentelemetry::nostd::shared_ptr TracerProvider::GetTracer( @@ -35,6 +39,11 @@ std::shared_ptr TracerProvider::GetSampler() const noexcept return sampler_; } +const opentelemetry::sdk::resource::Resource &TracerProvider::GetResource() const noexcept +{ + return resource_; +} + bool TracerProvider::Shutdown() noexcept { return GetProcessor()->Shutdown(); diff --git a/sdk/test/CMakeLists.txt b/sdk/test/CMakeLists.txt index 633f9c3465..eae1209f46 100644 --- a/sdk/test/CMakeLists.txt +++ b/sdk/test/CMakeLists.txt @@ -2,3 +2,4 @@ add_subdirectory(common) add_subdirectory(trace) add_subdirectory(metrics) add_subdirectory(logs) +add_subdirectory(resource) diff --git a/sdk/test/resource/BUILD b/sdk/test/resource/BUILD new file mode 100644 index 0000000000..a3b7b55b9b --- /dev/null +++ b/sdk/test/resource/BUILD @@ -0,0 +1,11 @@ +cc_test( + name = "resource_test", + srcs = [ + "resource_test.cc", + ], + deps = [ + "//api", + "//sdk/src/resource", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/sdk/test/resource/CMakeLists.txt b/sdk/test/resource/CMakeLists.txt new file mode 100644 index 0000000000..514b98680b --- /dev/null +++ b/sdk/test/resource/CMakeLists.txt @@ -0,0 +1,9 @@ +foreach(testname resource_test) + add_executable(${testname} "${testname}.cc") + target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} opentelemetry_resources) + gtest_add_tests( + TARGET ${testname} + TEST_PREFIX resources. + TEST_LIST ${testname}) +endforeach() diff --git a/sdk/test/resource/resource_test.cc b/sdk/test/resource/resource_test.cc new file mode 100644 index 0000000000..1a565128e0 --- /dev/null +++ b/sdk/test/resource/resource_test.cc @@ -0,0 +1,135 @@ +#include "opentelemetry/sdk/resource/resource.h" +#include "opentelemetry/common/key_value_iterable_view.h" +#include "opentelemetry/nostd/string_view.h" +#include "opentelemetry/sdk/common/attribute_utils.h" +#include "opentelemetry/sdk/resource/resource_detector.h" + +#include +#include +#include + +#include + +class TestResource : public opentelemetry::sdk::resource::Resource +{ +public: + TestResource(opentelemetry::sdk::resource::ResourceAttributes attributes = + opentelemetry::sdk::resource::ResourceAttributes()) + : Resource(attributes) + {} +}; + +TEST(ResourceTest, create) +{ + + opentelemetry::sdk::resource::ResourceAttributes expected_attributes = { + {"service", "backend"}, + {"version", (uint32_t)1}, + {"cost", 234.23}, + {"telemetry.sdk.language", "cpp"}, + {"telemetry.sdk.name", "opentelemetry"}, + {"telemetry.sdk.version", OPENTELEMETRY_SDK_VERSION}}; + + opentelemetry::sdk::resource::ResourceAttributes attributes = { + {"service", "backend"}, {"version", (uint32_t)1}, {"cost", 234.23}}; + auto resource2 = opentelemetry::sdk::resource::Resource::Create(attributes); + auto received_attributes2 = resource2.GetAttributes(); + for (auto &e : received_attributes2) + { + + EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end()); + if (expected_attributes.find(e.first) != expected_attributes.end()) + if (e.first == "version") + EXPECT_EQ(opentelemetry::nostd::get(expected_attributes.find(e.first)->second), + opentelemetry::nostd::get(e.second)); + else if (e.first == "cost") + EXPECT_EQ(opentelemetry::nostd::get(expected_attributes.find(e.first)->second), + opentelemetry::nostd::get(e.second)); + else + EXPECT_EQ(opentelemetry::nostd::get(expected_attributes.find(e.first)->second), + opentelemetry::nostd::get(e.second)); + } + EXPECT_EQ(received_attributes2.size(), expected_attributes.size()); +} + +TEST(ResourceTest, Merge) +{ + TestResource resource1( + opentelemetry::sdk::resource::ResourceAttributes({{"service", "backend"}})); + TestResource resource2( + opentelemetry::sdk::resource::ResourceAttributes({{"host", "service-host"}})); + std::map expected_attributes = {{"service", "backend"}, + {"host", "service-host"}}; + + auto merged_resource = resource1.Merge(resource2); + auto received_attributes = merged_resource.GetAttributes(); + for (auto &e : received_attributes) + { + EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end()); + if (expected_attributes.find(e.first) != expected_attributes.end()) + EXPECT_EQ(expected_attributes.find(e.first)->second, + opentelemetry::nostd::get(e.second)); + } + EXPECT_EQ(received_attributes.size(), expected_attributes.size()); +} +TEST(ResourceTest, MergeEmptyString) +{ + TestResource resource1({{"service", "backend"}, {"host", "service-host"}}); + TestResource resource2({{"service", ""}, {"host", "another-service-host"}}); + std::map expected_attributes = {{"service", ""}, + {"host", "another-service-host"}}; + + auto merged_resource = resource1.Merge(resource2); + auto received_attributes = merged_resource.GetAttributes(); + + for (auto &e : received_attributes) + { + EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end()); + if (expected_attributes.find(e.first) != expected_attributes.end()) + EXPECT_EQ(expected_attributes.find(e.first)->second, + opentelemetry::nostd::get(e.second)); + } + EXPECT_EQ(received_attributes.size(), expected_attributes.size()); +} + +// this test uses putenv to set the env variable - this is not available on windows +#ifdef __linux__ + +TEST(ResourceTest, OtelResourceDetector) +{ + std::map expected_attributes = {{"k", "v"}}; + + char env[] = "OTEL_RESOURCE_ATTRIBUTES=k=v"; + putenv(env); + + opentelemetry::sdk::resource::OTELResourceDetector detector; + auto resource = detector.Detect(); + auto received_attributes = resource.GetAttributes(); + for (auto &e : received_attributes) + { + EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end()); + if (expected_attributes.find(e.first) != expected_attributes.end()) + EXPECT_EQ(expected_attributes.find(e.first)->second, + opentelemetry::nostd::get(e.second)); + } + EXPECT_EQ(received_attributes.size(), expected_attributes.size()); + unsetenv("OTEL_RESOURCE_ATTRIBUTES"); +} + +TEST(ResourceTest, OtelResourceDetectorEmptyEnv) +{ + std::map expected_attributes = {}; + unsetenv("OTEL_RESOURCE_ATTRIBUTES"); + opentelemetry::sdk::resource::OTELResourceDetector detector; + auto resource = detector.Detect(); + auto received_attributes = resource.GetAttributes(); + for (auto &e : received_attributes) + { + EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end()); + if (expected_attributes.find(e.first) != expected_attributes.end()) + EXPECT_EQ(expected_attributes.find(e.first)->second, + opentelemetry::nostd::get(e.second)); + } + EXPECT_EQ(received_attributes.size(), expected_attributes.size()); +} +#endif // __linux__ \ No newline at end of file diff --git a/sdk/test/trace/BUILD b/sdk/test/trace/BUILD index 7322697e39..8f71385885 100644 --- a/sdk/test/trace/BUILD +++ b/sdk/test/trace/BUILD @@ -6,6 +6,7 @@ cc_test( "tracer_provider_test.cc", ], deps = [ + "//sdk/src/resource", "//sdk/src/trace", "@com_google_googletest//:gtest_main", ], @@ -52,6 +53,7 @@ cc_test( ], deps = [ "//exporters/memory:in_memory_span_exporter", + "//sdk/src/resource", "//sdk/src/trace", "@com_google_googletest//:gtest_main", ], @@ -107,6 +109,7 @@ otel_cc_benchmark( srcs = ["sampler_benchmark.cc"], deps = [ "//exporters/memory:in_memory_span_exporter", + "//sdk/src/resource", "//sdk/src/trace", ], ) diff --git a/sdk/test/trace/CMakeLists.txt b/sdk/test/trace/CMakeLists.txt index 0ba567a102..8a39c10a29 100644 --- a/sdk/test/trace/CMakeLists.txt +++ b/sdk/test/trace/CMakeLists.txt @@ -17,6 +17,7 @@ foreach( ${CMAKE_THREAD_LIBS_INIT} opentelemetry_common opentelemetry_trace + opentelemetry_resources opentelemetry_exporter_in_memory) gtest_add_tests( TARGET ${testname} @@ -26,5 +27,10 @@ endforeach() add_executable(sampler_benchmark sampler_benchmark.cc) target_link_libraries( - sampler_benchmark benchmark::benchmark ${CMAKE_THREAD_LIBS_INIT} - ${CORE_RUNTIME_LIBS} opentelemetry_trace opentelemetry_exporter_in_memory) + sampler_benchmark + benchmark::benchmark + ${CMAKE_THREAD_LIBS_INIT} + ${CORE_RUNTIME_LIBS} + opentelemetry_trace + opentelemetry_resources + opentelemetry_exporter_in_memory) diff --git a/sdk/test/trace/sampler_benchmark.cc b/sdk/test/trace/sampler_benchmark.cc index 4d31d0f43f..5606206ce6 100644 --- a/sdk/test/trace/sampler_benchmark.cc +++ b/sdk/test/trace/sampler_benchmark.cc @@ -1,4 +1,5 @@ #include "opentelemetry/exporters/memory/in_memory_span_exporter.h" +#include "opentelemetry/sdk/resource/resource.h" #include "opentelemetry/sdk/trace/sampler.h" #include "opentelemetry/sdk/trace/samplers/always_off.h" #include "opentelemetry/sdk/trace/samplers/always_on.h" @@ -118,7 +119,9 @@ void BenchmarkSpanCreation(std::shared_ptr sampler, benchmark::State &s { std::unique_ptr exporter(new InMemorySpanExporter()); auto processor = std::make_shared(std::move(exporter)); - auto tracer = std::shared_ptr(new Tracer(processor, sampler)); + auto resource = opentelemetry::sdk::resource::Resource::Create({}); + auto tracer = + std::shared_ptr(new Tracer(processor, resource, sampler)); while (state.KeepRunning()) { diff --git a/sdk/test/trace/tracer_provider_test.cc b/sdk/test/trace/tracer_provider_test.cc index 6226a16d3c..47c7ccc827 100644 --- a/sdk/test/trace/tracer_provider_test.cc +++ b/sdk/test/trace/tracer_provider_test.cc @@ -1,4 +1,5 @@ #include "opentelemetry/sdk/trace/tracer_provider.h" +#include "opentelemetry/sdk/resource/resource.h" #include "opentelemetry/sdk/trace/samplers/always_off.h" #include "opentelemetry/sdk/trace/samplers/always_on.h" #include "opentelemetry/sdk/trace/simple_processor.h" @@ -7,12 +8,13 @@ #include using namespace opentelemetry::sdk::trace; +using namespace opentelemetry::sdk::resource; TEST(TracerProvider, GetTracer) { std::shared_ptr processor(new SimpleSpanProcessor(nullptr)); - TracerProvider tp1(processor); + TracerProvider tp1(processor, Resource::Create({})); auto t1 = tp1.GetTracer("test"); auto t2 = tp1.GetTracer("test"); auto t3 = tp1.GetTracer("different", "1.0.0"); @@ -30,7 +32,7 @@ TEST(TracerProvider, GetTracer) ASSERT_EQ(processor, sdkTracer1->GetProcessor()); ASSERT_EQ("AlwaysOnSampler", sdkTracer1->GetSampler()->GetDescription()); - TracerProvider tp2(processor, std::make_shared()); + TracerProvider tp2(processor, Resource::Create({}), std::make_shared()); auto sdkTracer2 = dynamic_cast(tp2.GetTracer("test").get()); ASSERT_EQ("AlwaysOffSampler", sdkTracer2->GetSampler()->GetDescription()); } @@ -54,7 +56,7 @@ TEST(TracerProvider, GetSampler) // Create a TracerProvicer with a custom AlwaysOffSampler. std::shared_ptr processor2(new SimpleSpanProcessor(nullptr)); - TracerProvider tp2(processor2, std::make_shared()); + TracerProvider tp2(processor2, Resource::Create({}), std::make_shared()); auto t3 = tp2.GetSampler(); ASSERT_EQ("AlwaysOffSampler", t3->GetDescription()); diff --git a/sdk/test/trace/tracer_test.cc b/sdk/test/trace/tracer_test.cc index 45a5bfc020..d244ef2528 100644 --- a/sdk/test/trace/tracer_test.cc +++ b/sdk/test/trace/tracer_test.cc @@ -1,5 +1,6 @@ #include "opentelemetry/sdk/trace/tracer.h" #include "opentelemetry/exporters/memory/in_memory_span_exporter.h" +#include "opentelemetry/sdk/resource/resource.h" #include "opentelemetry/sdk/trace/samplers/always_off.h" #include "opentelemetry/sdk/trace/samplers/always_on.h" #include "opentelemetry/sdk/trace/samplers/parent.h" @@ -9,6 +10,7 @@ #include using namespace opentelemetry::sdk::trace; +using namespace opentelemetry::sdk::resource; using opentelemetry::core::SteadyTimestamp; using opentelemetry::core::SystemTimestamp; namespace nostd = opentelemetry::nostd; @@ -49,7 +51,8 @@ std::shared_ptr initTracer( std::unique_ptr &&exporter) { auto processor = std::make_shared(std::move(exporter)); - return std::shared_ptr(new Tracer(processor)); + auto resource = Resource::Create({}); + return std::shared_ptr(new Tracer(processor, resource)); } std::shared_ptr initTracer( @@ -57,7 +60,9 @@ std::shared_ptr initTracer( std::shared_ptr sampler) { auto processor = std::make_shared(std::move(exporter)); - return std::shared_ptr(new Tracer(processor, sampler)); + auto resource = Resource::Create({}); + + return std::shared_ptr(new Tracer(processor, resource, sampler)); } } // namespace @@ -275,9 +280,10 @@ TEST(Tracer, StartSpanWithAttributesCopy) TEST(Tracer, GetSampler) { + auto resource = Resource::Create({}); // Create a Tracer with a default AlwaysOnSampler std::shared_ptr processor_1(new SimpleSpanProcessor(nullptr)); - std::shared_ptr tracer_on(new Tracer(std::move(processor_1))); + std::shared_ptr tracer_on(new Tracer(std::move(processor_1), resource)); auto t1 = tracer_on->GetSampler(); ASSERT_EQ("AlwaysOnSampler", t1->GetDescription()); @@ -285,7 +291,7 @@ TEST(Tracer, GetSampler) // Create a Tracer with a AlwaysOffSampler std::shared_ptr processor_2(new SimpleSpanProcessor(nullptr)); std::shared_ptr tracer_off( - new Tracer(std::move(processor_2), std::make_shared())); + new Tracer(std::move(processor_2), resource, std::make_shared())); auto t2 = tracer_off->GetSampler(); ASSERT_EQ("AlwaysOffSampler", t2->GetDescription());