diff options
Diffstat (limited to 'src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin')
10 files changed, 513 insertions, 0 deletions
diff --git a/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/detail/dynamic_library_handle.h b/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/detail/dynamic_library_handle.h new file mode 100644 index 000000000..9ffe076ad --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/detail/dynamic_library_handle.h @@ -0,0 +1,20 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace plugin +{ +/** + * Manage the ownership of a dynamically loaded library. + */ +class DynamicLibraryHandle +{ +public: + virtual ~DynamicLibraryHandle() = default; +}; +} // namespace plugin +OPENTELEMETRY_END_NAMESPACE diff --git a/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/detail/dynamic_load_unix.h b/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/detail/dynamic_load_unix.h new file mode 100644 index 000000000..bcc4bd0b8 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/detail/dynamic_load_unix.h @@ -0,0 +1,72 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include <algorithm> +#include <memory> + +#include <dlfcn.h> + +#include "opentelemetry/plugin/detail/utility.h" +#include "opentelemetry/plugin/factory.h" +#include "opentelemetry/plugin/hook.h" +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace plugin +{ +class DynamicLibraryHandleUnix final : public DynamicLibraryHandle +{ +public: + explicit DynamicLibraryHandleUnix(void *handle) noexcept : handle_{handle} {} + + ~DynamicLibraryHandleUnix() override { ::dlclose(handle_); } + +private: + void *handle_; +}; + +inline std::unique_ptr<Factory> LoadFactory(const char *plugin, std::string &error_message) noexcept +{ + dlerror(); // Clear any existing error. + + auto handle = ::dlopen(plugin, RTLD_NOW | RTLD_LOCAL); + if (handle == nullptr) + { + detail::CopyErrorMessage(dlerror(), error_message); + return nullptr; + } + + std::shared_ptr<DynamicLibraryHandle> library_handle{new (std::nothrow) + DynamicLibraryHandleUnix{handle}}; + if (library_handle == nullptr) + { + return nullptr; + } + + auto make_factory_impl = + reinterpret_cast<OpenTelemetryHook *>(::dlsym(handle, "OpenTelemetryMakeFactoryImpl")); + if (make_factory_impl == nullptr) + { + detail::CopyErrorMessage(dlerror(), error_message); + return nullptr; + } + if (*make_factory_impl == nullptr) + { + detail::CopyErrorMessage("Invalid plugin hook", error_message); + return nullptr; + } + LoaderInfo loader_info; + nostd::unique_ptr<char[]> plugin_error_message; + auto factory_impl = (**make_factory_impl)(loader_info, plugin_error_message); + if (factory_impl == nullptr) + { + detail::CopyErrorMessage(plugin_error_message.get(), error_message); + return nullptr; + } + return std::unique_ptr<Factory>{new (std::nothrow) + Factory{std::move(library_handle), std::move(factory_impl)}}; +} +} // namespace plugin +OPENTELEMETRY_END_NAMESPACE diff --git a/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/detail/dynamic_load_windows.h b/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/detail/dynamic_load_windows.h new file mode 100644 index 000000000..7a586b6bc --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/detail/dynamic_load_windows.h @@ -0,0 +1,97 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include <memory> + +#include "opentelemetry/plugin/detail/utility.h" +#include "opentelemetry/plugin/factory.h" +#include "opentelemetry/plugin/hook.h" +#include "opentelemetry/version.h" + +#ifndef NOMINMAX +# define NOMINMAX +#endif +#include <Windows.h> + +#include <WinBase.h> +#include <errhandlingapi.h> + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace plugin +{ +namespace detail +{ +inline void GetLastErrorMessage(std::string &error_message) noexcept +{ + auto error_code = ::GetLastError(); + // See https://stackoverflow.com/a/455533/4447365 + LPTSTR error_text = nullptr; + auto size = ::FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + reinterpret_cast<LPTSTR>(&error_text), 0, nullptr); + if (size == 0) + { + return; + } + CopyErrorMessage(error_text, error_message); + ::LocalFree(error_text); +} +} // namespace detail + +class DynamicLibraryHandleWindows final : public DynamicLibraryHandle +{ +public: + explicit DynamicLibraryHandleWindows(HINSTANCE handle) : handle_{handle} {} + + ~DynamicLibraryHandleWindows() override { ::FreeLibrary(handle_); } + +private: + HINSTANCE handle_; +}; + +inline std::unique_ptr<Factory> LoadFactory(const char *plugin, std::string &error_message) noexcept +{ + auto handle = ::LoadLibrary(plugin); + if (handle == nullptr) + { + detail::GetLastErrorMessage(error_message); + return nullptr; + } + + std::shared_ptr<DynamicLibraryHandle> library_handle{new (std::nothrow) + DynamicLibraryHandleWindows{handle}}; + if (library_handle == nullptr) + { + detail::CopyErrorMessage("Allocation failure", error_message); + return nullptr; + } + + auto make_factory_impl = reinterpret_cast<OpenTelemetryHook *>( + ::GetProcAddress(handle, "OpenTelemetryMakeFactoryImpl")); + if (make_factory_impl == nullptr) + { + detail::GetLastErrorMessage(error_message); + return nullptr; + } + if (*make_factory_impl == nullptr) + { + detail::CopyErrorMessage("Invalid plugin hook", error_message); + return nullptr; + } + + LoaderInfo loader_info; + nostd::unique_ptr<char[]> plugin_error_message; + auto factory_impl = (**make_factory_impl)(loader_info, plugin_error_message); + if (factory_impl == nullptr) + { + detail::CopyErrorMessage(plugin_error_message.get(), error_message); + return nullptr; + } + return std::unique_ptr<Factory>{new (std::nothrow) + Factory{std::move(library_handle), std::move(factory_impl)}}; +} +} // namespace plugin +OPENTELEMETRY_END_NAMESPACE diff --git a/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/detail/loader_info.h b/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/detail/loader_info.h new file mode 100644 index 000000000..ca8c9f0a1 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/detail/loader_info.h @@ -0,0 +1,24 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "opentelemetry/nostd/string_view.h" +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace plugin +{ +/** + * LoaderInfo describes the versioning of the loader. + * + * Plugins can check against this information and properly error out if they were built against an + * incompatible OpenTelemetry API. + */ +struct LoaderInfo +{ + nostd::string_view opentelemetry_version = OPENTELEMETRY_VERSION; + nostd::string_view opentelemetry_abi_version = OPENTELEMETRY_ABI_VERSION; +}; +} // namespace plugin +OPENTELEMETRY_END_NAMESPACE diff --git a/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/detail/tracer_handle.h b/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/detail/tracer_handle.h new file mode 100644 index 000000000..559d7ddf4 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/detail/tracer_handle.h @@ -0,0 +1,23 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "opentelemetry/trace/tracer.h" +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace plugin +{ +/** + * Manage the ownership of a dynamically loaded tracer. + */ +class TracerHandle +{ +public: + virtual ~TracerHandle() = default; + + virtual trace::Tracer &tracer() const noexcept = 0; +}; +} // namespace plugin +OPENTELEMETRY_END_NAMESPACE diff --git a/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/detail/utility.h b/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/detail/utility.h new file mode 100644 index 000000000..6f8dd5d46 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/detail/utility.h @@ -0,0 +1,34 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include <memory> +#include <string> + +#include "opentelemetry/nostd/string_view.h" +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace plugin +{ +namespace detail +{ +inline void CopyErrorMessage(const char *source, std::string &destination) noexcept +#if __EXCEPTIONS +try +#endif +{ + if (source == nullptr) + { + return; + } + destination.assign(source); +} +#if __EXCEPTIONS +catch (const std::bad_alloc &) +{} +#endif +} // namespace detail +} // namespace plugin +OPENTELEMETRY_END_NAMESPACE diff --git a/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/dynamic_load.h b/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/dynamic_load.h new file mode 100644 index 000000000..8318d534a --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/dynamic_load.h @@ -0,0 +1,27 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include <string> + +#ifdef _WIN32 +# include "opentelemetry/plugin/detail/dynamic_load_windows.h" +#else +# include "opentelemetry/plugin/detail/dynamic_load_unix.h" +#endif + +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace plugin +{ +/** + * Load an OpenTelemetry implementation as a plugin. + * @param plugin the path to the plugin to load + * @param error_message on failure this is set to an error message + * @return a Factory that can be used to create OpenTelemetry objects or nullptr on failure. + */ +std::unique_ptr<Factory> LoadFactory(const char *plugin, std::string &error_message) noexcept; +} // namespace plugin +OPENTELEMETRY_END_NAMESPACE diff --git a/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/factory.h b/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/factory.h new file mode 100644 index 000000000..0a285d65b --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/factory.h @@ -0,0 +1,65 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once +#include <memory> +#include <string> + +#include "opentelemetry/plugin/detail/utility.h" +#include "opentelemetry/plugin/tracer.h" +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace plugin +{ +/** + * Factory creates OpenTelemetry objects from configuration strings. + */ +class Factory final +{ +public: + class FactoryImpl + { + public: + virtual ~FactoryImpl() {} + + virtual nostd::unique_ptr<TracerHandle> MakeTracerHandle( + nostd::string_view tracer_config, + nostd::unique_ptr<char[]> &error_message) const noexcept = 0; + }; + + Factory(std::shared_ptr<DynamicLibraryHandle> library_handle, + std::unique_ptr<FactoryImpl> &&factory_impl) noexcept + : library_handle_{std::move(library_handle)}, factory_impl_{std::move(factory_impl)} + {} + + /** + * Construct a tracer from a configuration string. + * @param tracer_config a representation of the tracer's config as a string. + * @param error_message on failure this will contain an error message. + * @return a Tracer on success or nullptr on failure. + */ + std::shared_ptr<opentelemetry::trace::Tracer> MakeTracer( + nostd::string_view tracer_config, + std::string &error_message) const noexcept + { + nostd::unique_ptr<char[]> plugin_error_message; + auto tracer_handle = factory_impl_->MakeTracerHandle(tracer_config, plugin_error_message); + if (tracer_handle == nullptr) + { + detail::CopyErrorMessage(plugin_error_message.get(), error_message); + return nullptr; + } + return std::shared_ptr<opentelemetry::trace::Tracer>{ + new (std::nothrow) Tracer{library_handle_, std::move(tracer_handle)}}; + } + +private: + // Note: The order is important here. + // + // It's undefined behavior to close the library while a loaded FactoryImpl is still active. + std::shared_ptr<DynamicLibraryHandle> library_handle_; + std::unique_ptr<FactoryImpl> factory_impl_; +}; +} // namespace plugin +OPENTELEMETRY_END_NAMESPACE diff --git a/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/hook.h b/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/hook.h new file mode 100644 index 000000000..c06c0b324 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/hook.h @@ -0,0 +1,48 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "opentelemetry/plugin/detail/loader_info.h" +#include "opentelemetry/plugin/factory.h" +#include "opentelemetry/version.h" + +#ifdef _WIN32 + +/** + * Cross-platform helper macro to declare the symbol used to load an OpenTelemetry implementation + * as a plugin. + * + * Note: The symbols use weak linkage so as to support using an OpenTelemetry both as a regular + * library and a dynamically loaded plugin. The weak linkage allows for multiple implementations to + * be linked in without getting multiple definition errors. + */ +# define OPENTELEMETRY_DEFINE_PLUGIN_HOOK(X) \ + extern "C" { \ + extern __declspec(dllexport) \ + opentelemetry::plugin::OpenTelemetryHook const OpenTelemetryMakeFactoryImpl; \ + \ + __declspec(selectany) \ + opentelemetry::plugin::OpenTelemetryHook const OpenTelemetryMakeFactoryImpl = X; \ + } // extern "C" + +#else + +# define OPENTELEMETRY_DEFINE_PLUGIN_HOOK(X) \ + extern "C" { \ + __attribute(( \ + weak)) extern opentelemetry::plugin::OpenTelemetryHook const OpenTelemetryMakeFactoryImpl; \ + \ + opentelemetry::plugin::OpenTelemetryHook const OpenTelemetryMakeFactoryImpl = X; \ + } // extern "C" + +#endif + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace plugin +{ +using OpenTelemetryHook = + nostd::unique_ptr<Factory::FactoryImpl> (*)(const LoaderInfo &loader_info, + nostd::unique_ptr<char[]> &error_message); +} // namespace plugin +OPENTELEMETRY_END_NAMESPACE diff --git a/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/tracer.h b/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/tracer.h new file mode 100644 index 000000000..149f2a93b --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/plugin/tracer.h @@ -0,0 +1,103 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include <memory> + +#include "opentelemetry/common/key_value_iterable.h" +#include "opentelemetry/plugin/detail/dynamic_library_handle.h" +#include "opentelemetry/plugin/detail/tracer_handle.h" +#include "opentelemetry/trace/tracer.h" +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace plugin +{ +class Span final : public trace::Span +{ +public: + Span(std::shared_ptr<trace::Tracer> &&tracer, nostd::shared_ptr<trace::Span> span) noexcept + : tracer_{std::move(tracer)}, span_{span} + {} + + // trace::Span + void SetAttribute(nostd::string_view name, const common::AttributeValue &value) noexcept override + { + span_->SetAttribute(name, value); + } + + void AddEvent(nostd::string_view name) noexcept override { span_->AddEvent(name); } + + void AddEvent(nostd::string_view name, common::SystemTimestamp timestamp) noexcept override + { + span_->AddEvent(name, timestamp); + } + + void AddEvent(nostd::string_view name, + common::SystemTimestamp timestamp, + const common::KeyValueIterable &attributes) noexcept override + { + span_->AddEvent(name, timestamp, attributes); + } + + void SetStatus(trace::StatusCode code, nostd::string_view description) noexcept override + { + span_->SetStatus(code, description); + } + + void UpdateName(nostd::string_view name) noexcept override { span_->UpdateName(name); } + + void End(const trace::EndSpanOptions &options = {}) noexcept override { span_->End(options); } + + bool IsRecording() const noexcept override { return span_->IsRecording(); } + + trace::SpanContext GetContext() const noexcept override { return span_->GetContext(); } + +private: + std::shared_ptr<trace::Tracer> tracer_; + nostd::shared_ptr<trace::Span> span_; +}; + +class Tracer final : public trace::Tracer, public std::enable_shared_from_this<Tracer> +{ +public: + Tracer(std::shared_ptr<DynamicLibraryHandle> library_handle, + std::unique_ptr<TracerHandle> &&tracer_handle) noexcept + : library_handle_{std::move(library_handle)}, tracer_handle_{std::move(tracer_handle)} + {} + + // trace::Tracer + nostd::shared_ptr<trace::Span> StartSpan( + nostd::string_view name, + const common::KeyValueIterable &attributes, + const trace::SpanContextKeyValueIterable &links, + const trace::StartSpanOptions &options = {}) noexcept override + { + auto span = tracer_handle_->tracer().StartSpan(name, attributes, links, options); + if (span == nullptr) + { + return nostd::shared_ptr<trace::Span>(nullptr); + } + return nostd::shared_ptr<trace::Span>{new (std::nothrow) Span{this->shared_from_this(), span}}; + } + + void ForceFlushWithMicroseconds(uint64_t timeout) noexcept override + { + tracer_handle_->tracer().ForceFlushWithMicroseconds(timeout); + } + + void CloseWithMicroseconds(uint64_t timeout) noexcept override + { + tracer_handle_->tracer().CloseWithMicroseconds(timeout); + } + +private: + // Note: The order is important here. + // + // It's undefined behavior to close the library while a loaded tracer is still active. + std::shared_ptr<DynamicLibraryHandle> library_handle_; + std::unique_ptr<TracerHandle> tracer_handle_; +}; +} // namespace plugin +OPENTELEMETRY_END_NAMESPACE |