Skip to content

Commit 9f5c450

Browse files
BridgeARdmehala
authored andcommitted
chore: add supported configurations
The configuration macro is changed to a registry that includes types and default values next to the configuration names. This is used for compile time generation instead of using runtime checks for the configurations (environment variables). For safety, failing to parse configurations is now going to log a warning instead. This aligns with other platforms / tracers to not crash a customer in production where their staging configuration might be valid and their production one not. The macro must now be used for any new configuration added and a CI job verifies that all entries do exist. If a new env is added otherwise it should fail. The CI will also verify that the generated file is up to date and matches the remote registry. It would fail, if either is not the case. The behavior change is documented in the README.md.
1 parent 32898b5 commit 9f5c450

9 files changed

Lines changed: 632 additions & 95 deletions

File tree

.github/workflows/dev.yml

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: "Development"
22
on: [pull_request, workflow_dispatch, workflow_call]
33

44
jobs:
5-
format:
5+
format-and-verify-configurations:
66
runs-on: ubuntu-22.04-arm
77
container:
88
image: datadog/docker-library:dd-trace-cpp-ci-23768e9-arm64
@@ -12,6 +12,19 @@ jobs:
1212
run: bin/check-format
1313
- name: Shellcheck
1414
run: find bin/ -executable -type f -print0 | xargs -0 shellcheck
15+
- name: Verify environment variable allowlist
16+
run: bin/check-environment-variables
17+
- name: Verify supported configurations metadata
18+
run: |
19+
tmp_dir="$(mktemp -d)"
20+
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
26+
exit 1
27+
fi
1528
1629
build-linux-cmake:
1730
strategy:
@@ -26,7 +39,7 @@ jobs:
2639
- runner: ubuntu-22.04
2740
arch: x64
2841
docker-arch: amd64
29-
needs: format
42+
needs: format-and-verify-configurations
3043
runs-on: ${{ matrix.runner }}
3144
container:
3245
image: datadog/docker-library:dd-trace-cpp-ci-23768e9-${{matrix.docker-arch}}
@@ -54,7 +67,7 @@ jobs:
5467
datadog-ci junit upload --service dd-trace-cpp --tags test.source.file:test/*.cpp .build/report.xml
5568
5669
build-linux-bazel:
57-
needs: format
70+
needs: format-and-verify-configurations
5871
strategy:
5972
fail-fast: false
6073
matrix:
@@ -77,7 +90,7 @@ jobs:
7790
run: bin/with-toolchain ${{ matrix.toolchain }} bazelisk --bazelrc=${{ matrix.bazelrc }} build dd_trace_cpp
7891

7992
build-windows-bazel:
80-
needs: format
93+
needs: format-and-verify-configurations
8194
runs-on: windows-2022
8295
defaults:
8396
run:
@@ -98,7 +111,7 @@ jobs:
98111
run: bazelisk.exe --bazelrc=${{ matrix.bazelrc }} build dd_trace_cpp
99112

100113
build-windows-cmake:
101-
needs: format
114+
needs: format-and-verify-configurations
102115
strategy:
103116
fail-fast: false
104117
matrix:

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ MODULE.bazel.lock
1111
.vscode
1212
.cache/
1313
.cursor/
14-
.DS_Store
14+
.DS_Store
15+
bin/.supported-configurations

.gitlab-ci.yml

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,35 @@
11
stages:
2+
- config-validation
23
- benchmarks
34
- benchmarks-report
45

5-
include: ".gitlab/benchmarks.yml"
6+
variables:
7+
SKIP_SHARED_PIPELINE: "true"
8+
9+
include:
10+
- local: ".gitlab/config-registry.yml"
11+
- local: ".gitlab/benchmarks.yml"
12+
13+
14+
# Config Registry CI Jobs
15+
validate_supported_configurations_v2_local_file:
16+
stage: config-validation
17+
image: registry.ddbuild.io/ci/libdatadog-build/packaging:82290795
18+
tags: ["runner:apm-k8s-tweaked-metal"]
19+
rules:
20+
- when: on_success
21+
extends: .validate_supported_configurations_v2_local_file
22+
variables:
23+
LOCAL_JSON_PATH: "metadata/supported-configurations.json"
24+
BACKFILLED: false
25+
26+
update_central_configurations_version_range_v2:
27+
stage: config-validation
28+
image: registry.ddbuild.io/ci/libdatadog-build/packaging:82290795
29+
tags: ["runner:apm-k8s-tweaked-metal"]
30+
extends: .update_central_configurations_version_range_v2
31+
variables:
32+
LOCAL_REPO_NAME: "dd-trace-cpp"
33+
LOCAL_JSON_PATH: "metadata/supported-configurations.json"
34+
LANGUAGE_NAME: "cpp"
35+
MULTIPLE_RELEASE_LINES: "false"

.gitlab/config-registry.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# This CI jobs are copied from libdatadog-build one-pipeline.yml gitlab template.
2+
# This URL is available in the dd-gitlab/publish-content-addresable-templates job whenever
3+
# a change is made on the one-pipeline template.
4+
variables:
5+
SCRIPTS_BASE_URL: https://gitlab-templates.ddbuild.io/libdatadog/one-pipeline/ca/f14ac28614630d12bcfe6cba4fd8d72dce142c62ff0b053ba7c323622104ebd7/scripts/config-inversion/
6+
7+
.download-scripts-from-template: &download-scripts-from-template
8+
- mkdir -p scripts
9+
- |
10+
for script_file in "config-inversion-local-validation.py" "config-inversion-update-supported-range.py"
11+
do
12+
curl --location --fail --show-error --output "scripts/${script_file}" "${SCRIPTS_BASE_URL}/${script_file}"
13+
chmod +x scripts/$script_file
14+
done
15+
16+
.validate_supported_configurations_v2_local_file:
17+
allow_failure: false
18+
rules:
19+
- when: on_success
20+
variables:
21+
LOCAL_JSON_PATH: ""
22+
BACKFILLED: ""
23+
before_script:
24+
- *download-scripts-from-template
25+
script:
26+
- scripts/config-inversion-local-validation.py
27+
28+
.update_central_configurations_version_range_v2:
29+
allow_failure: false
30+
rules:
31+
- if: '$CI_COMMIT_TAG =~ /^v?[0-9]+\.[0-9]+\.[0-9]+$/'
32+
when: always
33+
variables:
34+
LOCAL_JSON_PATH: ""
35+
LANGUAGE_NAME: ""
36+
MULTIPLE_RELEASE_LINES: "false" # expect "true" or "false" as a value to determine if a new "branch" identifier is needed to differentiate between multiple release lines
37+
before_script:
38+
- *download-scripts-from-template
39+
- export FP_API_KEY=$(aws ssm get-parameter --region us-east-1 --name ci.$CI_PROJECT_NAME.FP_API_KEY --with-decryption --query "Parameter.Value" --out text)
40+
script:
41+
- scripts/config-inversion-update-supported-range.py

include/datadog/environment.h

Lines changed: 119 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -6,91 +6,149 @@
66
// Each `enum Variable` denotes an environment variable. The enum value names
77
// are the same as the names of the environment variables.
88
//
9-
// `variable_names` is an array of the names of the environment variables. Nginx
10-
// uses `variable_names` as an allow list of environment variables to forward to
11-
// worker processes.
12-
//
139
// `name` returns the name of a specified `Variable`.
1410
//
1511
// `lookup` retrieves the value of `Variable` in the environment.
1612

13+
#include <datadog/environment_registry.h>
14+
#include <datadog/expected.h>
1715
#include <datadog/optional.h>
1816
#include <datadog/string_view.h>
1917

18+
#include <cstdint>
19+
#include <cstdlib>
20+
2021
namespace datadog {
2122
namespace tracing {
2223
namespace environment {
2324

24-
// To enforce correspondence between `enum Variable` and `variable_names`, the
25-
// preprocessor is used so that the DD_* symbols are listed exactly once.
26-
#define LIST_ENVIRONMENT_VARIABLES(MACRO) \
27-
MACRO(DD_AGENT_HOST) \
28-
MACRO(DD_ENV) \
29-
MACRO(DD_INSTRUMENTATION_TELEMETRY_ENABLED) \
30-
MACRO(DD_PROPAGATION_STYLE_EXTRACT) \
31-
MACRO(DD_PROPAGATION_STYLE_INJECT) \
32-
MACRO(DD_REMOTE_CONFIGURATION_ENABLED) \
33-
MACRO(DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS) \
34-
MACRO(DD_SERVICE) \
35-
MACRO(DD_SPAN_SAMPLING_RULES) \
36-
MACRO(DD_SPAN_SAMPLING_RULES_FILE) \
37-
MACRO(DD_TRACE_PROPAGATION_STYLE_EXTRACT) \
38-
MACRO(DD_TRACE_PROPAGATION_STYLE_INJECT) \
39-
MACRO(DD_TRACE_PROPAGATION_STYLE) \
40-
MACRO(DD_TAGS) \
41-
MACRO(DD_TRACE_AGENT_PORT) \
42-
MACRO(DD_TRACE_AGENT_URL) \
43-
MACRO(DD_TRACE_DEBUG) \
44-
MACRO(DD_TRACE_ENABLED) \
45-
MACRO(DD_TRACE_RATE_LIMIT) \
46-
MACRO(DD_TRACE_REPORT_HOSTNAME) \
47-
MACRO(DD_TRACE_SAMPLE_RATE) \
48-
MACRO(DD_TRACE_SAMPLING_RULES) \
49-
MACRO(DD_TRACE_STARTUP_LOGS) \
50-
MACRO(DD_TRACE_TAGS_PROPAGATION_MAX_LENGTH) \
51-
MACRO(DD_VERSION) \
52-
MACRO(DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED) \
53-
MACRO(DD_TELEMETRY_HEARTBEAT_INTERVAL) \
54-
MACRO(DD_TELEMETRY_METRICS_ENABLED) \
55-
MACRO(DD_TELEMETRY_METRICS_INTERVAL_SECONDS) \
56-
MACRO(DD_TELEMETRY_DEBUG) \
57-
MACRO(DD_TRACE_BAGGAGE_MAX_ITEMS) \
58-
MACRO(DD_TRACE_BAGGAGE_MAX_BYTES) \
59-
MACRO(DD_TELEMETRY_LOG_COLLECTION_ENABLED) \
60-
MACRO(DD_INSTRUMENTATION_INSTALL_ID) \
61-
MACRO(DD_INSTRUMENTATION_INSTALL_TYPE) \
62-
MACRO(DD_INSTRUMENTATION_INSTALL_TIME) \
63-
MACRO(DD_APM_TRACING_ENABLED) \
64-
MACRO(DD_TRACE_RESOURCE_RENAMING_ENABLED) \
65-
MACRO(DD_TRACE_RESOURCE_RENAMING_ALWAYS_SIMPLIFIED_ENDPOINT) \
66-
MACRO(DD_EXTERNAL_ENV)
67-
68-
#define WITH_COMMA(ARG) ARG,
69-
70-
enum Variable { LIST_ENVIRONMENT_VARIABLES(WITH_COMMA) };
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, ~) };
7142

7243
// Quoting a macro argument requires this two-step.
7344
#define QUOTED_IMPL(ARG) #ARG
7445
#define QUOTED(ARG) QUOTED_IMPL(ARG)
7546

76-
#define QUOTED_WITH_COMMA(ARG) WITH_COMMA(QUOTED(ARG))
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+
};
70+
71+
template <>
72+
struct LookupResultByType<VariableType::DECIMAL> {
73+
using type = Expected<Optional<double>>;
74+
};
7775

78-
inline const char *const variable_names[] = {
79-
LIST_ENVIRONMENT_VARIABLES(QUOTED_WITH_COMMA)};
76+
template <>
77+
struct LookupResultByType<VariableType::ARRAY> {
78+
using type = Optional<StringView>;
79+
};
8080

81-
#undef QUOTED_WITH_COMMA
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
82142
#undef QUOTED
83143
#undef QUOTED_IMPL
84-
#undef WITH_COMMA
85-
#undef LIST_ENVIRONMENT_VARIABLES
144+
#undef VARIABLE_ENUM_VALUE
145+
146+
// Return the metadata for the specified environment `variable`.
147+
const VariableSpec &spec(Variable variable);
86148

87149
// Return the name of the specified environment `variable`.
88150
StringView name(Variable variable);
89151

90-
// Return the value of the specified environment `variable`, or return
91-
// `nullopt` if that variable is not set in the environment.
92-
Optional<StringView> lookup(Variable variable);
93-
94152
std::string to_json();
95153

96154
} // namespace environment

0 commit comments

Comments
 (0)