Skip to content
Draft
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
35 changes: 34 additions & 1 deletion BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,4 +1,35 @@
load("@rules_cc//cc:defs.bzl", "cc_library")
load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")

cc_library(
name = "dd_trace_cpp_stable_config",
srcs = [
"src/datadog/stable_config_loader.cpp",
"src/datadog/stable_config_loader_internal.h",
"src/datadog/stable_config_parser.cpp",
],
hdrs = ["include/datadog/stable_config_loader.h"],
strip_include_prefix = "include/",
visibility = ["//visibility:public"],
linkopts = select({
"@platforms//os:windows": ["-lshell32"],
"//conditions:default": [],
}),
deps = [
":dd_trace_cpp",
"@yaml-cpp//:yaml-cpp",
],
)

cc_test(
name = "stable_config_loader_test",
size = "small",
srcs = ["test/bazel_stable_config_test.cpp"],
data = [
"test/fixtures/stable_config/fleet.yaml",
"test/fixtures/stable_config/local.yaml",
],
deps = [":dd_trace_cpp_stable_config"],
)

cc_library(
name = "dd_trace_cpp",
Expand Down Expand Up @@ -67,6 +98,7 @@ cc_library(
"src/datadog/span_sampler.cpp",
"src/datadog/span_sampler.h",
"src/datadog/span_sampler_config.cpp",
"src/datadog/stable_config.cpp",
"src/datadog/string_util.cpp",
"src/datadog/string_util.h",
"src/datadog/tag_propagation.cpp",
Expand Down Expand Up @@ -145,6 +177,7 @@ cc_library(
"include/datadog/span_defaults.h",
"include/datadog/span_matcher.h",
"include/datadog/span_sampler_config.h",
"include/datadog/stable_config.h",
"include/datadog/string_view.h",
"include/datadog/telemetry/configuration.h",
"include/datadog/telemetry/metrics.h",
Expand Down
40 changes: 40 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ project(
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
option(BUILD_STATIC_LIBS "Build static libraries" ON)
option(DD_TRACE_BUILD_C_BINDING "Build C binding" OFF)
option(DD_TRACE_BUILD_STABLE_CONFIG "Build the native stable config loader" OFF)

if (WIN32)
option(DD_TRACE_STATIC_CRT "Build dd-trace-cpp with static CRT with MSVC" OFF)
Expand Down Expand Up @@ -166,6 +167,7 @@ target_sources(dd-trace-cpp-objects
include/datadog/span_defaults.h
include/datadog/span_matcher.h
include/datadog/span_sampler_config.h
include/datadog/stable_config.h
include/datadog/string_view.h
include/datadog/trace_id.h
include/datadog/trace_sampler_config.h
Expand Down Expand Up @@ -214,6 +216,7 @@ target_sources(dd-trace-cpp-objects
src/datadog/span_matcher.cpp
src/datadog/span_sampler_config.cpp
src/datadog/span_sampler.cpp
src/datadog/stable_config.cpp
src/datadog/string_util.cpp
src/datadog/tags.cpp
src/datadog/tag_propagation.cpp
Expand Down Expand Up @@ -367,6 +370,43 @@ if (BUILD_STATIC_LIBS)
)
endif ()

if (DD_TRACE_BUILD_STABLE_CONFIG)
include(cmake/deps/yaml-cpp.cmake)
add_library(dd-trace-cpp-stable-config STATIC
src/datadog/stable_config_loader.cpp
src/datadog/stable_config_parser.cpp)
add_library(dd-trace-cpp::stable-config ALIAS dd-trace-cpp-stable-config)
set_target_properties(dd-trace-cpp-stable-config PROPERTIES EXPORT_NAME stable-config)
target_compile_features(dd-trace-cpp-stable-config PUBLIC cxx_std_17)
target_sources(dd-trace-cpp-stable-config PUBLIC
FILE_SET public_headers TYPE HEADERS BASE_DIRS include
FILES include/datadog/stable_config_loader.h)
target_link_libraries(dd-trace-cpp-stable-config PUBLIC yaml-cpp::yaml-cpp)
if (WIN32)
target_link_libraries(dd-trace-cpp-stable-config PUBLIC shell32)
endif ()
if (BUILD_STATIC_LIBS)
target_link_libraries(dd-trace-cpp-stable-config PUBLIC dd-trace-cpp::static)
elseif (BUILD_SHARED_LIBS)
target_link_libraries(dd-trace-cpp-stable-config PUBLIC dd-trace-cpp::shared)
else ()
message(FATAL_ERROR "Stable config requires a dd-trace-cpp library")
endif ()
install(TARGETS dd-trace-cpp-stable-config
EXPORT dd-trace-cpp-targets
FILE_SET public_headers DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(FILES "${yaml-cpp_SOURCE_DIR}/LICENSE"
DESTINATION ${CMAKE_INSTALL_DATADIR}/dd-trace-cpp/licenses
RENAME yaml-cpp-LICENSE)
if (DD_TRACE_BUILD_TESTING)
target_sources(tests PRIVATE test/test_stable_config.cpp)
target_link_libraries(tests PRIVATE dd-trace-cpp::stable-config)
target_compile_definitions(tests PRIVATE
"DD_TRACE_SOURCE_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}\"")
endif ()
endif ()

# install target
write_basic_package_version_file(
"${PROJECT_NAME}-config-version.cmake"
Expand Down
3 changes: 2 additions & 1 deletion LICENSE-3rdparty.csv
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ vendored,nlohmann/json,MIT,Copyright (c) 2013-2022 Niels Lohmann <http://nlohman
vendored,Catch2,Boost,Copyright (c) 2022 Two Blue Cubes Ltd. All rights reserved.
vendored,picosha2,MIT,Copyright (C) 2017 okdshin
vendored,cpp-httplib,MIT,Copyright (c) 2023 Yuji Hirose. All rights reserved.
vendored,open-telemetry/sig-profiling (process-context),Apache-2.0,"Copyright 2025 Datadog, Inc."
vendored,open-telemetry/sig-profiling (process-context),Apache-2.0,"Copyright 2025 Datadog, Inc."
dependency,jbeder/yaml-cpp,MIT,"Copyright (c) 2008-2015 Jesse Beder"
1 change: 1 addition & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ bazel_dep(name = "abseil-cpp", version = "20260817.0", repo_name = "com_google_a
bazel_dep(name = "bazel_skylib", version = "1.9.2")
bazel_dep(name = "platforms", version = "1.1.0")
bazel_dep(name = "rules_cc", version = "0.2.22")
bazel_dep(name = "yaml-cpp", version = "0.9.0")
43 changes: 43 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,49 @@ Installation places a shared library and public headers into the appropriate sys
cmake --install build --prefix=.install
```

### Stable configuration

The optional stable configuration loader uses native C++ and
[yaml-cpp 0.9.0](https://github.com/jbeder/yaml-cpp/releases/tag/yaml-cpp-0.9.0).
Both CMake and Bazel pin the release archive by SHA-256. No Rust toolchain is
needed.

```shell
cmake -B build -DDD_TRACE_BUILD_STABLE_CONFIG=ON .
cmake --build build -j
bazel test //:stable_config_loader_test
```

Link `dd-trace-cpp::stable-config` with CMake or
`//:dd_trace_cpp_stable_config` with Bazel, then load and finalize the
configuration before creating a tracer:

```c++
#include <datadog/stable_config_loader.h>

datadog::tracing::TracerConfig config;
auto finalized =
datadog::tracing::finalize_config_with_stable_config(config, "cpp");
if (!finalized) {
// Handle finalized.error().
}
```

The loader reads the platform's local and fleet `application_monitoring.yaml`
files by default. Pass explicit paths as the third and fourth arguments to
`finalize_config_with_stable_config`, or the second and third arguments to
`load_stable_config`. Files may contain `config_id`,
`apm_configuration_default`, `tags`, and `rules`. Rules select by language,
process arguments, environment variables, or tags. The first matching rule in
each file applies, and its values can contain `{{ language }}` or indexed
variables such as `{{ environment_variables[REGION] }}`.

Settings resolve in this order: defaults, local YAML, environment variables,
fleet YAML, and values in `TracerConfig`. Stable configuration records the
winning source and config ID in configuration telemetry. The existing
`finalize_config(config)` overload keeps its original behavior. Missing or
oversized files are ignored; malformed YAML and other read errors are reported.

### Optional: Linking to the shared library

In case you decided to build the shared library:
Expand Down
6 changes: 6 additions & 0 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
# accessed December 6, 2022.
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(
name = "yaml-cpp",
sha256 = "298593d9c440fd9034b8b193d96318b76d49bc97c6ceadb7b0836edf0b6d7539",
urls = ["https://github.com/jbeder/yaml-cpp/releases/download/yaml-cpp-0.9.0/yaml-cpp-yaml-cpp-0.9.0.tar.gz"],
)

http_archive(
name = "com_google_absl",
sha256 = "1692f77d1739bacf3f94337188b78583cf09bab7e420d2dc6c5605a4f86785a1",
Expand Down
4 changes: 4 additions & 0 deletions cmake/dd-trace-cpp-config.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,8 @@ if(DD_TRACE_TRANSPORT STREQUAL "curl")
find_dependency(CURL)
endif()

if(@DD_TRACE_BUILD_STABLE_CONFIG@)
find_dependency(yaml-cpp 0.9.0 CONFIG)
endif()

include("${CMAKE_CURRENT_LIST_DIR}/dd-trace-cpp-targets.cmake")
18 changes: 18 additions & 0 deletions cmake/deps/yaml-cpp.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
include(FetchContent)

set(YAML_BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
set(YAML_CPP_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(YAML_CPP_BUILD_TOOLS OFF CACHE BOOL "" FORCE)
set(YAML_CPP_INSTALL ON CACHE BOOL "" FORCE)
set(YAML_CPP_DISABLE_UNINSTALL ON CACHE BOOL "" FORCE)
set(YAML_ENABLE_PIC ON CACHE BOOL "" FORCE)
if (DD_TRACE_STATIC_CRT)
set(YAML_MSVC_SHARED_RT OFF CACHE BOOL "" FORCE)
endif ()

FetchContent_Declare(yaml-cpp
URL https://github.com/jbeder/yaml-cpp/releases/download/yaml-cpp-0.9.0/yaml-cpp-yaml-cpp-0.9.0.tar.gz
URL_HASH SHA256=298593d9c440fd9034b8b193d96318b76d49bc97c6ceadb7b0836edf0b6d7539
SYSTEM
)
FetchContent_MakeAvailable(yaml-cpp)
38 changes: 26 additions & 12 deletions include/datadog/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ struct ConfigMetadata {
ENVIRONMENT_VARIABLE, // Originating from environment variables
CODE, // Defined in code
REMOTE_CONFIG, // Retrieved from remote configuration
DEFAULT // Default value
DEFAULT, // Default value
LOCAL_STABLE_CONFIG,
FLEET_STABLE_CONFIG
};

// Name of the configuration parameter
Expand All @@ -56,11 +58,17 @@ struct ConfigMetadata {
Origin origin;
// Optional error associated with the configuration parameter
Optional<Error> error;
Optional<std::string> config_id;

ConfigMetadata() = default;
ConfigMetadata(ConfigName n, std::string v, Origin orig,
Optional<Error> err = nullopt)
: name(n), value(std::move(v)), origin(orig), error(std::move(err)) {}
Optional<Error> err = nullopt,
Optional<std::string> id = nullopt)
: name(n),
value(std::move(v)),
origin(orig),
error(std::move(err)),
config_id(std::move(id)) {}
};

// Returns the final configuration value using the following
Expand Down Expand Up @@ -96,7 +104,11 @@ Value resolve_and_record_config(
const Optional<Value>& from_env, const Optional<Value>& from_user,
std::unordered_map<ConfigName, std::vector<ConfigMetadata>>* metadata,
ConfigName config_name, DefaultValue fallback = nullptr,
Stringifier to_string_fn = nullptr) {
Stringifier to_string_fn = nullptr,
ConfigMetadata::Origin from_env_origin =
ConfigMetadata::Origin::ENVIRONMENT_VARIABLE,
Optional<std::string> from_env_config_id = nullopt,
bool programmatic_wins = false) {
auto stringify = [&](const Value& v) -> std::string {
if constexpr (!std::is_same_v<Stringifier, std::nullptr_t>) {
return to_string_fn(v); // use provided function
Expand All @@ -112,9 +124,11 @@ Value resolve_and_record_config(
std::vector<ConfigMetadata> metadata_entries;
Optional<Value> chosen_value;

auto add_entry = [&](ConfigMetadata::Origin origin, const Value& val) {
auto add_entry = [&](ConfigMetadata::Origin origin, const Value& val,
Optional<std::string> config_id = nullopt) {
std::string val_str = stringify(val);
metadata_entries.emplace_back(ConfigMetadata{config_name, val_str, origin});
metadata_entries.emplace_back(
ConfigMetadata{config_name, val_str, origin, nullopt, config_id});
chosen_value = val;
};

Expand All @@ -123,12 +137,12 @@ Value resolve_and_record_config(
add_entry(ConfigMetadata::Origin::DEFAULT, fallback);
}

if (from_user) {
add_entry(ConfigMetadata::Origin::CODE, *from_user);
}

if (from_env) {
add_entry(ConfigMetadata::Origin::ENVIRONMENT_VARIABLE, *from_env);
if (programmatic_wins) {
if (from_env) add_entry(from_env_origin, *from_env, from_env_config_id);
if (from_user) add_entry(ConfigMetadata::Origin::CODE, *from_user);
} else {
if (from_user) add_entry(ConfigMetadata::Origin::CODE, *from_user);
if (from_env) add_entry(from_env_origin, *from_env, from_env_config_id);
}

if (!metadata_entries.empty()) {
Expand Down
6 changes: 4 additions & 2 deletions include/datadog/datadog_agent_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ namespace datadog::tracing {

class EventScheduler;
class Logger;
class StableConfig;

struct DatadogAgentConfig {
// The `HTTPClient` used to submit traces to the Datadog Agent. If this
Expand Down Expand Up @@ -64,7 +65,8 @@ struct DatadogAgentConfig {

class FinalizedDatadogAgentConfig {
friend Expected<FinalizedDatadogAgentConfig> finalize_config(
const DatadogAgentConfig&, const std::shared_ptr<Logger>&, const Clock&);
const DatadogAgentConfig&, const std::shared_ptr<Logger>&, const Clock&,
const StableConfig*);

FinalizedDatadogAgentConfig() = default;

Expand Down Expand Up @@ -93,6 +95,6 @@ class FinalizedDatadogAgentConfig {

Expected<FinalizedDatadogAgentConfig> finalize_config(
const DatadogAgentConfig& config, const std::shared_ptr<Logger>& logger,
const Clock& clock);
const Clock& clock, const StableConfig* stable_config = nullptr);

} // namespace datadog::tracing
3 changes: 3 additions & 0 deletions include/datadog/environment.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

namespace datadog {
namespace tracing {
class StableConfig;
namespace environment {

// Central registry for supported environment variables.
Expand Down Expand Up @@ -117,6 +118,8 @@ StringView name(Variable variable);
// Return the value of the specified environment `variable`, or return
// `nullopt` if that variable is not set in the environment.
Optional<StringView> lookup(Variable variable);
Optional<StringView> lookup(Variable variable,
const StableConfig* stable_config);

std::string to_json();

Expand Down
8 changes: 5 additions & 3 deletions include/datadog/span_sampler_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
namespace datadog {
namespace tracing {

class StableConfig;

struct SpanSamplerConfig {
struct Rule : public SpanMatcher {
double sample_rate = 1.0;
Expand All @@ -37,7 +39,7 @@ struct SpanSamplerConfig {

class FinalizedSpanSamplerConfig {
friend Expected<FinalizedSpanSamplerConfig> finalize_config(
const SpanSamplerConfig&, Logger&);
const SpanSamplerConfig&, Logger&, const StableConfig*);
friend class FinalizedTracerConfig;

FinalizedSpanSamplerConfig() = default;
Expand All @@ -52,8 +54,8 @@ class FinalizedSpanSamplerConfig {
std::unordered_map<ConfigName, std::vector<ConfigMetadata>> metadata;
};

Expected<FinalizedSpanSamplerConfig> finalize_config(const SpanSamplerConfig&,
Logger&);
Expected<FinalizedSpanSamplerConfig> finalize_config(
const SpanSamplerConfig&, Logger&, const StableConfig* = nullptr);

std::string to_string(const FinalizedSpanSamplerConfig::Rule&);

Expand Down
Loading
Loading