Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ cc_library(
"src/datadog/telemetry/metrics.cpp",
"src/datadog/telemetry/log.h",
"src/datadog/telemetry/telemetry.cpp",
"src/datadog/baggage.cpp",
"src/datadog/base64.cpp",
"src/datadog/cerr_logger.cpp",
"src/datadog/clock.cpp",
Expand Down Expand Up @@ -78,6 +79,7 @@ cc_library(
"src/datadog/w3c_propagation.h",
],
hdrs = [
"include/datadog/baggage.h",
"include/datadog/cerr_logger.h",
"include/datadog/clock.h",
"include/datadog/collector.h",
Expand Down
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ target_sources(dd_trace_cpp-objects
src/datadog/telemetry/configuration.cpp
src/datadog/telemetry/metrics.cpp
src/datadog/telemetry/telemetry.cpp
src/datadog/baggage.cpp
src/datadog/base64.cpp
src/datadog/cerr_logger.cpp
src/datadog/clock.cpp
Expand Down
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,5 @@ run chmod +x /tmp/install-cmake && /tmp/install-cmake && rm /tmp/install-cmake
copy bin/install-lcov /tmp/install-lcov
run chmod +x /tmp/install-lcov && /tmp/install-lcov && rm /tmp/install-lcov

run curl -fLSs https://raw.githubusercontent.com/CircleCI-Public/circleci-cli/main/install.sh | bash

1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
add_subdirectory(baggage)
add_subdirectory(hasher)
add_subdirectory(http-server)
2 changes: 2 additions & 0 deletions examples/baggage/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
add_executable(baggage-example main.cpp)
target_link_libraries(baggage-example dd_trace_cpp-static)
95 changes: 95 additions & 0 deletions examples/baggage/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#include <datadog/dict_reader.h>
#include <datadog/tracer.h>

#include <iostream>

namespace dd = datadog::tracing;

struct CinReader : public dd::DictReader {
std::string input;

dd::Optional<dd::StringView> lookup(dd::StringView key) const override {
return input;
}

void visit(
const std::function<void(dd::StringView key, dd::StringView value)>&
visitor) const override{};
};

std::istream& operator>>(std::istream& is, CinReader& reader) {
is >> reader.input;
return is;
}

std::ostream& operator<<(std::ostream& os, dd::Baggage::Error error) {
using dd::Baggage;
switch (error.code) {
case Baggage::Error::MISSING_HEADER:
os << "missing `baggage` header";
break;
case Baggage::Error::MALFORMED_BAGGAGE_HEADER: {
os << "malformed `baggage` header";
if (error.pos) {
os << " at position " << *error.pos;
}
} break;
case Baggage::Error::MAXIMUM_CAPACITY_REACHED:
os << "maximum number of bagge items reached";
break;
case Baggage::Error::MAXIMUM_BYTES_REACHED:
os << "maximum amount of bytes written";
break;
default:
os << "unknown error code";
break;
}
return os;
}

int main() {
dd::TracerConfig cfg;
cfg.log_on_startup = false;
cfg.telemetry.enabled = false;
cfg.agent.remote_configuration_enabled = false;
const auto finalized_cfg = datadog::tracing::finalize_config(cfg);
if (auto error = finalized_cfg.if_error()) {
std::cerr << "Failed to initialize the tracer: " << error->message
<< std::endl;
return error->code;
}

dd::Tracer tracer(*finalized_cfg);

std::cout
<< "This program demonstrates how to use baggage, a feature that allows "
"metadata (key-value pairs) to be attached to a request and "
"propagated across services.\n"
"Baggage can be useful for passing contextual information, such as "
"user IDs, session tokens, or request attributes, between different "
"components of a distributed system.\n\n"
"This example lets you input baggage values, validate them and "
"displays the baggage content parsed.\n"
"You can enter baggage manually or provide it through a file, try:\n"
"- k1=v1,k2=v2\n"
"- ,invalid=input\n"
"or ./baggage-example < list-of-baggages.txt\n\n";

CinReader reader;
std::cout << "Enter baggage (or 'CTRL+C' to quit): ";
while (std::getline(std::cin, reader.input)) {
auto baggage = tracer.extract_baggage(reader);
if (!baggage) {
std::cout << "Error parsing \"" << reader.input
<< "\": " << baggage.error() << ".\n";
} else {
std::cout << "Baggage key-value parsed: \n";
baggage->visit([](dd::StringView key, dd::StringView value) {
std::cout << key << ": " << value << std::endl;
});
}

std::cout << "\nEnter baggage (or 'CTRL+C' to quit): ";
}
return 0;
}
1 change: 1 addition & 0 deletions fuzz/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
add_subdirectory(base64)
add_subdirectory(tracing)
add_subdirectory(w3c-propagation)

12 changes: 12 additions & 0 deletions fuzz/tracing/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
add_executable(baggage-fuzz baggage.cpp)

add_dependencies(baggage-fuzz dd_trace_cpp-static)

target_include_directories(baggage-fuzz
PRIVATE
${CMAKE_SOURCE_DIR}/src
)

target_link_libraries(baggage-fuzz dd_trace_cpp-static)

add_target_to_group(baggage-fuzz dd_trace_cpp-fuzzers)
33 changes: 33 additions & 0 deletions fuzz/tracing/baggage.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include <datadog/baggage.h>
#include <datadog/dict_reader.h>
#include <datadog/string_view.h>

#include <cstdint>

namespace dd = datadog::tracing;

class MapReader : public dd::DictReader {
std::unordered_map<std::string, std::string> map_;

public:
~MapReader() override = default;

MapReader(std::unordered_map<std::string, std::string> map)
: map_(std::move(map)) {}

dd::Optional<dd::StringView> lookup(dd::StringView key) const override {
auto it = map_.find(std::string(key));
if (it == map_.cend()) return dd::nullopt;

return it->second;
}

void visit(const std::function<void(dd::StringView key,
dd::StringView value)>&) const override{};
};

extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, size_t size) {
MapReader reader({{"baggage", std::string((const char*)data, size)}});
dd::Baggage::extract(reader);
return 0;
}
148 changes: 148 additions & 0 deletions include/datadog/baggage.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
#pragma once

#include <datadog/dict_reader.h>
#include <datadog/dict_writer.h>
#include <datadog/expected.h>
#include <datadog/optional.h>
#include <datadog/string_view.h>

#include <string>
#include <unordered_map>

namespace datadog {
namespace tracing {

/// OpenTelemetry-like implementation of the Baggage concept.
/// Baggage is a key-value store meant to propagate data across services and
/// processes boundaries.
///
/// Baggage are extracted from any tracing context implementing the `DictReader`
/// interface using `Baggage::extract`.
///
/// Baggages are injected to any tracing context implementing the `DictWriter`
/// interface using the `inject` method.
class Baggage {
public:
struct Error final {
enum Code : char {
/// Baggage propagation is disabled. This may be due to one of the
/// following
/// reasons:
/// - `baggage` is not set as an extraction or injection propagation
/// style.
/// - The maximum number of items is less than 0.
/// - The number of bytes is less than 3.
DISABLED,
MISSING_HEADER,
MALFORMED_BAGGAGE_HEADER,
MAXIMUM_CAPACITY_REACHED,
MAXIMUM_BYTES_REACHED,
};
Code code;
Optional<size_t> pos;

Error(Code in_code) : code(in_code), pos(nullopt) {}
Error(Code in_code, size_t position) : code(in_code), pos(position) {}
};

struct Options final {
size_t max_bytes;
size_t max_items;
};

static constexpr size_t default_max_capacity = 64;
static constexpr Options default_options{2048, default_max_capacity};

/// Extracts a Baggage instance from a `DictReader` and creates a Baggage
/// instance if no errors are encounters .
///
/// @param `reader` The input `DictReader` from which to extract the data.
/// @return A `Baggage` instance or an `Error`.
static Expected<Baggage, Error> extract(const DictReader& reader);

/// Initializes an empty Baggage with the default maximum capacity.
Baggage() = default;

/// Initializes an empty Baggage instance with the given maximum capacity.
///
/// @param `max_capacity` The maximum capacity for this Baggage instance.
Baggage(size_t max_capacity);

/// Initializes a Baggage instance using the provided unordered_map of
/// key-value pairs. The maximum capacity can also be specified.
///
/// @param `baggage_map` The map containing key-value pairs to initialize the
/// Baggage.
/// @param `max_capacity` The maximum capacity for this Baggage instance.
Baggage(std::unordered_map<std::string, std::string>,
size_t max_capacity = default_max_capacity);

/// Checks if the Baggage contains a specified key.
///
/// @param `key` The key to check.
/// @return `true` if the key exists in the Baggage; otherwise, `false`.
bool contains(StringView key) const;

/// Retrieves the value associated with a specified key.
///
/// @param `key` The key to retrieve the value for.
/// @return An `Optional<StringView>` containing the value if the key exists,
/// or an empty Optional if the key is not found.
Optional<StringView> get(StringView key) const;

/// Adds a key-value pair to the Baggage.
///
/// This function will attempt to add the given key-value pair to the Baggage.
/// If the maximum capacity has been reached, the insertion will fail.
/// If a `key` already exists, its value will be overwritten with `value`.
///
/// @param `key` The key to insert.
/// @param `value` The value to associate with the key.
/// @return `true` if the key-value pair was successfully added; `false` if
/// the maximum capacity was reached.
bool set(std::string key, std::string value);

/// Removes the key-value pair corresponding to the specified key.
///
/// @param `key` The key to remove from the Baggage.
void remove(StringView key);

/// Removes all key-value pair.
void clear();

/// Retrieves the number of items stored.
size_t size() const;

/// Returns whether any items are stored.
bool empty() const;

/// Visits each key-value pair in the Baggage and invoke the provided
/// visitor function for each key-value pair in the Baggage.
///
/// @param `visitor` A function object that will be called for each
/// key-value pair.
void visit(std::function<void(StringView, StringView)>&& visitor);

/// Injects the Baggage data into a `DictWriter` with the constraint that
/// the amount of bytes written does not exceed the specified maximum byte
/// limit.
///
/// @param `writer` The DictWriter to inject the data into.
/// @param `opts` Injection options.
/// @return An `Expected<void>`, which may either succeed or contain an
/// error.
Expected<void> inject(DictWriter& writer,
const Options& opts = default_options) const;

/// Equality operator for comparing two Baggage instances.
inline bool operator==(const Baggage& rhs) const {
return baggage_ == rhs.baggage_;
}

private:
const size_t max_capacity_ = Baggage::default_max_capacity;
std::unordered_map<std::string, std::string> baggage_;
};

} // namespace tracing
} // namespace datadog
2 changes: 2 additions & 0 deletions include/datadog/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ enum class ConfigName : char {
TRACE_SAMPLING_LIMIT,
TRACE_SAMPLING_RULES,
SPAN_SAMPLING_RULES,
TRACE_BAGGAGE_MAX_BYTES,
TRACE_BAGGAGE_MAX_ITEMS,
};

// Represents metadata for configuration parameters
Expand Down
2 changes: 2 additions & 0 deletions include/datadog/environment.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ namespace environment {
MACRO(DD_TELEMETRY_METRICS_ENABLED) \
MACRO(DD_TELEMETRY_METRICS_INTERVAL_SECONDS) \
MACRO(DD_TELEMETRY_DEBUG) \
MACRO(DD_TRACE_BAGGAGE_MAX_ITEMS) \
MACRO(DD_TRACE_BAGGAGE_MAX_BYTES) \
MACRO(DD_TELEMETRY_LOG_COLLECTION_ENABLED)

#define WITH_COMMA(ARG) ARG,
Expand Down
2 changes: 2 additions & 0 deletions include/datadog/error.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ struct Error {
DATADOG_AGENT_INVALID_REMOTE_CONFIG_POLL_INTERVAL = 51,
SAMPLING_DELEGATION_RESPONSE_INVALID_JSON = 52,
REMOTE_CONFIGURATION_INVALID_INPUT = 53,
BAGGAGE_MAXIMUM_BYTES_REACHED = 54,
BAGGAGE_MAXIMUM_ITEMS_REACHED = 55,
};

Code code;
Expand Down
Loading
Loading