forked from open-telemetry/opentelemetry-specification
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add plugin support (open-telemetry#36)
* Add code for dynamic loading * Add a mock hook * Fix CopyErrorMessage * Set up loading example * Add plugin example * Add plugin example * Make a noisy plugin * Remove mock from sdk * Add ci for testing plugin * Reformat * Remove noexcept from alias * Add windows stub * Add missing includes * Document * Reorganize * Fix formatting * Setup plugin test for windows * Fix typo * Fix windows script * Fix windows script * Fix typo * Fix windows path * Fill out windows testing * Fix windows script * Fix windows script * Fix windows script * Fix windows script * Fix windows script * Fill in windows loading code * Use std::string for error message * Fix example * Use string for error_message * Fix namespace error * Add windows error handling * Fix windows preprocessor error * Fix signature * Add tests for plugins * Fix formatting * Refactor plugin test * Drop unused private section * Update for master
- Loading branch information
Showing
35 changed files
with
870 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
16 changes: 16 additions & 0 deletions
16
api/include/opentelemetry/plugin/detail/dynamic_library_handle.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#pragma once | ||
|
||
namespace opentelemetry | ||
{ | ||
namespace plugin | ||
{ | ||
/** | ||
* Manage the ownership of a dynamically loaded library. | ||
*/ | ||
class DynamicLibraryHandle | ||
{ | ||
public: | ||
virtual ~DynamicLibraryHandle() = default; | ||
}; | ||
} // namespace plugin | ||
} // namespace opentelemetry |
70 changes: 70 additions & 0 deletions
70
api/include/opentelemetry/plugin/detail/dynamic_load_unix.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
#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" | ||
|
||
namespace opentelemetry | ||
{ | ||
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 | ||
} // namespace opentelemetry |
92 changes: 92 additions & 0 deletions
92
api/include/opentelemetry/plugin/detail/dynamic_load_windows.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
#pragma once | ||
|
||
#include <memory> | ||
|
||
#include "opentelemetry/plugin/detail/utility.h" | ||
#include "opentelemetry/plugin/factory.h" | ||
#include "opentelemetry/plugin/hook.h" | ||
#include "opentelemetry/version.h" | ||
|
||
#include <windows.h> | ||
|
||
#include <errhandlingapi.h> | ||
#include <winbase.h> | ||
|
||
namespace opentelemetry | ||
{ | ||
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 | ||
} // namespace opentelemetry |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
#pragma once | ||
|
||
#include "opentelemetry/nostd/string_view.h" | ||
#include "opentelemetry/version.h" | ||
|
||
namespace opentelemetry | ||
{ | ||
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 | ||
} // namespace opentelemetry |
Oops, something went wrong.