Skip to content

Commit

Permalink
feat: store tracer configuration in an in-memory file (#184)
Browse files Browse the repository at this point in the history
Resolves [APMAPI-1066]
  • Loading branch information
dmehala authored Feb 15, 2025
1 parent 62a9e91 commit f3ebccc
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 0 deletions.
8 changes: 8 additions & 0 deletions include/datadog/tracer.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ struct SpanConfig;
class TraceSampler;
class SpanSampler;
class IDGenerator;
class InMemoryFile;

class Tracer {
std::shared_ptr<Logger> logger_;
Expand All @@ -47,6 +48,10 @@ class Tracer {
Optional<std::string> 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<InMemoryFile> metadata_file_;

public:
// Create a tracer configured using the specified `config`, and optionally:
Expand Down Expand Up @@ -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
Expand Down
57 changes: 57 additions & 0 deletions src/datadog/platform_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
# define DD_SDK_KERNEL "Linux"
# include "string_util.h"
# include <fstream>
# include <sys/types.h>
# include <sys/mman.h>
# include <fcntl.h>
# include <errno.h>
# endif
#elif defined(_MSC_VER)
# include <windows.h>
Expand Down Expand Up @@ -224,5 +228,58 @@ 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<int*>(handle_);
close(*data);
delete (data);
}

bool InMemoryFile::write_then_seal(const std::string& data) {
int fd = *static_cast<int*>(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> 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 = ";
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> InMemoryFile::make(StringView) {
return Error{Error::Code::NOT_IMPLEMENTED, "In-memory file not implemented"};
}
#endif

} // namespace tracing
} // namespace datadog
42 changes: 42 additions & 0 deletions src/datadog/platform_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,53 @@

// This component provides platform-dependent miscellanea.

#include <datadog/expected.h>
#include <datadog/string_view.h>

#include <string>

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<InMemoryFile> 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<InMemoryFile> make(StringView name);
};

// Hold host information mainly used for telemetry purposes
// and for identifying a tracer.
struct HostInfo final {
Expand Down
6 changes: 6 additions & 0 deletions src/datadog/random.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions src/datadog/random.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
40 changes: 40 additions & 0 deletions src/datadog/tracer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,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"
Expand Down Expand Up @@ -85,6 +87,8 @@ Tracer::Tracer(const FinalizedTracerConfig& config,
log << "DATADOG TRACER CONFIGURATION - " << configuration;
});
}

store_config();
}

std::string Tracer::config() const {
Expand All @@ -110,6 +114,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<InMemoryFile>(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<void>{}; },
"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) {
Expand Down

0 comments on commit f3ebccc

Please sign in to comment.