From 14c8deef2675f69ca14f55a0ed95cac57589b5cf Mon Sep 17 00:00:00 2001 From: Damien Mehala Date: Tue, 4 Feb 2025 11:12:29 +0100 Subject: [PATCH 1/7] feat: store tracer configuration in-memory file Resolves [APMAPI-1066] --- include/datadog/tracer.h | 8 +++++ src/datadog/platform_util.cpp | 58 ++++++++++++++++++++++++++++++++++- src/datadog/platform_util.h | 43 ++++++++++++++++++++++++++ src/datadog/random.cpp | 6 ++++ src/datadog/random.h | 1 + src/datadog/tracer.cpp | 42 +++++++++++++++++++++++++ 6 files changed, 157 insertions(+), 1 deletion(-) diff --git a/include/datadog/tracer.h b/include/datadog/tracer.h index 49b0211c..949b19b4 100644 --- a/include/datadog/tracer.h +++ b/include/datadog/tracer.h @@ -31,6 +31,7 @@ struct SpanConfig; class TraceSampler; class SpanSampler; class IDGenerator; +class InMemoryFile; class Tracer { std::shared_ptr logger_; @@ -47,6 +48,10 @@ class Tracer { Optional hostname_; std::size_t tags_header_max_size_; bool sampling_delegation_enabled_; + // Store the tracer configuration in an in-memory file, allowing it to be + // read to determine if the process is instrumented with a tracer and to + // retrieve relevant tracing information. + std::shared_ptr metadata_file_; public: // Create a tracer configured using the specified `config`, and optionally: @@ -81,6 +86,9 @@ class Tracer { // Return a JSON object describing this Tracer's configuration. It is the same // JSON object that was logged when this Tracer was created. std::string config() const; + + private: + void store_config(); }; } // namespace tracing diff --git a/src/datadog/platform_util.cpp b/src/datadog/platform_util.cpp index f395d7cf..e566d625 100644 --- a/src/datadog/platform_util.cpp +++ b/src/datadog/platform_util.cpp @@ -1,5 +1,6 @@ #include "platform_util.h" +#include // clang-format off #if defined(__x86_64__) || defined(_M_X64) # define DD_SDK_CPU_ARCH "x86_64" @@ -25,6 +26,10 @@ # define DD_SDK_KERNEL "Linux" # include "string_util.h" # include +# include +# include +# include +# include # endif #elif defined(_MSC_VER) # include @@ -98,7 +103,7 @@ std::tuple get_windows_info() { // application manifest, which is the lowest version supported by the // application. Use `RtlGetVersion` to obtain the accurate OS version // regardless of the manifest. - using RtlGetVersion = auto(*)(LPOSVERSIONINFOEXW)->NTSTATUS; + using RtlGetVersion = auto (*)(LPOSVERSIONINFOEXW)->NTSTATUS; RtlGetVersion func = (RtlGetVersion)GetProcAddress(GetModuleHandleA("ntdll"), "RtlGetVersion"); @@ -224,5 +229,56 @@ int at_fork_in_child(void (*on_fork)()) { #endif } +InMemoryFile::InMemoryFile(void* handle) : handle_(handle) {} + +InMemoryFile::InMemoryFile(InMemoryFile&& rhs) { + std::swap(rhs.handle_, handle_); +}; +InMemoryFile& InMemoryFile::operator=(InMemoryFile&& rhs) { + std::swap(handle_, rhs.handle_); + return *this; +} + +#if defined(__linux__) || defined(__unix__) + +InMemoryFile::~InMemoryFile() { + /// NOTE(@dmehala): No need to close the fd since it is automatically handled + /// by `MFD_CLOEXEC`. + if (handle_ == nullptr) return; + int* data = static_cast(handle_); + delete (data); +} + +bool InMemoryFile::write_then_seal(const std::string& data) { + int fd = *static_cast(handle_); + + size_t written = write(fd, data.data(), data.size()); + if (written != data.size()) return false; + + return fcntl(fd, F_ADD_SEALS, + F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL) == 0; +} + +Expected InMemoryFile::make(std::string_view name) { + int fd = memfd_create(name.data(), MFD_CLOEXEC | MFD_ALLOW_SEALING); + if (fd == -1) { + std::string err_msg = "failed to create an anonymous file. errno = "; + err_msg += std::to_string(errno); + return Error{Error::Code::OTHER, std::move(err_msg)}; + } + + int* handle = new int; + *handle = fd; + return InMemoryFile(handle); +} + +#else +InMemoryFile::~InMemoryFile() {} +bool InMemoryFile::write_then_seal(const std::string&) { return false; } +Expected InMemoryFile::make(StringView) { + return Error{Error::Code::NOT_IMPLEMENTED, "In-memory file not implemented"}; +} +#endif + } // namespace tracing } // namespace datadog diff --git a/src/datadog/platform_util.h b/src/datadog/platform_util.h index cfadfecd..908760b0 100644 --- a/src/datadog/platform_util.h +++ b/src/datadog/platform_util.h @@ -2,11 +2,54 @@ // This component provides platform-dependent miscellanea. +#include +#include +#include + #include namespace datadog { namespace tracing { +// A wrapper around an in-memory file descriptor. +// +// This class provides a simple interface to create an in-memory file, write +// data to it, and seal it to prevent further modifications. +// Currently, this implementation is only available on Linux as it relies on the +// `memfd_create` system call. +class InMemoryFile final { + /// Internal handle on the in-memory file. + void* handle_ = nullptr; + + /// Constructs an `InMemoryFile` from an existing handle. + /// + /// @param handle A valid handle to an in-memory file. + InMemoryFile(void* handle); + friend Expected make(StringView); + + public: + InMemoryFile(const InMemoryFile&) = delete; + InMemoryFile& operator=(const InMemoryFile&) = delete; + InMemoryFile(InMemoryFile&&); + InMemoryFile& operator=(InMemoryFile&&); + + ~InMemoryFile(); + + /// Writes content to the in-memory file and then seals it. + /// Once sealed, further modifications to the file are not possible. + /// + /// @param content The data to write into the in-memory file. + /// @return `true` if the write and seal operations succeed, `false` + /// otherwise. + bool write_then_seal(const std::string& content); + + /// Creates an in-memory file with the given name. + /// + /// @param name The name of the in-memoru file. + /// @return An `InMemoryFile` if successful, or an error on failure. + static Expected make(StringView name); +}; + // Hold host information mainly used for telemetry purposes // and for identifying a tracer. struct HostInfo final { diff --git a/src/datadog/random.cpp b/src/datadog/random.cpp index 3125df04..48138af2 100644 --- a/src/datadog/random.cpp +++ b/src/datadog/random.cpp @@ -82,5 +82,11 @@ std::string uuid() { return result; } +std::string short_uuid() { + std::bitset<64> high = random_uint64(); + std::string hexed = hex_padded(high.to_ullong()); + return hexed.substr(0, 8); +} + } // namespace tracing } // namespace datadog diff --git a/src/datadog/random.h b/src/datadog/random.h index c8f2ea17..2c3312eb 100644 --- a/src/datadog/random.h +++ b/src/datadog/random.h @@ -16,6 +16,7 @@ std::uint64_t random_uint64(); // Return a pseudo-random UUID in canonical string form as described in RFC // 4122. For example, "595af0a4-ff29-4a8c-9f37-f8ff055e0f80". std::string uuid(); +std::string short_uuid(); } // namespace tracing } // namespace datadog diff --git a/src/datadog/tracer.cpp b/src/datadog/tracer.cpp index 248f0b34..f651e550 100644 --- a/src/datadog/tracer.cpp +++ b/src/datadog/tracer.cpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include @@ -19,7 +21,9 @@ #include "extraction_util.h" #include "hex.h" #include "json.hpp" +#include "msgpack.h" #include "platform_util.h" +#include "random.h" #include "span_data.h" #include "span_sampler.h" #include "tags.h" @@ -85,6 +89,8 @@ Tracer::Tracer(const FinalizedTracerConfig& config, log << "DATADOG TRACER CONFIGURATION - " << configuration; }); } + + store_config(); } std::string Tracer::config() const { @@ -110,6 +116,42 @@ std::string Tracer::config() const { return config.dump(); } +void Tracer::store_config() { + auto maybe_file = + InMemoryFile::make(std::string("datadog-tracer-info-") + short_uuid()); + if (auto error = maybe_file.if_error()) { + if (error->code == Error::Code::NOT_IMPLEMENTED) return; + + logger_->log_error("Failed to open anonymous file"); + return; + } + + metadata_file_ = std::make_unique(std::move(*maybe_file)); + + auto defaults = config_manager_->span_defaults(); + + std::string buffer; + buffer.reserve(1024); + + // clang-format off + msgpack::pack_map( + buffer, + "schema_version", [&](auto& buffer) { msgpack::pack_integer(buffer, std::uint64_t(1)); return Expected{}; }, + "runtime_id", [&](auto& buffer) { return msgpack::pack_string(buffer, runtime_id_.string()); }, + "tracer_version", [&](auto& buffer) { return msgpack::pack_string(buffer, signature_.library_version); }, + "tracer_language", [&](auto& buffer) { return msgpack::pack_string(buffer, signature_.library_language); }, + "hostname", [&](auto& buffer) { return msgpack::pack_string(buffer, hostname_.value_or("")); }, + "service_name", [&](auto& buffer) { return msgpack::pack_string(buffer, defaults->service); }, + "service_env", [&](auto& buffer) { return msgpack::pack_string(buffer, defaults->environment); }, + "service_version", [&](auto& buffer) { return msgpack::pack_string(buffer, defaults->version); } + ); + // clang-format on + + if (!metadata_file_->write_then_seal(buffer)) { + logger_->log_error("Either failed to write or seal the configuration file"); + } +} + Span Tracer::create_span() { return create_span(SpanConfig{}); } Span Tracer::create_span(const SpanConfig& config) { From 06b7aa4959bc833b728147dfe034c12e6cb264ff Mon Sep 17 00:00:00 2001 From: Damien Mehala Date: Sun, 9 Feb 2025 19:54:13 +0100 Subject: [PATCH 2/7] fix: abseil compilation --- src/datadog/platform_util.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/datadog/platform_util.cpp b/src/datadog/platform_util.cpp index e566d625..c8fb60d0 100644 --- a/src/datadog/platform_util.cpp +++ b/src/datadog/platform_util.cpp @@ -259,7 +259,7 @@ bool InMemoryFile::write_then_seal(const std::string& data) { F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL) == 0; } -Expected InMemoryFile::make(std::string_view name) { +Expected InMemoryFile::make(StringView name) { int fd = memfd_create(name.data(), MFD_CLOEXEC | MFD_ALLOW_SEALING); if (fd == -1) { std::string err_msg = "failed to create an anonymous file. errno = "; From 73b6735f3fe8a64d4db45253bfac09264944fca3 Mon Sep 17 00:00:00 2001 From: Damien Mehala Date: Sun, 9 Feb 2025 19:55:40 +0100 Subject: [PATCH 3/7] fix: format --- src/datadog/platform_util.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/datadog/platform_util.cpp b/src/datadog/platform_util.cpp index c8fb60d0..effca080 100644 --- a/src/datadog/platform_util.cpp +++ b/src/datadog/platform_util.cpp @@ -103,7 +103,7 @@ std::tuple get_windows_info() { // application manifest, which is the lowest version supported by the // application. Use `RtlGetVersion` to obtain the accurate OS version // regardless of the manifest. - using RtlGetVersion = auto (*)(LPOSVERSIONINFOEXW)->NTSTATUS; + using RtlGetVersion = auto(*)(LPOSVERSIONINFOEXW)->NTSTATUS; RtlGetVersion func = (RtlGetVersion)GetProcAddress(GetModuleHandleA("ntdll"), "RtlGetVersion"); From e822ca811fe002e7f2e153f296d3ec0f9691514a Mon Sep 17 00:00:00 2001 From: Damien Mehala Date: Sun, 9 Feb 2025 21:34:31 +0100 Subject: [PATCH 4/7] fix: compilation --- src/datadog/platform_util.cpp | 3 +-- src/datadog/platform_util.h | 1 - src/datadog/tracer.cpp | 2 -- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/datadog/platform_util.cpp b/src/datadog/platform_util.cpp index effca080..32db8f04 100644 --- a/src/datadog/platform_util.cpp +++ b/src/datadog/platform_util.cpp @@ -1,6 +1,5 @@ #include "platform_util.h" -#include // clang-format off #if defined(__x86_64__) || defined(_M_X64) # define DD_SDK_CPU_ARCH "x86_64" @@ -103,7 +102,7 @@ std::tuple get_windows_info() { // application manifest, which is the lowest version supported by the // application. Use `RtlGetVersion` to obtain the accurate OS version // regardless of the manifest. - using RtlGetVersion = auto(*)(LPOSVERSIONINFOEXW)->NTSTATUS; + using RtlGetVersion = auto (*)(LPOSVERSIONINFOEXW)->NTSTATUS; RtlGetVersion func = (RtlGetVersion)GetProcAddress(GetModuleHandleA("ntdll"), "RtlGetVersion"); diff --git a/src/datadog/platform_util.h b/src/datadog/platform_util.h index 908760b0..5b0acb7a 100644 --- a/src/datadog/platform_util.h +++ b/src/datadog/platform_util.h @@ -3,7 +3,6 @@ // This component provides platform-dependent miscellanea. #include -#include #include #include diff --git a/src/datadog/tracer.cpp b/src/datadog/tracer.cpp index f651e550..7b530258 100644 --- a/src/datadog/tracer.cpp +++ b/src/datadog/tracer.cpp @@ -9,8 +9,6 @@ #include #include #include -#include -#include #include #include From 5e66b93f8f6958f346dfd47f738797f0f19eec89 Mon Sep 17 00:00:00 2001 From: Damien Mehala Date: Sun, 9 Feb 2025 21:42:29 +0100 Subject: [PATCH 5/7] fix: format --- src/datadog/platform_util.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/datadog/platform_util.cpp b/src/datadog/platform_util.cpp index 32db8f04..496d453e 100644 --- a/src/datadog/platform_util.cpp +++ b/src/datadog/platform_util.cpp @@ -102,7 +102,7 @@ std::tuple get_windows_info() { // application manifest, which is the lowest version supported by the // application. Use `RtlGetVersion` to obtain the accurate OS version // regardless of the manifest. - using RtlGetVersion = auto (*)(LPOSVERSIONINFOEXW)->NTSTATUS; + using RtlGetVersion = auto(*)(LPOSVERSIONINFOEXW)->NTSTATUS; RtlGetVersion func = (RtlGetVersion)GetProcAddress(GetModuleHandleA("ntdll"), "RtlGetVersion"); @@ -232,7 +232,8 @@ InMemoryFile::InMemoryFile(void* handle) : handle_(handle) {} InMemoryFile::InMemoryFile(InMemoryFile&& rhs) { std::swap(rhs.handle_, handle_); -}; +} + InMemoryFile& InMemoryFile::operator=(InMemoryFile&& rhs) { std::swap(handle_, rhs.handle_); return *this; From bb89b1344513cb53c9c02a3030c6200209715de3 Mon Sep 17 00:00:00 2001 From: Damien Mehala Date: Tue, 11 Feb 2025 12:08:58 +0100 Subject: [PATCH 6/7] close fd in destructor --- src/datadog/platform_util.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/datadog/platform_util.cpp b/src/datadog/platform_util.cpp index 496d453e..8ff89e8d 100644 --- a/src/datadog/platform_util.cpp +++ b/src/datadog/platform_util.cpp @@ -102,7 +102,7 @@ std::tuple get_windows_info() { // application manifest, which is the lowest version supported by the // application. Use `RtlGetVersion` to obtain the accurate OS version // regardless of the manifest. - using RtlGetVersion = auto(*)(LPOSVERSIONINFOEXW)->NTSTATUS; + using RtlGetVersion = auto (*)(LPOSVERSIONINFOEXW)->NTSTATUS; RtlGetVersion func = (RtlGetVersion)GetProcAddress(GetModuleHandleA("ntdll"), "RtlGetVersion"); @@ -246,6 +246,7 @@ InMemoryFile::~InMemoryFile() { /// by `MFD_CLOEXEC`. if (handle_ == nullptr) return; int* data = static_cast(handle_); + close(*data); delete (data); } From 6f71825356b6d7544c7c709230086c545c8b878d Mon Sep 17 00:00:00 2001 From: Damien Mehala Date: Tue, 11 Feb 2025 14:21:21 +0100 Subject: [PATCH 7/7] fix: format --- src/datadog/platform_util.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/datadog/platform_util.cpp b/src/datadog/platform_util.cpp index 8ff89e8d..169094f5 100644 --- a/src/datadog/platform_util.cpp +++ b/src/datadog/platform_util.cpp @@ -102,7 +102,7 @@ std::tuple get_windows_info() { // application manifest, which is the lowest version supported by the // application. Use `RtlGetVersion` to obtain the accurate OS version // regardless of the manifest. - using RtlGetVersion = auto (*)(LPOSVERSIONINFOEXW)->NTSTATUS; + using RtlGetVersion = auto(*)(LPOSVERSIONINFOEXW)->NTSTATUS; RtlGetVersion func = (RtlGetVersion)GetProcAddress(GetModuleHandleA("ntdll"), "RtlGetVersion");