summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dynamic_load.cpp56
-rw-r--r--src/dynamic_load_unix.cpp94
-rw-r--r--src/dynamic_load_unsupported.cpp10
-rw-r--r--src/dynamic_load_windows.cpp107
-rw-r--r--src/ext/tags.cpp37
-rw-r--r--src/noop.cpp103
-rw-r--r--src/propagation.cpp63
-rw-r--r--src/tracer.cpp60
-rw-r--r--src/tracer_factory.cpp44
9 files changed, 574 insertions, 0 deletions
diff --git a/src/dynamic_load.cpp b/src/dynamic_load.cpp
new file mode 100644
index 0000000..d36c062
--- /dev/null
+++ b/src/dynamic_load.cpp
@@ -0,0 +1,56 @@
+#include <opentracing/dynamic_load.h>
+#include <opentracing/version.h>
+
+namespace opentracing {
+BEGIN_OPENTRACING_ABI_NAMESPACE
+namespace {
+class DynamicLoadErrorCategory : public std::error_category {
+ public:
+ DynamicLoadErrorCategory() {}
+
+ const char* name() const noexcept override {
+ return "OpenTracingDynamicLoadError";
+ }
+
+ std::error_condition default_error_condition(int code) const
+ noexcept override {
+ if (code == dynamic_load_failure_error.value()) {
+ return std::make_error_condition(std::errc::no_such_file_or_directory);
+ }
+ if (code == dynamic_load_not_supported_error.value()) {
+ return std::make_error_condition(std::errc::not_supported);
+ }
+ if (code == incompatible_library_versions_error.value()) {
+ return std::make_error_condition(std::errc::invalid_argument);
+ }
+ return std::error_condition(code, *this);
+ }
+
+ std::string message(int code) const override {
+ if (code == dynamic_load_failure_error.value()) {
+ return "opentracing: failed to load dynamic library";
+ }
+ if (code == dynamic_load_not_supported_error.value()) {
+ return "opentracing: dynamic library loading is not supported";
+ }
+ if (code == incompatible_library_versions_error.value()) {
+ return "opentracing: versions of opentracing libraries are incompatible";
+ }
+ return "opentracing: unknown dynamic load error";
+ }
+};
+} // anonymous namespace
+
+const std::error_category& dynamic_load_error_category() {
+ static const DynamicLoadErrorCategory error_category;
+ return error_category;
+}
+
+DynamicTracingLibraryHandle::DynamicTracingLibraryHandle(
+ std::unique_ptr<const TracerFactory>&& tracer_factory,
+ std::unique_ptr<DynamicLibraryHandle>&& dynamic_library_handle) noexcept
+ : dynamic_library_handle_{std::move(dynamic_library_handle)},
+ tracer_factory_{std::move(tracer_factory)} {}
+
+END_OPENTRACING_ABI_NAMESPACE
+} // namespace opentracing
diff --git a/src/dynamic_load_unix.cpp b/src/dynamic_load_unix.cpp
new file mode 100644
index 0000000..17e08fd
--- /dev/null
+++ b/src/dynamic_load_unix.cpp
@@ -0,0 +1,94 @@
+#include <dlfcn.h>
+#include <opentracing/dynamic_load.h>
+#include <opentracing/version.h>
+
+namespace opentracing {
+BEGIN_OPENTRACING_ABI_NAMESPACE
+namespace {
+class DynamicLibraryHandleUnix : public DynamicLibraryHandle {
+ public:
+ explicit DynamicLibraryHandleUnix(void* handle) : handle_{handle} {}
+
+ ~DynamicLibraryHandleUnix() override { dlclose(handle_); }
+
+ private:
+ void* handle_;
+};
+} // namespace
+
+// Undefined behavior sanitizer has a bug where it will produce a false positive
+// when casting the result of dlsym to a function pointer.
+//
+// See https://github.com/envoyproxy/envoy/pull/2252#issuecomment-362668221
+// https://github.com/google/sanitizers/issues/911
+//
+// Note: undefined behavior sanitizer is supported in clang and gcc > 4.9
+#if defined(__clang__)
+__attribute__((no_sanitize("function")))
+// Copied from https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
+#elif defined(__GNUC__) && \
+ ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= 40900)
+__attribute__((no_sanitize_undefined))
+#endif
+expected<DynamicTracingLibraryHandle>
+DynamicallyLoadTracingLibrary(const char* shared_library,
+ std::string& error_message) noexcept try {
+ dlerror(); // Clear any existing error.
+
+ const auto handle = dlopen(shared_library, RTLD_NOW | RTLD_LOCAL);
+ if (handle == nullptr) {
+ error_message = dlerror();
+ return make_unexpected(dynamic_load_failure_error);
+ }
+
+ std::unique_ptr<DynamicLibraryHandle> dynamic_library_handle{
+ new DynamicLibraryHandleUnix{handle}};
+
+ const auto make_tracer_factory =
+ reinterpret_cast<OpenTracingMakeTracerFactoryType**>(
+ dlsym(handle, "OpenTracingMakeTracerFactory"));
+ if (make_tracer_factory == nullptr) {
+ error_message = dlerror();
+ return make_unexpected(dynamic_load_failure_error);
+ }
+
+ if (*make_tracer_factory == nullptr) {
+ error_message =
+ "An error occurred while looking up for OpenTracingMakeTracerFactory. "
+ "It seems that it was set to nullptr.";
+ return make_unexpected(dynamic_load_failure_error);
+ }
+
+ const void* error_category = nullptr;
+ void* tracer_factory = nullptr;
+ const auto rcode = (*make_tracer_factory)(
+ OPENTRACING_VERSION, OPENTRACING_ABI_VERSION, &error_category,
+ static_cast<void*>(&error_message), &tracer_factory);
+ if (rcode != 0) {
+ if (error_category == nullptr) {
+ error_message = "failed to construct a TracerFactory: unknown error code";
+ return make_unexpected(dynamic_load_failure_error);
+ }
+ const auto error_code = std::error_code{
+ rcode, *static_cast<const std::error_category*>(error_category)};
+ if (error_message.empty()) {
+ error_message = error_code.message();
+ }
+ return make_unexpected(dynamic_load_failure_error);
+ }
+
+ if (tracer_factory == nullptr) {
+ error_message =
+ "failed to construct a TracerFactory: `tracer_factory` is null";
+ return make_unexpected(dynamic_load_failure_error);
+ }
+
+ return DynamicTracingLibraryHandle{
+ std::unique_ptr<const TracerFactory>{
+ static_cast<TracerFactory*>(tracer_factory)},
+ std::move(dynamic_library_handle)};
+} catch (const std::bad_alloc&) {
+ return make_unexpected(std::make_error_code(std::errc::not_enough_memory));
+}
+END_OPENTRACING_ABI_NAMESPACE
+} // namespace opentracing
diff --git a/src/dynamic_load_unsupported.cpp b/src/dynamic_load_unsupported.cpp
new file mode 100644
index 0000000..fd0d767
--- /dev/null
+++ b/src/dynamic_load_unsupported.cpp
@@ -0,0 +1,10 @@
+#include <opentracing/dynamic_load.h>
+
+namespace opentracing {
+BEGIN_OPENTRACING_ABI_NAMESPACE
+expected<DynamicTracingLibraryHandle> DynamicallyLoadTracingLibrary(
+ const char* /*shared_library*/, std::string& /*error_message*/) noexcept {
+ return make_unexpected(dynamic_load_not_supported_error);
+}
+END_OPENTRACING_ABI_NAMESPACE
+} // namespace opentracing
diff --git a/src/dynamic_load_windows.cpp b/src/dynamic_load_windows.cpp
new file mode 100644
index 0000000..ba8cbcf
--- /dev/null
+++ b/src/dynamic_load_windows.cpp
@@ -0,0 +1,107 @@
+#include <opentracing/dynamic_load.h>
+#include <opentracing/version.h>
+
+#include <windows.h>
+
+namespace opentracing {
+BEGIN_OPENTRACING_ABI_NAMESPACE
+// Returns the last Win32 error, in string format. Returns an empty string if
+// there is no error.
+//
+// Taken from https://stackoverflow.com/a/17387176/4447365
+static std::string GetLastErrorAsString() {
+ // Get the error message, if any.
+ DWORD errorMessageID = ::GetLastError();
+ if (errorMessageID == 0)
+ return std::string(); // No error message has been recorded
+
+ LPSTR messageBuffer = nullptr;
+ size_t size = FormatMessageA(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPSTR)&messageBuffer, 0, NULL);
+
+ std::string message(messageBuffer, size);
+
+ // Free the buffer.
+ LocalFree(messageBuffer);
+
+ return message;
+}
+
+namespace {
+class DynamicLibraryHandleWindows : public DynamicLibraryHandle {
+ public:
+ explicit DynamicLibraryHandleWindows(HINSTANCE handle) : handle_{handle} {}
+
+ ~DynamicLibraryHandleWindows() override { FreeLibrary(handle_); }
+
+ private:
+ HINSTANCE handle_;
+};
+} // namespace
+
+expected<DynamicTracingLibraryHandle> DynamicallyLoadTracingLibrary(
+ const char* shared_library, std::string& error_message) noexcept try {
+ const auto handle = LoadLibrary(shared_library);
+ if (handle == nullptr) {
+ error_message = "An error occurred: " + GetLastErrorAsString();
+ return make_unexpected(dynamic_load_failure_error);
+ }
+
+ std::unique_ptr<DynamicLibraryHandle> dynamic_library_handle{
+ new DynamicLibraryHandleWindows{handle}};
+
+ const auto make_tracer_factory =
+ reinterpret_cast<OpenTracingMakeTracerFactoryType**>(
+ GetProcAddress(handle, "OpenTracingMakeTracerFactory"));
+
+ if (make_tracer_factory == nullptr) {
+ error_message =
+ "An error occurred while looking up for OpenTracingMakeTracerFactory "
+ ": " +
+ GetLastErrorAsString();
+ return make_unexpected(dynamic_load_failure_error);
+ }
+
+ if (*make_tracer_factory == nullptr) {
+ error_message =
+ "An error occurred while looking up for OpenTracingMakeTracerFactory. "
+ "It seems that it was set to nullptr.";
+ return make_unexpected(dynamic_load_failure_error);
+ }
+
+ const void* error_category = nullptr;
+ void* tracer_factory = nullptr;
+ const auto rcode = (*make_tracer_factory)(
+ OPENTRACING_VERSION, OPENTRACING_ABI_VERSION, &error_category,
+ static_cast<void*>(&error_message), &tracer_factory);
+ if (rcode != 0) {
+ if (error_category == nullptr) {
+ error_message = "failed to construct a TracerFactory: unknown error code";
+ return make_unexpected(dynamic_load_failure_error);
+ }
+ const auto error_code = std::error_code{
+ rcode, *static_cast<const std::error_category*>(error_category)};
+ if (error_message.empty()) {
+ error_message = error_code.message();
+ }
+ return make_unexpected(error_code);
+ }
+
+ if (tracer_factory == nullptr) {
+ error_message =
+ "failed to construct a TracerFactory: `tracer_factory` is null";
+ return make_unexpected(dynamic_load_failure_error);
+ }
+
+ return DynamicTracingLibraryHandle{
+ std::unique_ptr<const TracerFactory>{
+ static_cast<TracerFactory*>(tracer_factory)},
+ std::move(dynamic_library_handle)};
+} catch (const std::bad_alloc&) {
+ return make_unexpected(std::make_error_code(std::errc::not_enough_memory));
+}
+END_OPENTRACING_ABI_NAMESPACE
+} // namespace opentracing
diff --git a/src/ext/tags.cpp b/src/ext/tags.cpp
new file mode 100644
index 0000000..a86f6f6
--- /dev/null
+++ b/src/ext/tags.cpp
@@ -0,0 +1,37 @@
+#include <opentracing/ext/tags.h>
+
+namespace opentracing {
+BEGIN_OPENTRACING_ABI_NAMESPACE
+namespace ext {
+const opentracing::string_view span_kind = "span.kind";
+const opentracing::string_view span_kind_rpc_client = "client";
+const opentracing::string_view span_kind_rpc_server = "server";
+
+const opentracing::string_view error = "error";
+
+const opentracing::string_view component = "component";
+
+const opentracing::string_view sampling_priority = "sampling.priority";
+
+const opentracing::string_view peer_service = "peer.service";
+
+extern const opentracing::string_view peer_hostname = "peer.hostname";
+extern const opentracing::string_view peer_address = "peer.address";
+extern const opentracing::string_view peer_host_ipv4 = "peer.ipv4";
+extern const opentracing::string_view peer_host_ipv6 = "peer.ipv6";
+extern const opentracing::string_view peer_port = "peer.port";
+
+extern const opentracing::string_view http_url = "http.url";
+extern const opentracing::string_view http_method = "http.method";
+extern const opentracing::string_view http_status_code = "http.status_code";
+
+extern const opentracing::string_view database_instance = "db.instance";
+extern const opentracing::string_view database_statement = "db.statement";
+extern const opentracing::string_view database_type = "db.type";
+extern const opentracing::string_view database_user = "db.user";
+
+extern const opentracing::string_view message_bus_destination =
+ "message_bus.destination";
+} // namespace ext
+END_OPENTRACING_ABI_NAMESPACE
+} // namespace opentracing
diff --git a/src/noop.cpp b/src/noop.cpp
new file mode 100644
index 0000000..9c41ddb
--- /dev/null
+++ b/src/noop.cpp
@@ -0,0 +1,103 @@
+#include <opentracing/noop.h>
+
+namespace opentracing {
+BEGIN_OPENTRACING_ABI_NAMESPACE
+namespace {
+class NoopSpanContext : public SpanContext {
+ public:
+ void ForeachBaggageItem(
+ std::function<bool(const std::string& key,
+ const std::string& value)> /*f*/) const override {}
+
+ std::unique_ptr<SpanContext> Clone() const noexcept override {
+ return std::unique_ptr<SpanContext>{new (std::nothrow) NoopSpanContext{}};
+ }
+};
+
+class NoopSpan : public Span {
+ public:
+ explicit NoopSpan(std::shared_ptr<const Tracer>&& tracer) noexcept
+ : tracer_(std::move(tracer)) {}
+
+ void FinishWithOptions(
+ const FinishSpanOptions& /*finish_span_options*/) noexcept override {}
+
+ void SetOperationName(string_view /*name*/) noexcept override {}
+
+ void SetTag(string_view /*key*/, const Value& /*value*/) noexcept override {}
+
+ void SetBaggageItem(string_view /*restricted_key*/,
+ string_view /*value*/) noexcept override {}
+
+ std::string BaggageItem(string_view /*restricted_key*/) const
+ noexcept override {
+ return {};
+ }
+
+ void Log(std::initializer_list<std::pair<string_view, Value>>
+ /*fields*/) noexcept override {}
+
+ void Log(SystemTime /*timestamp*/,
+ std::initializer_list<
+ std::pair<string_view, Value>> /*fields*/) noexcept override {}
+
+ void Log(SystemTime /*timestamp*/,
+ const std::vector<
+ std::pair<string_view, Value>>& /*fields*/) noexcept override {}
+
+ const SpanContext& context() const noexcept override { return span_context_; }
+
+ const Tracer& tracer() const noexcept override { return *tracer_; }
+
+ private:
+ std::shared_ptr<const Tracer> tracer_;
+ NoopSpanContext span_context_;
+};
+
+class NoopTracer : public Tracer,
+ public std::enable_shared_from_this<NoopTracer> {
+ public:
+ std::unique_ptr<Span> StartSpanWithOptions(
+ string_view /*operation_name*/, const StartSpanOptions& /*options*/) const
+ noexcept override {
+ return std::unique_ptr<Span>(new (std::nothrow)
+ NoopSpan(shared_from_this()));
+ }
+
+ expected<void> Inject(const SpanContext& /*sc*/,
+ std::ostream& /*writer*/) const override {
+ return {};
+ }
+
+ expected<void> Inject(const SpanContext& /*sc*/,
+ const TextMapWriter& /*writer*/) const override {
+ return {};
+ }
+
+ expected<void> Inject(const SpanContext& /*sc*/,
+ const HTTPHeadersWriter& /*writer*/) const override {
+ return {};
+ }
+
+ expected<std::unique_ptr<SpanContext>> Extract(
+ std::istream& /*reader*/) const override {
+ return std::unique_ptr<SpanContext>(nullptr);
+ }
+
+ expected<std::unique_ptr<SpanContext>> Extract(
+ const TextMapReader& /*reader*/) const override {
+ return std::unique_ptr<SpanContext>(nullptr);
+ }
+
+ expected<std::unique_ptr<SpanContext>> Extract(
+ const HTTPHeadersReader& /*reader*/) const override {
+ return std::unique_ptr<SpanContext>(nullptr);
+ }
+};
+} // anonymous namespace
+
+std::shared_ptr<Tracer> MakeNoopTracer() noexcept {
+ return std::shared_ptr<Tracer>(new (std::nothrow) NoopTracer());
+}
+END_OPENTRACING_ABI_NAMESPACE
+} // namespace opentracing
diff --git a/src/propagation.cpp b/src/propagation.cpp
new file mode 100644
index 0000000..56f8394
--- /dev/null
+++ b/src/propagation.cpp
@@ -0,0 +1,63 @@
+#include <opentracing/propagation.h>
+
+namespace opentracing {
+BEGIN_OPENTRACING_ABI_NAMESPACE
+namespace {
+class PropagationErrorCategory : public std::error_category {
+ public:
+ // Needed to fix bug in macOS build
+ // (https://travis-ci.org/isaachier/hunter/jobs/281868518).
+ // See https://stackoverflow.com/a/7411708/1930331 for justification.
+ PropagationErrorCategory() {}
+
+ const char* name() const noexcept override {
+ return "OpenTracingPropagationError";
+ }
+
+ std::error_condition default_error_condition(int code) const
+ noexcept override {
+ if (code == invalid_span_context_error.value()) {
+ return std::make_error_condition(std::errc::not_supported);
+ }
+ if (code == invalid_carrier_error.value()) {
+ return std::make_error_condition(std::errc::invalid_argument);
+ }
+ if (code == span_context_corrupted_error.value()) {
+ return std::make_error_condition(std::errc::invalid_argument);
+ }
+ if (code == key_not_found_error.value()) {
+ return std::make_error_condition(std::errc::invalid_argument);
+ }
+ if (code == lookup_key_not_supported_error.value()) {
+ return std::make_error_condition(std::errc::not_supported);
+ }
+ return std::error_condition(code, *this);
+ }
+
+ std::string message(int code) const override {
+ if (code == invalid_span_context_error.value()) {
+ return "opentracing: SpanContext type incompatible with tracer";
+ }
+ if (code == invalid_carrier_error.value()) {
+ return "opentracing: Invalid Inject/Extract carrier";
+ }
+ if (code == span_context_corrupted_error.value()) {
+ return "opentracing: SpanContext data corrupted in Extract carrier";
+ }
+ if (code == key_not_found_error.value()) {
+ return "opentracing: SpanContext key not found";
+ }
+ if (code == lookup_key_not_supported_error.value()) {
+ return "opentracing: Lookup for the given key is not supported";
+ }
+ return "opentracing: unknown propagation error";
+ }
+};
+} // anonymous namespace
+
+const std::error_category& propagation_error_category() {
+ static const PropagationErrorCategory error_category;
+ return error_category;
+}
+END_OPENTRACING_ABI_NAMESPACE
+} // namespace opentracing
diff --git a/src/tracer.cpp b/src/tracer.cpp
new file mode 100644
index 0000000..52f2f46
--- /dev/null
+++ b/src/tracer.cpp
@@ -0,0 +1,60 @@
+#include <opentracing/noop.h>
+#include <opentracing/tracer.h>
+
+#include <mutex>
+
+namespace opentracing {
+BEGIN_OPENTRACING_ABI_NAMESPACE
+namespace {
+class TracerRegistry {
+ public:
+ static TracerRegistry& instance() noexcept {
+ static TracerRegistry result;
+ return result;
+ }
+
+ static std::shared_ptr<Tracer> RegisterTracer(
+ std::shared_ptr<Tracer>& tracer) noexcept {
+ std::lock_guard<std::mutex> lock_guard{mutex_};
+ is_registered_ = true;
+ tracer_.swap(tracer);
+ return tracer;
+ }
+
+ static std::shared_ptr<Tracer> tracer() noexcept {
+ std::lock_guard<std::mutex> lock_guard{mutex_};
+ return tracer_;
+ }
+
+ static bool is_registered() noexcept {
+ std::lock_guard<std::mutex> lock_guard{mutex_};
+ return is_registered_;
+ }
+
+ private:
+ static std::mutex mutex_;
+ static bool is_registered_;
+ static std::shared_ptr<Tracer> tracer_;
+};
+
+std::mutex TracerRegistry::mutex_;
+
+bool TracerRegistry::is_registered_{false};
+
+std::shared_ptr<Tracer> TracerRegistry::tracer_{MakeNoopTracer()};
+} // namespace
+
+std::shared_ptr<Tracer> Tracer::Global() noexcept {
+ return TracerRegistry::instance().tracer();
+}
+
+std::shared_ptr<Tracer> Tracer::InitGlobal(
+ std::shared_ptr<Tracer> tracer) noexcept {
+ return TracerRegistry::instance().RegisterTracer(tracer);
+}
+
+bool Tracer::IsGlobalTracerRegistered() noexcept {
+ return TracerRegistry::instance().is_registered();
+}
+END_OPENTRACING_ABI_NAMESPACE
+} // namespace opentracing
diff --git a/src/tracer_factory.cpp b/src/tracer_factory.cpp
new file mode 100644
index 0000000..8958310
--- /dev/null
+++ b/src/tracer_factory.cpp
@@ -0,0 +1,44 @@
+#include <opentracing/tracer_factory.h>
+#include <opentracing/version.h>
+
+namespace opentracing {
+BEGIN_OPENTRACING_ABI_NAMESPACE
+namespace {
+class TracerFactoryErrorCategory : public std::error_category {
+ public:
+ TracerFactoryErrorCategory() {}
+
+ const char* name() const noexcept override {
+ return "OpenTracingTracerFactoryError";
+ }
+
+ std::error_condition default_error_condition(int code) const
+ noexcept override {
+ if (code == configuration_parse_error.value()) {
+ return std::make_error_condition(std::errc::invalid_argument);
+ }
+ if (code == invalid_configuration_error.value()) {
+ return std::make_error_condition(std::errc::invalid_argument);
+ }
+ return std::error_condition(code, *this);
+ }
+
+ std::string message(int code) const override {
+ if (code == configuration_parse_error.value()) {
+ return "opentracing: failed to parse configuration";
+ }
+ if (code == invalid_configuration_error.value()) {
+ return "opentracing: invalid configuration";
+ }
+ return "opentracing: unknown tracer factory error";
+ }
+};
+} // anonymous namespace
+
+const std::error_category& tracer_factory_error_category() {
+ static const TracerFactoryErrorCategory error_category;
+ return error_category;
+}
+
+END_OPENTRACING_ABI_NAMESPACE
+} // namespace opentracing