Skip to content

Commit 9e5b88a

Browse files
committed
rework config inversion
1 parent 9f5c450 commit 9e5b88a

15 files changed

Lines changed: 629 additions & 555 deletions

.github/workflows/dev.yml

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,32 @@ name: "Development"
22
on: [pull_request, workflow_dispatch, workflow_call]
33

44
jobs:
5-
format-and-verify-configurations:
5+
verify:
66
runs-on: ubuntu-22.04-arm
77
container:
88
image: datadog/docker-library:dd-trace-cpp-ci-23768e9-arm64
9+
env:
10+
BUILD_DIR: .build
911
steps:
1012
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
1113
- name: Check format
1214
run: bin/check-format
1315
- name: Shellcheck
1416
run: find bin/ -executable -type f -print0 | xargs -0 shellcheck
15-
- name: Verify environment variable allowlist
17+
- name: Verify getenv usage
1618
run: bin/check-environment-variables
19+
- name: Configure
20+
run: bin/with-toolchain llvm cmake . -B ${BUILD_DIR} --preset ci-clang
21+
- name: Build
22+
run: cmake --build ${BUILD_DIR} -j --target config-inversion -v
1723
- name: Verify supported configurations metadata
1824
run: |
1925
tmp_dir="$(mktemp -d)"
2026
trap 'rm -rf "$tmp_dir"' EXIT
21-
cp metadata/supported-configurations.json "$tmp_dir/supported-configurations.json"
22-
bin/generate-supported-configurations
23-
if ! diff -q "$tmp_dir/supported-configurations.json" metadata/supported-configurations.json >/dev/null 2>&1; then
24-
echo "ERROR: metadata/supported-configurations.json got out of sync with implemented configurations. Please run bin/generate-supported-configurations locally."
25-
diff -u "$tmp_dir/supported-configurations.json" metadata/supported-configurations.json || true
27+
./${BUILD_DIR}/tools/config-inversion/config-inversion --output-file "${tmp_dir}/ci-supported-configurations.json"
28+
if ! diff -q "$tmp_dir/ci-supported-configurations.json" "supported-configurations.json" >/dev/null 2>&1; then
29+
echo "ERROR: supported-configurations.json got out of sync with implemented configurations. Please run `./config-inversion --output-file supported-configurations.json` locally."
30+
diff -u "$tmp_dir/supported-configurations.json" supported-configurations.json || true
2631
exit 1
2732
fi
2833
@@ -39,7 +44,7 @@ jobs:
3944
- runner: ubuntu-22.04
4045
arch: x64
4146
docker-arch: amd64
42-
needs: format-and-verify-configurations
47+
needs: verify
4348
runs-on: ${{ matrix.runner }}
4449
container:
4550
image: datadog/docker-library:dd-trace-cpp-ci-23768e9-${{matrix.docker-arch}}
@@ -67,7 +72,7 @@ jobs:
6772
datadog-ci junit upload --service dd-trace-cpp --tags test.source.file:test/*.cpp .build/report.xml
6873
6974
build-linux-bazel:
70-
needs: format-and-verify-configurations
75+
needs: verify
7176
strategy:
7277
fail-fast: false
7378
matrix:
@@ -90,7 +95,7 @@ jobs:
9095
run: bin/with-toolchain ${{ matrix.toolchain }} bazelisk --bazelrc=${{ matrix.bazelrc }} build dd_trace_cpp
9196

9297
build-windows-bazel:
93-
needs: format-and-verify-configurations
98+
needs: verify
9499
runs-on: windows-2022
95100
defaults:
96101
run:
@@ -111,7 +116,7 @@ jobs:
111116
run: bazelisk.exe --bazelrc=${{ matrix.bazelrc }} build dd_trace_cpp
112117

113118
build-windows-cmake:
114-
needs: format-and-verify-configurations
119+
needs: verify
115120
strategy:
116121
fail-fast: false
117122
matrix:

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,3 @@ MODULE.bazel.lock
1212
.cache/
1313
.cursor/
1414
.DS_Store
15-
bin/.supported-configurations

.gitlab-ci.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ validate_supported_configurations_v2_local_file:
2020
- when: on_success
2121
extends: .validate_supported_configurations_v2_local_file
2222
variables:
23-
LOCAL_JSON_PATH: "metadata/supported-configurations.json"
23+
LOCAL_JSON_PATH: "supported-configurations.json"
2424
BACKFILLED: false
2525

2626
update_central_configurations_version_range_v2:
@@ -30,6 +30,6 @@ update_central_configurations_version_range_v2:
3030
extends: .update_central_configurations_version_range_v2
3131
variables:
3232
LOCAL_REPO_NAME: "dd-trace-cpp"
33-
LOCAL_JSON_PATH: "metadata/supported-configurations.json"
33+
LOCAL_JSON_PATH: "supported-configurations.json"
3434
LANGUAGE_NAME: "cpp"
35-
MULTIPLE_RELEASE_LINES: "false"
35+
MULTIPLE_RELEASE_LINES: "false"

CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
4343
option(DD_TRACE_BUILD_EXAMPLES "Build example programs" OFF)
4444
option(DD_TRACE_BUILD_TESTING "Build the unit tests (test/)" OFF)
4545
option(DD_TRACE_BUILD_FUZZERS "Build fuzzers" OFF)
46+
option(DD_TRACE_BUILD_TOOLS "Build tools" OFF)
4647
option(DD_TRACE_BUILD_BENCHMARK "Build benchmark binaries" OFF)
4748
option(DD_TRACE_ENABLE_COVERAGE "Build code with code coverage profiling instrumentation" OFF)
4849
option(DD_TRACE_ENABLE_SANITIZE "Build with address sanitizer and undefined behavior sanitizer" OFF)
@@ -98,6 +99,11 @@ if (DD_TRACE_BUILD_BENCHMARK)
9899
add_subdirectory(benchmark)
99100
endif ()
100101

102+
if (DD_TRACE_BUILD_TOOLS)
103+
include(cmake/deps/cxxopts.cmake)
104+
add_subdirectory(tools/config-inversion)
105+
endif ()
106+
101107
add_library(dd-trace-cpp-objects OBJECT)
102108
add_library(dd-trace-cpp::obj ALIAS dd-trace-cpp-objects)
103109

CMakePresets.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"DD_TRACE_ENABLE_SANITIZE": "ON",
3131
"DD_TRACE_BUILD_TESTING": "ON",
3232
"DD_TRACE_BUILD_EXAMPLES": "ON",
33+
"DD_TRACE_BUILD_TOOLS": "ON",
3334
"DD_TRACE_BUILD_FUZZERS": "OFF"
3435
}
3536
},
@@ -39,6 +40,7 @@
3940
"cacheVariables": {
4041
"CMAKE_BUILD_TYPE": "Debug",
4142
"DD_TRACE_ENABLE_SANITIZE": "ON",
43+
"DD_TRACE_BUILD_TOOLS": "ON",
4244
"DD_TRACE_BUILD_TESTING": "ON"
4345
}
4446
}

bin/check-environment-variables

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/bin/sh
2+
# TODO
3+
set -eu
4+
5+
if grep -R -n \
6+
--include='*.c' \
7+
--include='*.cc' \
8+
--include='*.cpp' \
9+
--include='*.cxx' \
10+
--include='*.h' \
11+
--include='*.hpp' \
12+
--exclude='environment.cpp' \
13+
'std::getenv' include src; then
14+
echo "Check failed: std::getenv usage detected."
15+
exit 1
16+
else
17+
echo "Check passed: no std::getenv usage found."
18+
exit 0
19+
fi

cmake/deps/cxxopts.cmake

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
include(FetchContent)
2+
3+
FetchContent_Declare(cxxopts
4+
URL https://github.com/jarro2783/cxxopts/archive/refs/tags/v3.3.1.tar.gz
5+
URL_HASH SHA256=3bfc70542c521d4b55a46429d808178916a579b28d048bd8c727ee76c39e2072
6+
FIND_PACKAGE_ARGS NAMES cxxopts
7+
EXCLUDE_FROM_ALL
8+
SYSTEM
9+
)
10+
11+
FetchContent_MakeAvailable(cxxopts)

include/datadog/environment.h

Lines changed: 80 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -9,146 +9,107 @@
99
// `name` returns the name of a specified `Variable`.
1010
//
1111
// `lookup` retrieves the value of `Variable` in the environment.
12-
13-
#include <datadog/environment_registry.h>
14-
#include <datadog/expected.h>
1512
#include <datadog/optional.h>
1613
#include <datadog/string_view.h>
1714

18-
#include <cstdint>
19-
#include <cstdlib>
15+
#include <string>
2016

2117
namespace datadog {
2218
namespace tracing {
2319
namespace environment {
2420

25-
enum class VariableType {
26-
STRING,
27-
BOOLEAN,
28-
INT,
29-
DECIMAL,
30-
ARRAY,
31-
MAP,
32-
};
33-
34-
struct VariableSpec {
35-
StringView name;
36-
VariableType type;
37-
};
38-
39-
#define VARIABLE_ENUM_VALUE(DATA, NAME, TYPE, DEFAULT_VALUE) NAME,
40-
41-
enum Variable { DD_ENVIRONMENT_VARIABLES(VARIABLE_ENUM_VALUE, ~) };
21+
// Central registry for supported environment variables.
22+
// All configurations must be registered here.
23+
//
24+
// This registry is the single source of truth for:
25+
// - env variable name allowlist (`include/datadog/environment.h`)
26+
// - generated metadata (`metadata/supported-configurations.json`)
27+
//
28+
// Each entry has:
29+
// - NAME: environment variable symbol (e.g. DD_SERVICE)
30+
// - TYPE: STRING | BOOLEAN | INT | DECIMAL | ARRAY | MAP
31+
// - DEFAULT: literal default value or a marker token
32+
//
33+
// Marker tokens:
34+
// - ENV_DEFAULT_RESOLVED_IN_CODE("...description...")
35+
// The runtime default is resolved in C++ configuration finalization
36+
// logic. The description is emitted as the "default" field in
37+
// metadata/supported-configurations.json.
38+
#define DD_LIST_ENVIRONMENT_VARIABLES(MACRO) \
39+
MACRO(DD_AGENT_HOST, STRING, "localhost") \
40+
MACRO(DD_ENV, STRING, "") \
41+
MACRO(DD_INSTRUMENTATION_TELEMETRY_ENABLED, BOOLEAN, true) \
42+
MACRO(DD_PROPAGATION_STYLE_EXTRACT, ARRAY, "datadog,tracecontext,baggage") \
43+
MACRO(DD_PROPAGATION_STYLE_INJECT, ARRAY, "datadog,tracecontext,baggage") \
44+
MACRO(DD_REMOTE_CONFIGURATION_ENABLED, BOOLEAN, true) \
45+
MACRO(DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS, DECIMAL, 5.0) \
46+
MACRO(DD_SERVICE, STRING, \
47+
ENV_DEFAULT_RESOLVED_IN_CODE("Defaults to process name when unset.")) \
48+
MACRO(DD_SPAN_SAMPLING_RULES, ARRAY, "[]") \
49+
MACRO(DD_SPAN_SAMPLING_RULES_FILE, STRING, "") \
50+
MACRO(DD_TRACE_PROPAGATION_STYLE_EXTRACT, ARRAY, \
51+
"datadog,tracecontext,baggage") \
52+
MACRO(DD_TRACE_PROPAGATION_STYLE_INJECT, ARRAY, \
53+
"datadog,tracecontext,baggage") \
54+
MACRO(DD_TRACE_PROPAGATION_STYLE, ARRAY, "datadog,tracecontext,baggage") \
55+
MACRO(DD_TAGS, MAP, "") \
56+
MACRO(DD_TRACE_AGENT_PORT, INT, 8126) \
57+
MACRO(DD_TRACE_AGENT_URL, STRING, \
58+
ENV_DEFAULT_RESOLVED_IN_CODE( \
59+
"If unset, built from DD_AGENT_HOST and DD_TRACE_AGENT_PORT, " \
60+
"then defaults to http://localhost:8126.")) \
61+
MACRO(DD_TRACE_DEBUG, BOOLEAN, false) \
62+
MACRO(DD_TRACE_ENABLED, BOOLEAN, true) \
63+
MACRO(DD_TRACE_RATE_LIMIT, DECIMAL, 100.0) \
64+
MACRO(DD_TRACE_REPORT_HOSTNAME, BOOLEAN, false) \
65+
MACRO(DD_TRACE_SAMPLE_RATE, DECIMAL, 1.0) \
66+
MACRO(DD_TRACE_SAMPLING_RULES, ARRAY, "[]") \
67+
MACRO(DD_TRACE_STARTUP_LOGS, BOOLEAN, true) \
68+
MACRO(DD_TRACE_TAGS_PROPAGATION_MAX_LENGTH, INT, 512) \
69+
MACRO(DD_VERSION, STRING, "") \
70+
MACRO(DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED, BOOLEAN, true) \
71+
MACRO(DD_TELEMETRY_HEARTBEAT_INTERVAL, DECIMAL, 10) \
72+
MACRO(DD_TELEMETRY_METRICS_ENABLED, BOOLEAN, true) \
73+
MACRO(DD_TELEMETRY_METRICS_INTERVAL_SECONDS, DECIMAL, 60) \
74+
MACRO(DD_TELEMETRY_DEBUG, BOOLEAN, false) \
75+
MACRO(DD_TRACE_BAGGAGE_MAX_ITEMS, INT, 64) \
76+
MACRO(DD_TRACE_BAGGAGE_MAX_BYTES, INT, 8192) \
77+
MACRO(DD_TELEMETRY_LOG_COLLECTION_ENABLED, BOOLEAN, true) \
78+
MACRO(DD_INSTRUMENTATION_INSTALL_ID, STRING, "") \
79+
MACRO(DD_INSTRUMENTATION_INSTALL_TYPE, STRING, "") \
80+
MACRO(DD_INSTRUMENTATION_INSTALL_TIME, STRING, "") \
81+
MACRO(DD_APM_TRACING_ENABLED, BOOLEAN, true) \
82+
MACRO(DD_TRACE_RESOURCE_RENAMING_ENABLED, BOOLEAN, false) \
83+
MACRO(DD_TRACE_RESOURCE_RENAMING_ALWAYS_SIMPLIFIED_ENDPOINT, BOOLEAN, false) \
84+
MACRO(DD_EXTERNAL_ENV, STRING, "")
85+
86+
#define ENV_DEFAULT_RESOLVED_IN_CODE(X) X
87+
#define WITH_COMMA(ARG, TYPE, DEFAULT_VALUE) ARG,
88+
89+
enum Variable { DD_LIST_ENVIRONMENT_VARIABLES(WITH_COMMA) };
4290

4391
// Quoting a macro argument requires this two-step.
4492
#define QUOTED_IMPL(ARG) #ARG
4593
#define QUOTED(ARG) QUOTED_IMPL(ARG)
4694

47-
#define VARIABLE_SPEC_WITH_COMMA(DATA, NAME, TYPE, DEFAULT_VALUE) \
48-
VariableSpec{StringView{QUOTED(NAME)}, VariableType::TYPE},
49-
50-
inline const VariableSpec variable_specs[] = {
51-
DD_ENVIRONMENT_VARIABLES(VARIABLE_SPEC_WITH_COMMA, ~)};
52-
53-
template <VariableType type>
54-
struct LookupResultByType;
55-
56-
template <>
57-
struct LookupResultByType<VariableType::STRING> {
58-
using type = Optional<StringView>;
59-
};
60-
61-
template <>
62-
struct LookupResultByType<VariableType::BOOLEAN> {
63-
using type = Optional<bool>;
64-
};
65-
66-
template <>
67-
struct LookupResultByType<VariableType::INT> {
68-
using type = Expected<Optional<std::uint64_t>>;
69-
};
95+
#define QUOTED_WITH_COMMA(ARG, TYPE, DEFAULT_VALUE) \
96+
WITH_COMMA(QUOTED(ARG), TYPE, DEFAULT_VALUE)
7097

71-
template <>
72-
struct LookupResultByType<VariableType::DECIMAL> {
73-
using type = Expected<Optional<double>>;
74-
};
98+
inline const char *const variable_names[] = {
99+
DD_LIST_ENVIRONMENT_VARIABLES(QUOTED_WITH_COMMA)};
75100

76-
template <>
77-
struct LookupResultByType<VariableType::ARRAY> {
78-
using type = Optional<StringView>;
79-
};
80-
81-
template <>
82-
struct LookupResultByType<VariableType::MAP> {
83-
using type = Optional<StringView>;
84-
};
85-
86-
template <Variable variable>
87-
struct VariableTraits;
88-
89-
#define VARIABLE_TRAITS_VALUE(DATA, NAME, TYPE, DEFAULT_VALUE) \
90-
template <> \
91-
struct VariableTraits<NAME> { \
92-
static constexpr VariableType variable_type = VariableType::TYPE; \
93-
static constexpr const char *name() { return QUOTED(NAME); } \
94-
using lookup_result = typename LookupResultByType<variable_type>::type; \
95-
};
96-
97-
DD_ENVIRONMENT_VARIABLES(VARIABLE_TRAITS_VALUE, ~)
98-
99-
template <Variable variable>
100-
using LookupResult = typename VariableTraits<variable>::lookup_result;
101-
102-
namespace detail {
103-
template <VariableType>
104-
inline constexpr bool unsupported_variable_type_v = false;
105-
106-
template <Variable variable>
107-
Optional<StringView> lookup_raw() {
108-
const char *value = std::getenv(VariableTraits<variable>::name());
109-
if (!value) {
110-
return nullopt;
111-
}
112-
return StringView{value};
113-
}
114-
115-
Optional<bool> lookup_bool_from_raw(Optional<StringView> value);
116-
Expected<Optional<std::uint64_t>> lookup_uint64_from_raw(
117-
Optional<StringView> value);
118-
Expected<Optional<double>> lookup_double_from_raw(Optional<StringView> value);
119-
} // namespace detail
120-
121-
template <Variable variable>
122-
LookupResult<variable> lookup() {
123-
constexpr VariableType type = VariableTraits<variable>::variable_type;
124-
const auto raw = detail::lookup_raw<variable>();
125-
if constexpr (type == VariableType::STRING || type == VariableType::ARRAY ||
126-
type == VariableType::MAP) {
127-
return raw;
128-
} else if constexpr (type == VariableType::BOOLEAN) {
129-
return detail::lookup_bool_from_raw(raw);
130-
} else if constexpr (type == VariableType::INT) {
131-
return detail::lookup_uint64_from_raw(raw);
132-
} else if constexpr (type == VariableType::DECIMAL) {
133-
return detail::lookup_double_from_raw(raw);
134-
} else {
135-
static_assert(detail::unsupported_variable_type_v<type>,
136-
"Unsupported environment variable type");
137-
}
138-
}
139-
140-
#undef VARIABLE_SPEC_WITH_COMMA
141-
#undef VARIABLE_TRAITS_VALUE
142101
#undef QUOTED
143102
#undef QUOTED_IMPL
144-
#undef VARIABLE_ENUM_VALUE
145-
146-
// Return the metadata for the specified environment `variable`.
147-
const VariableSpec &spec(Variable variable);
103+
#undef WITH_COMMA
104+
#undef ENV_DEFAULT_RESOLVED_IN_CODE
148105

149106
// Return the name of the specified environment `variable`.
150107
StringView name(Variable variable);
151108

109+
// Return the value of the specified environment `variable`, or return
110+
// `nullopt` if that variable is not set in the environment.
111+
Optional<StringView> lookup(Variable variable);
112+
152113
std::string to_json();
153114

154115
} // namespace environment

0 commit comments

Comments
 (0)