diff --git a/api/include/opentelemetry/_metrics/provider.h b/api/include/opentelemetry/_metrics/provider.h index e079b34d5f..3604bf6d8c 100644 --- a/api/include/opentelemetry/_metrics/provider.h +++ b/api/include/opentelemetry/_metrics/provider.h @@ -7,12 +7,28 @@ # include "opentelemetry/_metrics/meter_provider.h" # include "opentelemetry/_metrics/noop.h" +# include "opentelemetry/common/macros.h" # include "opentelemetry/common/spin_lock_mutex.h" # include "opentelemetry/nostd/shared_ptr.h" OPENTELEMETRY_BEGIN_NAMESPACE namespace metrics { + +class ProviderSingleton +{ +public: + ProviderSingleton() : lock(), provider(new NoopMeterProvider()) {} + + common::SpinLockMutex lock; + nostd::shared_ptr provider; + + ProviderSingleton(const ProviderSingleton &) = delete; + ProviderSingleton &operator=(const ProviderSingleton &) = delete; + ProviderSingleton(ProviderSingleton &&) = delete; + ProviderSingleton &operator=(ProviderSingleton &&) = delete; +}; + /** * Stores the singleton global MeterProvider. */ @@ -27,8 +43,9 @@ class Provider */ static nostd::shared_ptr GetMeterProvider() noexcept { - std::lock_guard guard(GetLock()); - return nostd::shared_ptr(GetProvider()); + std::lock_guard guard(s.lock); + nostd::shared_ptr result(s.provider); + return result; } /** @@ -36,24 +53,16 @@ class Provider */ static void SetMeterProvider(nostd::shared_ptr tp) noexcept { - std::lock_guard guard(GetLock()); - GetProvider() = tp; + std::lock_guard guard(s.lock); + s.provider = tp; } private: - static nostd::shared_ptr &GetProvider() noexcept - { - static nostd::shared_ptr provider(new NoopMeterProvider); - return provider; - } - - static common::SpinLockMutex &GetLock() noexcept - { - static common::SpinLockMutex lock; - return lock; - } + OPENTELEMETRY_DECLARE_API_SINGLETON static ProviderSingleton s; }; +OPENTELEMETRY_DEFINE_API_SINGLETON ProviderSingleton Provider::s; + } // namespace metrics OPENTELEMETRY_END_NAMESPACE #endif diff --git a/api/include/opentelemetry/baggage/baggage.h b/api/include/opentelemetry/baggage/baggage.h index eb5e4dcc7c..a36fd9bd91 100644 --- a/api/include/opentelemetry/baggage/baggage.h +++ b/api/include/opentelemetry/baggage/baggage.h @@ -6,6 +6,7 @@ #include #include "opentelemetry/common/kv_properties.h" +#include "opentelemetry/common/macros.h" #include "opentelemetry/nostd/shared_ptr.h" #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/version.h" @@ -34,11 +35,7 @@ class Baggage : kv_properties_(new opentelemetry::common::KeyValueProperties(keys_and_values)) {} - static nostd::shared_ptr GetDefault() - { - static nostd::shared_ptr baggage{new Baggage()}; - return baggage; - } + static nostd::shared_ptr GetDefault() { return default_baggage; } /* Get value for key in the baggage @returns true if key is found, false otherwise @@ -292,8 +289,13 @@ class Baggage private: // Store entries in a C-style array to avoid using std::array or std::vector. nostd::unique_ptr kv_properties_; + + OPENTELEMETRY_DECLARE_API_SINGLETON static nostd::shared_ptr default_baggage; }; +OPENTELEMETRY_DEFINE_API_SINGLETON nostd::shared_ptr Baggage::default_baggage( + new Baggage()); + } // namespace baggage OPENTELEMETRY_END_NAMESPACE diff --git a/api/include/opentelemetry/common/macros.h b/api/include/opentelemetry/common/macros.h index 204c1ed04e..68abafc5f7 100644 --- a/api/include/opentelemetry/common/macros.h +++ b/api/include/opentelemetry/common/macros.h @@ -89,3 +89,31 @@ #else # define OPENTELEMETRY_DEPRECATED_MESSAGE(msg) #endif + +/** + @def OPENTELEMETRY_DECLARE_API_SINGLETON + Declare a weak symbol with visibility default. +*/ +#if defined(__clang__) +# define OPENTELEMETRY_DECLARE_API_SINGLETON __attribute__((visibility("default"), weak)) +#elif defined(__GNUC__) +# define OPENTELEMETRY_DECLARE_API_SINGLETON __attribute__((visibility("default"), weak)) +#elif defined(_MSC_VER) +# define OPENTELEMETRY_DECLARE_API_SINGLETON +#else +# define OPENTELEMETRY_DECLARE_API_SINGLETON +#endif + +/** + @def OPENTELEMETRY_DEFINE_API_SINGLETON + Define a weak symbol with visibility default. +*/ +#if defined(__clang__) +# define OPENTELEMETRY_DEFINE_API_SINGLETON __attribute__((visibility("default"), weak)) +#elif defined(__GNUC__) +# define OPENTELEMETRY_DEFINE_API_SINGLETON __attribute__((visibility("default"), weak)) +#elif defined(_MSC_VER) +# define OPENTELEMETRY_DEFINE_API_SINGLETON __declspec(selectany) +#else +# define OPENTELEMETRY_DEFINE_API_SINGLETON +#endif diff --git a/api/include/opentelemetry/context/propagation/global_propagator.h b/api/include/opentelemetry/context/propagation/global_propagator.h index b4e49325cd..690ccaad97 100644 --- a/api/include/opentelemetry/context/propagation/global_propagator.h +++ b/api/include/opentelemetry/context/propagation/global_propagator.h @@ -8,6 +8,7 @@ #include "opentelemetry/context/propagation/noop_propagator.h" #include "opentelemetry/context/propagation/text_map_propagator.h" +#include "opentelemetry/common/macros.h" #include "opentelemetry/common/spin_lock_mutex.h" #include "opentelemetry/nostd/shared_ptr.h" @@ -19,37 +20,45 @@ namespace context namespace propagation { -/* Stores the singleton TextMapPropagator */ +class PropagatorSingleton +{ +public: + PropagatorSingleton() : lock(), propagator(new NoOpPropagator()) {} + + common::SpinLockMutex lock; + nostd::shared_ptr propagator; + PropagatorSingleton(const PropagatorSingleton &) = delete; + PropagatorSingleton &operator=(const PropagatorSingleton &) = delete; + PropagatorSingleton(PropagatorSingleton &&) = delete; + PropagatorSingleton &operator=(PropagatorSingleton &&) = delete; +}; + +/** + * Stores the singleton TextMapPropagator. + */ class GlobalTextMapPropagator { public: static nostd::shared_ptr GetGlobalPropagator() noexcept { - std::lock_guard guard(GetLock()); - return nostd::shared_ptr(GetPropagator()); + std::lock_guard guard(s.lock); + nostd::shared_ptr result(s.propagator); + return result; } static void SetGlobalPropagator(nostd::shared_ptr prop) noexcept { - std::lock_guard guard(GetLock()); - GetPropagator() = prop; + std::lock_guard guard(s.lock); + s.propagator = prop; } private: - static nostd::shared_ptr &GetPropagator() noexcept - { - static nostd::shared_ptr propagator(new NoOpPropagator()); - return propagator; - } - - static common::SpinLockMutex &GetLock() noexcept - { - static common::SpinLockMutex lock; - return lock; - } + OPENTELEMETRY_DECLARE_API_SINGLETON static PropagatorSingleton s; }; +OPENTELEMETRY_DEFINE_API_SINGLETON PropagatorSingleton GlobalTextMapPropagator::s; + } // namespace propagation } // namespace context -OPENTELEMETRY_END_NAMESPACE \ No newline at end of file +OPENTELEMETRY_END_NAMESPACE diff --git a/api/include/opentelemetry/context/runtime_context.h b/api/include/opentelemetry/context/runtime_context.h index 167a928f10..cb89344e5a 100644 --- a/api/include/opentelemetry/context/runtime_context.h +++ b/api/include/opentelemetry/context/runtime_context.h @@ -3,6 +3,7 @@ #pragma once +#include "opentelemetry/common/macros.h" #include "opentelemetry/context/context.h" OPENTELEMETRY_BEGIN_NAMESPACE @@ -17,7 +18,7 @@ class Token public: bool operator==(const Context &other) const noexcept { return context_ == other; } - ~Token(); + ~Token() noexcept; private: friend class RuntimeContextStorage; @@ -74,6 +75,19 @@ class RuntimeContextStorage */ static RuntimeContextStorage *GetDefaultStorage() noexcept; +class RuntimeContextSingleton +{ +public: + RuntimeContextSingleton() : context_storage(GetDefaultStorage()) {} + + nostd::shared_ptr context_storage; + + RuntimeContextSingleton(const RuntimeContextSingleton &) = delete; + RuntimeContextSingleton &operator=(const RuntimeContextSingleton &) = delete; + RuntimeContextSingleton(RuntimeContextSingleton &&) = delete; + RuntimeContextSingleton &operator=(RuntimeContextSingleton &&) = delete; +}; + // Provides a wrapper for propagating the context object globally. // // By default, a thread-local runtime context storage is used. @@ -145,7 +159,7 @@ class RuntimeContext */ static void SetRuntimeContextStorage(nostd::shared_ptr storage) noexcept { - GetStorage() = storage; + s.context_storage = storage; } /** @@ -163,16 +177,14 @@ class RuntimeContext private: static nostd::shared_ptr GetRuntimeContextStorage() noexcept { - return GetStorage(); + return s.context_storage; } - static nostd::shared_ptr &GetStorage() noexcept - { - static nostd::shared_ptr context(GetDefaultStorage()); - return context; - } + OPENTELEMETRY_DECLARE_API_SINGLETON static RuntimeContextSingleton s; }; +OPENTELEMETRY_DEFINE_API_SINGLETON RuntimeContextSingleton RuntimeContext::s; + inline Token::~Token() noexcept { context::RuntimeContext::Detach(*this); diff --git a/api/include/opentelemetry/logs/provider.h b/api/include/opentelemetry/logs/provider.h index 38186bbe75..c75d6697e3 100644 --- a/api/include/opentelemetry/logs/provider.h +++ b/api/include/opentelemetry/logs/provider.h @@ -6,6 +6,7 @@ # include +# include "opentelemetry/common/macros.h" # include "opentelemetry/common/spin_lock_mutex.h" # include "opentelemetry/logs/logger_provider.h" # include "opentelemetry/logs/noop.h" @@ -14,6 +15,21 @@ OPENTELEMETRY_BEGIN_NAMESPACE namespace logs { + +class ProviderSingleton +{ +public: + ProviderSingleton() : lock(), provider(new NoopLoggerProvider()) {} + + common::SpinLockMutex lock; + nostd::shared_ptr provider; + + ProviderSingleton(const ProviderSingleton &) = delete; + ProviderSingleton &operator=(const ProviderSingleton &) = delete; + ProviderSingleton(ProviderSingleton &&) = delete; + ProviderSingleton &operator=(ProviderSingleton &&) = delete; +}; + /** * Stores the singleton global LoggerProvider. */ @@ -28,8 +44,9 @@ class Provider */ static nostd::shared_ptr GetLoggerProvider() noexcept { - std::lock_guard guard(GetLock()); - return nostd::shared_ptr(GetProvider()); + std::lock_guard guard(s.lock); + nostd::shared_ptr result(s.provider); + return result; } /** @@ -37,24 +54,16 @@ class Provider */ static void SetLoggerProvider(nostd::shared_ptr tp) noexcept { - std::lock_guard guard(GetLock()); - GetProvider() = tp; + std::lock_guard guard(s.lock); + s.provider = tp; } private: - static nostd::shared_ptr &GetProvider() noexcept - { - static nostd::shared_ptr provider(new NoopLoggerProvider); - return provider; - } - - static common::SpinLockMutex &GetLock() noexcept - { - static common::SpinLockMutex lock; - return lock; - } + OPENTELEMETRY_DECLARE_API_SINGLETON static ProviderSingleton s; }; +OPENTELEMETRY_DEFINE_API_SINGLETON ProviderSingleton Provider::s; + } // namespace logs OPENTELEMETRY_END_NAMESPACE #endif diff --git a/api/include/opentelemetry/metrics/provider.h b/api/include/opentelemetry/metrics/provider.h index 3bacac9760..3ec9e08fa9 100644 --- a/api/include/opentelemetry/metrics/provider.h +++ b/api/include/opentelemetry/metrics/provider.h @@ -6,6 +6,7 @@ # include +# include "opentelemetry/common/macros.h" # include "opentelemetry/common/spin_lock_mutex.h" # include "opentelemetry/metrics/meter_provider.h" # include "opentelemetry/metrics/noop.h" @@ -14,6 +15,21 @@ OPENTELEMETRY_BEGIN_NAMESPACE namespace metrics { + +class ProviderSingleton +{ +public: + ProviderSingleton() : lock(), provider(new NoopMeterProvider()) {} + + common::SpinLockMutex lock; + nostd::shared_ptr provider; + + ProviderSingleton(const ProviderSingleton &) = delete; + ProviderSingleton &operator=(const ProviderSingleton &) = delete; + ProviderSingleton(ProviderSingleton &&) = delete; + ProviderSingleton &operator=(ProviderSingleton &&) = delete; +}; + /** * Stores the singleton global MeterProvider. */ @@ -28,8 +44,9 @@ class Provider */ static nostd::shared_ptr GetMeterProvider() noexcept { - std::lock_guard guard(GetLock()); - return nostd::shared_ptr(GetProvider()); + std::lock_guard guard(s.lock); + nostd::shared_ptr result(s.provider); + return result; } /** @@ -37,24 +54,16 @@ class Provider */ static void SetMeterProvider(nostd::shared_ptr tp) noexcept { - std::lock_guard guard(GetLock()); - GetProvider() = tp; + std::lock_guard guard(s.lock); + s.provider = tp; } private: - static nostd::shared_ptr &GetProvider() noexcept - { - static nostd::shared_ptr provider(new NoopMeterProvider); - return provider; - } - - static common::SpinLockMutex &GetLock() noexcept - { - static common::SpinLockMutex lock; - return lock; - } + OPENTELEMETRY_DECLARE_API_SINGLETON static ProviderSingleton s; }; +OPENTELEMETRY_DEFINE_API_SINGLETON ProviderSingleton Provider::s; + } // namespace metrics OPENTELEMETRY_END_NAMESPACE -#endif \ No newline at end of file +#endif diff --git a/api/include/opentelemetry/trace/provider.h b/api/include/opentelemetry/trace/provider.h index 6267cbd4d2..7c1311df02 100644 --- a/api/include/opentelemetry/trace/provider.h +++ b/api/include/opentelemetry/trace/provider.h @@ -5,6 +5,7 @@ #include +#include "opentelemetry/common/macros.h" #include "opentelemetry/common/spin_lock_mutex.h" #include "opentelemetry/nostd/shared_ptr.h" #include "opentelemetry/trace/noop.h" @@ -13,6 +14,21 @@ OPENTELEMETRY_BEGIN_NAMESPACE namespace trace { + +class ProviderSingleton +{ +public: + ProviderSingleton() : lock(), provider(new NoopTracerProvider()) {} + + common::SpinLockMutex lock; + nostd::shared_ptr provider; + + ProviderSingleton(const ProviderSingleton &) = delete; + ProviderSingleton &operator=(const ProviderSingleton &) = delete; + ProviderSingleton(ProviderSingleton &&) = delete; + ProviderSingleton &operator=(ProviderSingleton &&) = delete; +}; + /** * Stores the singleton global TracerProvider. */ @@ -27,8 +43,9 @@ class Provider */ static nostd::shared_ptr GetTracerProvider() noexcept { - std::lock_guard guard(GetLock()); - return nostd::shared_ptr(GetProvider()); + std::lock_guard guard(s.lock); + nostd::shared_ptr result(s.provider); + return result; } /** @@ -36,23 +53,15 @@ class Provider */ static void SetTracerProvider(nostd::shared_ptr tp) noexcept { - std::lock_guard guard(GetLock()); - GetProvider() = tp; + std::lock_guard guard(s.lock); + s.provider = tp; } private: - static nostd::shared_ptr &GetProvider() noexcept - { - static nostd::shared_ptr provider(new NoopTracerProvider); - return provider; - } - - static common::SpinLockMutex &GetLock() noexcept - { - static common::SpinLockMutex lock; - return lock; - } + OPENTELEMETRY_DECLARE_API_SINGLETON static ProviderSingleton s; }; +OPENTELEMETRY_DEFINE_API_SINGLETON ProviderSingleton Provider::s; + } // namespace trace OPENTELEMETRY_END_NAMESPACE diff --git a/api/include/opentelemetry/trace/trace_state.h b/api/include/opentelemetry/trace/trace_state.h index 0343637cfa..e4ce9cba67 100644 --- a/api/include/opentelemetry/trace/trace_state.h +++ b/api/include/opentelemetry/trace/trace_state.h @@ -15,6 +15,7 @@ #endif #include "opentelemetry/common/kv_properties.h" +#include "opentelemetry/common/macros.h" #include "opentelemetry/nostd/shared_ptr.h" #include "opentelemetry/nostd/span.h" #include "opentelemetry/nostd/string_view.h" @@ -41,11 +42,7 @@ class TraceState static constexpr auto kKeyValueSeparator = '='; static constexpr auto kMembersSeparator = ','; - static nostd::shared_ptr GetDefault() - { - static nostd::shared_ptr ts{new TraceState()}; - return ts; - } + static nostd::shared_ptr GetDefault() { return default_ts; } /** * Returns shared_ptr to a newly created TraceState parsed from the header provided. @@ -315,6 +312,12 @@ class TraceState private: // Store entries in a C-style array to avoid using std::array or std::vector. nostd::unique_ptr kv_properties_; + + OPENTELEMETRY_DECLARE_API_SINGLETON static nostd::shared_ptr default_ts; }; + +OPENTELEMETRY_DEFINE_API_SINGLETON nostd::shared_ptr TraceState::default_ts( + new TraceState()); + } // namespace trace OPENTELEMETRY_END_NAMESPACE diff --git a/api/test/CMakeLists.txt b/api/test/CMakeLists.txt index 41125005ee..06f29d7365 100644 --- a/api/test/CMakeLists.txt +++ b/api/test/CMakeLists.txt @@ -13,3 +13,4 @@ if(WITH_LOGS_PREVIEW) endif() add_subdirectory(common) add_subdirectory(baggage) +add_subdirectory(singleton) diff --git a/api/test/singleton/BUILD b/api/test/singleton/BUILD new file mode 100644 index 0000000000..a8f5450532 --- /dev/null +++ b/api/test/singleton/BUILD @@ -0,0 +1,142 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +# FIXME: visibility("hidden") / visibility("default") compiling options. + +DEFAULT_WIN_COPTS = [ +] + +# gcc and clang, assumed to be used on this platform +DEFAULT_NOWIN_COPTS = [ + "-fvisibility=default", +] + +HIDDEN_WIN_COPTS = [ +] + +# gcc and clang, assumed to be used on this platform +HIDDEN_NOWIN_COPTS = [ + "-fvisibility=hidden", +] + +cc_library( + name = "component_a", + srcs = [ + "component_a.cc", + ], + hdrs = [ + "component_a.h", + ], + linkstatic = True, + deps = [ + "//api", + ], +) + +cc_library( + name = "component_b", + srcs = [ + "component_b.cc", + ], + hdrs = [ + "component_b.h", + ], + linkstatic = True, + deps = [ + "//api", + ], +) + +cc_library( + name = "component_c", + srcs = [ + "component_c.cc", + ], + hdrs = [ + "component_c.h", + ], + copts = select({ + "//bazel:windows": DEFAULT_WIN_COPTS, + "//conditions:default": DEFAULT_NOWIN_COPTS, + }), + linkstatic = False, + deps = [ + "//api", + ], +) + +cc_library( + name = "component_d", + srcs = [ + "component_d.cc", + ], + hdrs = [ + "component_d.h", + ], + copts = select({ + "//bazel:windows": HIDDEN_WIN_COPTS, + "//conditions:default": HIDDEN_NOWIN_COPTS, + }), + linkstatic = False, + deps = [ + "//api", + ], +) + +cc_library( + name = "component_e", + srcs = [ + "component_e.cc", + ], + hdrs = [ + "component_e.h", + ], + copts = select({ + "//bazel:windows": DEFAULT_WIN_COPTS, + "//conditions:default": DEFAULT_NOWIN_COPTS, + }), + linkstatic = False, + deps = [ + "//api", + ], +) + +cc_library( + name = "component_f", + srcs = [ + "component_f.cc", + ], + hdrs = [ + "component_f.h", + ], + copts = select({ + "//bazel:windows": HIDDEN_WIN_COPTS, + "//conditions:default": HIDDEN_NOWIN_COPTS, + }), + linkstatic = False, + deps = [ + "//api", + ], +) + +cc_test( + name = "singleton_test", + srcs = [ + "singleton_test.cc", + ], + linkstatic = False, + tags = [ + "api", + "test", + ], + deps = [ + "component_a", + "component_b", + "component_c", + "component_d", + "component_e", + "component_f", + "//api", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/api/test/singleton/CMakeLists.txt b/api/test/singleton/CMakeLists.txt new file mode 100644 index 0000000000..ef475bb34d --- /dev/null +++ b/api/test/singleton/CMakeLists.txt @@ -0,0 +1,39 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +include(GoogleTest) + +add_library(component_a STATIC component_a.cc) + +add_library(component_b STATIC component_b.cc) + +add_library(component_c SHARED component_c.cc) +set_target_properties(component_c PROPERTIES CXX_VISIBILITY_PRESET default) + +add_library(component_d SHARED component_d.cc) +set_target_properties(component_d PROPERTIES CXX_VISIBILITY_PRESET hidden) + +add_library(component_e SHARED component_e.cc) +set_target_properties(component_e PROPERTIES CXX_VISIBILITY_PRESET default) + +add_library(component_f SHARED component_f.cc) +set_target_properties(component_f PROPERTIES CXX_VISIBILITY_PRESET hidden) + +add_executable(singleton_test singleton_test.cc) + +target_link_libraries( + singleton_test + component_a + component_b + component_c + component_d + component_e + component_f + ${GTEST_BOTH_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} + opentelemetry_api) + +gtest_add_tests( + TARGET singleton_test + TEST_PREFIX singleton. + TEST_LIST singleton_test) diff --git a/api/test/singleton/component_a.cc b/api/test/singleton/component_a.cc new file mode 100644 index 0000000000..bdf03cb699 --- /dev/null +++ b/api/test/singleton/component_a.cc @@ -0,0 +1,37 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/nostd/shared_ptr.h" +#include "opentelemetry/trace/provider.h" +#include "opentelemetry/version.h" + +#include "component_a.h" + +namespace trace = opentelemetry::trace; +namespace nostd = opentelemetry::nostd; + +static nostd::shared_ptr get_tracer() +{ + auto provider = trace::Provider::GetTracerProvider(); + return provider->GetTracer("A", "10.1"); +} + +static void f1() +{ + auto scoped_span = trace::Scope(get_tracer()->StartSpan("A::f1")); +} + +static void f2() +{ + auto scoped_span = trace::Scope(get_tracer()->StartSpan("A::f2")); + + f1(); + f1(); +} + +void do_something_in_a() +{ + auto scoped_span = trace::Scope(get_tracer()->StartSpan("A::library")); + + f2(); +} diff --git a/api/test/singleton/component_a.h b/api/test/singleton/component_a.h new file mode 100644 index 0000000000..2e06edf9ca --- /dev/null +++ b/api/test/singleton/component_a.h @@ -0,0 +1,4 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +void do_something_in_a(); diff --git a/api/test/singleton/component_b.cc b/api/test/singleton/component_b.cc new file mode 100644 index 0000000000..966d9c461a --- /dev/null +++ b/api/test/singleton/component_b.cc @@ -0,0 +1,37 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/nostd/shared_ptr.h" +#include "opentelemetry/trace/provider.h" +#include "opentelemetry/version.h" + +#include "component_b.h" + +namespace trace = opentelemetry::trace; +namespace nostd = opentelemetry::nostd; + +static nostd::shared_ptr get_tracer() +{ + auto provider = trace::Provider::GetTracerProvider(); + return provider->GetTracer("B", "20.2"); +} + +static void f1() +{ + auto scoped_span = trace::Scope(get_tracer()->StartSpan("B::f1")); +} + +static void f2() +{ + auto scoped_span = trace::Scope(get_tracer()->StartSpan("B::f2")); + + f1(); + f1(); +} + +void do_something_in_b() +{ + auto scoped_span = trace::Scope(get_tracer()->StartSpan("B::library")); + + f2(); +} diff --git a/api/test/singleton/component_b.h b/api/test/singleton/component_b.h new file mode 100644 index 0000000000..2e526e21d5 --- /dev/null +++ b/api/test/singleton/component_b.h @@ -0,0 +1,4 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +void do_something_in_b(); diff --git a/api/test/singleton/component_c.cc b/api/test/singleton/component_c.cc new file mode 100644 index 0000000000..cd87ceb727 --- /dev/null +++ b/api/test/singleton/component_c.cc @@ -0,0 +1,39 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/nostd/shared_ptr.h" +#include "opentelemetry/trace/provider.h" +#include "opentelemetry/version.h" + +#define BUILD_COMPONENT_C + +#include "component_c.h" + +namespace trace = opentelemetry::trace; +namespace nostd = opentelemetry::nostd; + +static nostd::shared_ptr get_tracer() +{ + auto provider = trace::Provider::GetTracerProvider(); + return provider->GetTracer("C", "30.3"); +} + +static void f1() +{ + auto scoped_span = trace::Scope(get_tracer()->StartSpan("C::f1")); +} + +static void f2() +{ + auto scoped_span = trace::Scope(get_tracer()->StartSpan("C::f2")); + + f1(); + f1(); +} + +void do_something_in_c() +{ + auto scoped_span = trace::Scope(get_tracer()->StartSpan("C::library")); + + f2(); +} diff --git a/api/test/singleton/component_c.h b/api/test/singleton/component_c.h new file mode 100644 index 0000000000..31193da2df --- /dev/null +++ b/api/test/singleton/component_c.h @@ -0,0 +1,15 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#if defined(_MSC_VER) +// component_c is a DDL + +# ifdef BUILD_COMPONENT_C +__declspec(dllexport) +# else +__declspec(dllimport) +# endif + +#endif + + void do_something_in_c(); diff --git a/api/test/singleton/component_d.cc b/api/test/singleton/component_d.cc new file mode 100644 index 0000000000..313fd1d23a --- /dev/null +++ b/api/test/singleton/component_d.cc @@ -0,0 +1,39 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/nostd/shared_ptr.h" +#include "opentelemetry/trace/provider.h" +#include "opentelemetry/version.h" + +#define BUILD_COMPONENT_D + +#include "component_d.h" + +namespace trace = opentelemetry::trace; +namespace nostd = opentelemetry::nostd; + +static nostd::shared_ptr get_tracer() +{ + auto provider = trace::Provider::GetTracerProvider(); + return provider->GetTracer("D", "40.4"); +} + +static void f1() +{ + auto scoped_span = trace::Scope(get_tracer()->StartSpan("D::f1")); +} + +static void f2() +{ + auto scoped_span = trace::Scope(get_tracer()->StartSpan("D::f2")); + + f1(); + f1(); +} + +void do_something_in_d() +{ + auto scoped_span = trace::Scope(get_tracer()->StartSpan("D::library")); + + f2(); +} diff --git a/api/test/singleton/component_d.h b/api/test/singleton/component_d.h new file mode 100644 index 0000000000..be65f4b5ac --- /dev/null +++ b/api/test/singleton/component_d.h @@ -0,0 +1,21 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +// Make the entry point visible, loaded dynamically + +#if defined(_MSC_VER) +// component_d is a DDL + +# ifdef BUILD_COMPONENT_D +__declspec(dllexport) +# else +__declspec(dllimport) +# endif + +#else +// component_d is a shared library (*.so) +// component_d is compiled with visibility("hidden"), +__attribute__((visibility("default"))) +#endif + + void do_something_in_d(); diff --git a/api/test/singleton/component_e.cc b/api/test/singleton/component_e.cc new file mode 100644 index 0000000000..9c88d27732 --- /dev/null +++ b/api/test/singleton/component_e.cc @@ -0,0 +1,39 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/nostd/shared_ptr.h" +#include "opentelemetry/trace/provider.h" +#include "opentelemetry/version.h" + +#define BUILD_COMPONENT_E + +#include "component_e.h" + +namespace trace = opentelemetry::trace; +namespace nostd = opentelemetry::nostd; + +static nostd::shared_ptr get_tracer() +{ + auto provider = trace::Provider::GetTracerProvider(); + return provider->GetTracer("E", "50.5"); +} + +static void f1() +{ + auto scoped_span = trace::Scope(get_tracer()->StartSpan("E::f1")); +} + +static void f2() +{ + auto scoped_span = trace::Scope(get_tracer()->StartSpan("E::f2")); + + f1(); + f1(); +} + +void do_something_in_e() +{ + auto scoped_span = trace::Scope(get_tracer()->StartSpan("E::library")); + + f2(); +} diff --git a/api/test/singleton/component_e.h b/api/test/singleton/component_e.h new file mode 100644 index 0000000000..53782d76f7 --- /dev/null +++ b/api/test/singleton/component_e.h @@ -0,0 +1,15 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#if defined(_MSC_VER) +// component_e is a DDL + +# ifdef BUILD_COMPONENT_E +__declspec(dllexport) +# else +__declspec(dllimport) +# endif + +#endif + + void do_something_in_e(); diff --git a/api/test/singleton/component_f.cc b/api/test/singleton/component_f.cc new file mode 100644 index 0000000000..33b0af2fbd --- /dev/null +++ b/api/test/singleton/component_f.cc @@ -0,0 +1,39 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/nostd/shared_ptr.h" +#include "opentelemetry/trace/provider.h" +#include "opentelemetry/version.h" + +#define BUILD_COMPONENT_F + +#include "component_f.h" + +namespace trace = opentelemetry::trace; +namespace nostd = opentelemetry::nostd; + +static nostd::shared_ptr get_tracer() +{ + auto provider = trace::Provider::GetTracerProvider(); + return provider->GetTracer("F", "60.6"); +} + +static void f1() +{ + auto scoped_span = trace::Scope(get_tracer()->StartSpan("F::f1")); +} + +static void f2() +{ + auto scoped_span = trace::Scope(get_tracer()->StartSpan("F::f2")); + + f1(); + f1(); +} + +void do_something_in_f() +{ + auto scoped_span = trace::Scope(get_tracer()->StartSpan("F::library")); + + f2(); +} diff --git a/api/test/singleton/component_f.h b/api/test/singleton/component_f.h new file mode 100644 index 0000000000..775a6cf758 --- /dev/null +++ b/api/test/singleton/component_f.h @@ -0,0 +1,21 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +// Make the entry point visible, loaded dynamically + +#if defined(_MSC_VER) +// component_d is a DDL + +# ifdef BUILD_COMPONENT_F +__declspec(dllexport) +# else +__declspec(dllimport) +# endif + +#else +// component_d is a shared library (*.so) +// component_d is compiled with visibility("hidden"), +__attribute__((visibility("default"))) +#endif + + void do_something_in_f(); diff --git a/api/test/singleton/singleton_test.cc b/api/test/singleton/singleton_test.cc new file mode 100644 index 0000000000..f9942c2f65 --- /dev/null +++ b/api/test/singleton/singleton_test.cc @@ -0,0 +1,289 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include + +#include +#include + +#include "component_a.h" +#include "component_b.h" +#include "component_c.h" +#include "component_d.h" +#include "component_e.h" +#include "component_f.h" + +#include "opentelemetry/trace/default_span.h" +#include "opentelemetry/trace/provider.h" +#include "opentelemetry/trace/span.h" +#include "opentelemetry/trace/span_context_kv_iterable.h" +#include "opentelemetry/trace/span_startoptions.h" +#include "opentelemetry/trace/tracer_provider.h" + +using namespace opentelemetry; + +void do_something() +{ + do_something_in_a(); + do_something_in_b(); + do_something_in_c(); + do_something_in_d(); + do_something_in_e(); + do_something_in_f(); +} + +int span_a_lib_count = 0; +int span_a_f1_count = 0; +int span_a_f2_count = 0; +int span_b_lib_count = 0; +int span_b_f1_count = 0; +int span_b_f2_count = 0; +int span_c_lib_count = 0; +int span_c_f1_count = 0; +int span_c_f2_count = 0; +int span_d_lib_count = 0; +int span_d_f1_count = 0; +int span_d_f2_count = 0; +int span_e_lib_count = 0; +int span_e_f1_count = 0; +int span_e_f2_count = 0; +int span_f_lib_count = 0; +int span_f_f1_count = 0; +int span_f_f2_count = 0; +int unknown_span_count = 0; + +void reset_counts() +{ + span_a_lib_count = 0; + span_a_f1_count = 0; + span_a_f2_count = 0; + span_b_lib_count = 0; + span_b_f1_count = 0; + span_b_f2_count = 0; + span_c_lib_count = 0; + span_c_f1_count = 0; + span_c_f2_count = 0; + span_d_lib_count = 0; + span_d_f1_count = 0; + span_d_f2_count = 0; + span_e_lib_count = 0; + span_e_f1_count = 0; + span_e_f2_count = 0; + span_f_lib_count = 0; + span_f_f1_count = 0; + span_f_f2_count = 0; + unknown_span_count = 0; +} + +class MyTracer : public trace::Tracer +{ +public: + nostd::shared_ptr StartSpan(nostd::string_view name, + const common::KeyValueIterable &attributes, + const trace::SpanContextKeyValueIterable &links, + const trace::StartSpanOptions &options) noexcept override + { + nostd::shared_ptr result(new trace::DefaultSpan(trace::SpanContext::GetInvalid())); + + /* + Unit test code, no need to be fancy. + */ + + if (name == "A::library") + { + span_a_lib_count++; + } + else if (name == "A::f1") + { + span_a_f1_count++; + } + else if (name == "A::f2") + { + span_a_f2_count++; + } + else if (name == "B::library") + { + span_b_lib_count++; + } + else if (name == "B::f1") + { + span_b_f1_count++; + } + else if (name == "B::f2") + { + span_b_f2_count++; + } + else if (name == "C::library") + { + span_c_lib_count++; + } + else if (name == "C::f1") + { + span_c_f1_count++; + } + else if (name == "C::f2") + { + span_c_f2_count++; + } + else if (name == "D::library") + { + span_d_lib_count++; + } + else if (name == "D::f1") + { + span_d_f1_count++; + } + else if (name == "D::f2") + { + span_d_f2_count++; + } + else if (name == "E::library") + { + span_e_lib_count++; + } + else if (name == "E::f1") + { + span_e_f1_count++; + } + else if (name == "E::f2") + { + span_e_f2_count++; + } + else if (name == "F::library") + { + span_f_lib_count++; + } + else if (name == "F::f1") + { + span_f_f1_count++; + } + else if (name == "F::f2") + { + span_f_f2_count++; + } + else + { + unknown_span_count++; + } + + return result; + } + + void ForceFlushWithMicroseconds(uint64_t timeout) noexcept override {} + + void CloseWithMicroseconds(uint64_t timeout) noexcept override {} +}; + +class MyTracerProvider : public trace::TracerProvider +{ +public: + static std::shared_ptr Create() + { + std::shared_ptr result(new MyTracerProvider()); + return result; + } + + nostd::shared_ptr GetTracer(nostd::string_view library_name, + nostd::string_view library_version, + nostd::string_view schema_url) noexcept override + { + nostd::shared_ptr result(new MyTracer()); + return result; + } +}; + +void setup_otel() +{ + std::shared_ptr provider = MyTracerProvider::Create(); + + // The whole point of this test is to make sure + // that the API singleton behind SetTracerProvider() + // works for all components, static and dynamic. + + // Set the global tracer provider + trace_api::Provider::SetTracerProvider(provider); +} + +void cleanup_otel() +{ + std::shared_ptr provider( + new opentelemetry::trace::NoopTracerProvider()); + + // Set the global tracer provider + trace_api::Provider::SetTracerProvider(provider); +} + +TEST(SingletonTest, Uniqueness) +{ + do_something(); + + EXPECT_EQ(span_a_lib_count, 0); + EXPECT_EQ(span_a_f1_count, 0); + EXPECT_EQ(span_a_f2_count, 0); + EXPECT_EQ(span_b_lib_count, 0); + EXPECT_EQ(span_b_f1_count, 0); + EXPECT_EQ(span_b_f2_count, 0); + EXPECT_EQ(span_c_lib_count, 0); + EXPECT_EQ(span_c_f1_count, 0); + EXPECT_EQ(span_c_f2_count, 0); + EXPECT_EQ(span_d_lib_count, 0); + EXPECT_EQ(span_d_f1_count, 0); + EXPECT_EQ(span_d_f2_count, 0); + EXPECT_EQ(span_e_lib_count, 0); + EXPECT_EQ(span_e_f1_count, 0); + EXPECT_EQ(span_e_f2_count, 0); + EXPECT_EQ(span_f_lib_count, 0); + EXPECT_EQ(span_f_f1_count, 0); + EXPECT_EQ(span_f_f2_count, 0); + EXPECT_EQ(unknown_span_count, 0); + + reset_counts(); + setup_otel(); + + do_something(); + + EXPECT_EQ(span_a_lib_count, 1); + EXPECT_EQ(span_a_f1_count, 2); + EXPECT_EQ(span_a_f2_count, 1); + EXPECT_EQ(span_b_lib_count, 1); + EXPECT_EQ(span_b_f1_count, 2); + EXPECT_EQ(span_b_f2_count, 1); + EXPECT_EQ(span_c_lib_count, 1); + EXPECT_EQ(span_c_f1_count, 2); + EXPECT_EQ(span_c_f2_count, 1); + EXPECT_EQ(span_d_lib_count, 1); + EXPECT_EQ(span_d_f1_count, 2); + EXPECT_EQ(span_d_f2_count, 1); + EXPECT_EQ(span_e_lib_count, 1); + EXPECT_EQ(span_e_f1_count, 2); + EXPECT_EQ(span_e_f2_count, 1); + EXPECT_EQ(span_f_lib_count, 1); + EXPECT_EQ(span_f_f1_count, 2); + EXPECT_EQ(span_f_f2_count, 1); + EXPECT_EQ(unknown_span_count, 0); + + reset_counts(); + cleanup_otel(); + + do_something(); + + EXPECT_EQ(span_a_lib_count, 0); + EXPECT_EQ(span_a_f1_count, 0); + EXPECT_EQ(span_a_f2_count, 0); + EXPECT_EQ(span_b_lib_count, 0); + EXPECT_EQ(span_b_f1_count, 0); + EXPECT_EQ(span_b_f2_count, 0); + EXPECT_EQ(span_c_lib_count, 0); + EXPECT_EQ(span_c_f1_count, 0); + EXPECT_EQ(span_c_f2_count, 0); + EXPECT_EQ(span_d_lib_count, 0); + EXPECT_EQ(span_d_f1_count, 0); + EXPECT_EQ(span_d_f2_count, 0); + EXPECT_EQ(span_e_lib_count, 0); + EXPECT_EQ(span_e_f1_count, 0); + EXPECT_EQ(span_e_f2_count, 0); + EXPECT_EQ(span_f_lib_count, 0); + EXPECT_EQ(span_f_f1_count, 0); + EXPECT_EQ(span_f_f2_count, 0); + EXPECT_EQ(unknown_span_count, 0); +}