From 9f5c450c12f8f3611da3f9284b8904d382ad2cd3 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Thu, 26 Feb 2026 16:14:41 +0100 Subject: [PATCH 1/3] 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. --- .github/workflows/dev.yml | 23 +- .gitignore | 3 +- .gitlab-ci.yml | 32 ++- .gitlab/config-registry.yml | 41 ++++ include/datadog/environment.h | 180 ++++++++++------ include/datadog/environment_registry.h | 71 ++++++ metadata/supported-configurations.json | 286 +++++++++++++++++++++++++ src/datadog/datadog_agent_config.cpp | 42 ++-- src/datadog/environment.cpp | 49 ++++- 9 files changed, 632 insertions(+), 95 deletions(-) create mode 100644 .gitlab/config-registry.yml create mode 100644 include/datadog/environment_registry.h create mode 100644 metadata/supported-configurations.json diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index 9c65e53f..2ae86d68 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -2,7 +2,7 @@ name: "Development" on: [pull_request, workflow_dispatch, workflow_call] jobs: - format: + format-and-verify-configurations: runs-on: ubuntu-22.04-arm container: image: datadog/docker-library:dd-trace-cpp-ci-23768e9-arm64 @@ -12,6 +12,19 @@ jobs: run: bin/check-format - name: Shellcheck run: find bin/ -executable -type f -print0 | xargs -0 shellcheck + - name: Verify environment variable allowlist + run: bin/check-environment-variables + - name: Verify supported configurations metadata + run: | + tmp_dir="$(mktemp -d)" + trap 'rm -rf "$tmp_dir"' EXIT + cp metadata/supported-configurations.json "$tmp_dir/supported-configurations.json" + bin/generate-supported-configurations + if ! diff -q "$tmp_dir/supported-configurations.json" metadata/supported-configurations.json >/dev/null 2>&1; then + echo "ERROR: metadata/supported-configurations.json got out of sync with implemented configurations. Please run bin/generate-supported-configurations locally." + diff -u "$tmp_dir/supported-configurations.json" metadata/supported-configurations.json || true + exit 1 + fi build-linux-cmake: strategy: @@ -26,7 +39,7 @@ jobs: - runner: ubuntu-22.04 arch: x64 docker-arch: amd64 - needs: format + needs: format-and-verify-configurations runs-on: ${{ matrix.runner }} container: image: datadog/docker-library:dd-trace-cpp-ci-23768e9-${{matrix.docker-arch}} @@ -54,7 +67,7 @@ jobs: datadog-ci junit upload --service dd-trace-cpp --tags test.source.file:test/*.cpp .build/report.xml build-linux-bazel: - needs: format + needs: format-and-verify-configurations strategy: fail-fast: false matrix: @@ -77,7 +90,7 @@ jobs: run: bin/with-toolchain ${{ matrix.toolchain }} bazelisk --bazelrc=${{ matrix.bazelrc }} build dd_trace_cpp build-windows-bazel: - needs: format + needs: format-and-verify-configurations runs-on: windows-2022 defaults: run: @@ -98,7 +111,7 @@ jobs: run: bazelisk.exe --bazelrc=${{ matrix.bazelrc }} build dd_trace_cpp build-windows-cmake: - needs: format + needs: format-and-verify-configurations strategy: fail-fast: false matrix: diff --git a/.gitignore b/.gitignore index 60c94744..409fd98a 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,5 @@ MODULE.bazel.lock .vscode .cache/ .cursor/ -.DS_Store \ No newline at end of file +.DS_Store +bin/.supported-configurations \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7f9babbc..5978566f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,5 +1,35 @@ stages: + - config-validation - benchmarks - benchmarks-report -include: ".gitlab/benchmarks.yml" +variables: + SKIP_SHARED_PIPELINE: "true" + +include: + - local: ".gitlab/config-registry.yml" + - local: ".gitlab/benchmarks.yml" + + +# Config Registry CI Jobs +validate_supported_configurations_v2_local_file: + stage: config-validation + image: registry.ddbuild.io/ci/libdatadog-build/packaging:82290795 + tags: ["runner:apm-k8s-tweaked-metal"] + rules: + - when: on_success + extends: .validate_supported_configurations_v2_local_file + variables: + LOCAL_JSON_PATH: "metadata/supported-configurations.json" + BACKFILLED: false + +update_central_configurations_version_range_v2: + stage: config-validation + image: registry.ddbuild.io/ci/libdatadog-build/packaging:82290795 + tags: ["runner:apm-k8s-tweaked-metal"] + extends: .update_central_configurations_version_range_v2 + variables: + LOCAL_REPO_NAME: "dd-trace-cpp" + LOCAL_JSON_PATH: "metadata/supported-configurations.json" + LANGUAGE_NAME: "cpp" + MULTIPLE_RELEASE_LINES: "false" \ No newline at end of file diff --git a/.gitlab/config-registry.yml b/.gitlab/config-registry.yml new file mode 100644 index 00000000..1d3bf2f3 --- /dev/null +++ b/.gitlab/config-registry.yml @@ -0,0 +1,41 @@ +# This CI jobs are copied from libdatadog-build one-pipeline.yml gitlab template. +# This URL is available in the dd-gitlab/publish-content-addresable-templates job whenever +# a change is made on the one-pipeline template. +variables: + SCRIPTS_BASE_URL: https://gitlab-templates.ddbuild.io/libdatadog/one-pipeline/ca/f14ac28614630d12bcfe6cba4fd8d72dce142c62ff0b053ba7c323622104ebd7/scripts/config-inversion/ + +.download-scripts-from-template: &download-scripts-from-template + - mkdir -p scripts + - | + for script_file in "config-inversion-local-validation.py" "config-inversion-update-supported-range.py" + do + curl --location --fail --show-error --output "scripts/${script_file}" "${SCRIPTS_BASE_URL}/${script_file}" + chmod +x scripts/$script_file + done + +.validate_supported_configurations_v2_local_file: + allow_failure: false + rules: + - when: on_success + variables: + LOCAL_JSON_PATH: "" + BACKFILLED: "" + before_script: + - *download-scripts-from-template + script: + - scripts/config-inversion-local-validation.py + +.update_central_configurations_version_range_v2: + allow_failure: false + rules: + - if: '$CI_COMMIT_TAG =~ /^v?[0-9]+\.[0-9]+\.[0-9]+$/' + when: always + variables: + LOCAL_JSON_PATH: "" + LANGUAGE_NAME: "" + 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 + before_script: + - *download-scripts-from-template + - 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) + script: + - scripts/config-inversion-update-supported-range.py \ No newline at end of file diff --git a/include/datadog/environment.h b/include/datadog/environment.h index 358d0bcb..baa33f58 100644 --- a/include/datadog/environment.h +++ b/include/datadog/environment.h @@ -6,91 +6,149 @@ // Each `enum Variable` denotes an environment variable. The enum value names // are the same as the names of the environment variables. // -// `variable_names` is an array of the names of the environment variables. Nginx -// uses `variable_names` as an allow list of environment variables to forward to -// worker processes. -// // `name` returns the name of a specified `Variable`. // // `lookup` retrieves the value of `Variable` in the environment. +#include +#include #include #include +#include +#include + namespace datadog { namespace tracing { namespace environment { -// To enforce correspondence between `enum Variable` and `variable_names`, the -// preprocessor is used so that the DD_* symbols are listed exactly once. -#define LIST_ENVIRONMENT_VARIABLES(MACRO) \ - MACRO(DD_AGENT_HOST) \ - MACRO(DD_ENV) \ - MACRO(DD_INSTRUMENTATION_TELEMETRY_ENABLED) \ - MACRO(DD_PROPAGATION_STYLE_EXTRACT) \ - MACRO(DD_PROPAGATION_STYLE_INJECT) \ - MACRO(DD_REMOTE_CONFIGURATION_ENABLED) \ - MACRO(DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS) \ - MACRO(DD_SERVICE) \ - MACRO(DD_SPAN_SAMPLING_RULES) \ - MACRO(DD_SPAN_SAMPLING_RULES_FILE) \ - MACRO(DD_TRACE_PROPAGATION_STYLE_EXTRACT) \ - MACRO(DD_TRACE_PROPAGATION_STYLE_INJECT) \ - MACRO(DD_TRACE_PROPAGATION_STYLE) \ - MACRO(DD_TAGS) \ - MACRO(DD_TRACE_AGENT_PORT) \ - MACRO(DD_TRACE_AGENT_URL) \ - MACRO(DD_TRACE_DEBUG) \ - MACRO(DD_TRACE_ENABLED) \ - MACRO(DD_TRACE_RATE_LIMIT) \ - MACRO(DD_TRACE_REPORT_HOSTNAME) \ - MACRO(DD_TRACE_SAMPLE_RATE) \ - MACRO(DD_TRACE_SAMPLING_RULES) \ - MACRO(DD_TRACE_STARTUP_LOGS) \ - MACRO(DD_TRACE_TAGS_PROPAGATION_MAX_LENGTH) \ - MACRO(DD_VERSION) \ - MACRO(DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED) \ - MACRO(DD_TELEMETRY_HEARTBEAT_INTERVAL) \ - 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) \ - MACRO(DD_INSTRUMENTATION_INSTALL_ID) \ - MACRO(DD_INSTRUMENTATION_INSTALL_TYPE) \ - MACRO(DD_INSTRUMENTATION_INSTALL_TIME) \ - MACRO(DD_APM_TRACING_ENABLED) \ - MACRO(DD_TRACE_RESOURCE_RENAMING_ENABLED) \ - MACRO(DD_TRACE_RESOURCE_RENAMING_ALWAYS_SIMPLIFIED_ENDPOINT) \ - MACRO(DD_EXTERNAL_ENV) - -#define WITH_COMMA(ARG) ARG, - -enum Variable { LIST_ENVIRONMENT_VARIABLES(WITH_COMMA) }; +enum class VariableType { + STRING, + BOOLEAN, + INT, + DECIMAL, + ARRAY, + MAP, +}; + +struct VariableSpec { + StringView name; + VariableType type; +}; + +#define VARIABLE_ENUM_VALUE(DATA, NAME, TYPE, DEFAULT_VALUE) NAME, + +enum Variable { DD_ENVIRONMENT_VARIABLES(VARIABLE_ENUM_VALUE, ~) }; // Quoting a macro argument requires this two-step. #define QUOTED_IMPL(ARG) #ARG #define QUOTED(ARG) QUOTED_IMPL(ARG) -#define QUOTED_WITH_COMMA(ARG) WITH_COMMA(QUOTED(ARG)) +#define VARIABLE_SPEC_WITH_COMMA(DATA, NAME, TYPE, DEFAULT_VALUE) \ + VariableSpec{StringView{QUOTED(NAME)}, VariableType::TYPE}, + +inline const VariableSpec variable_specs[] = { + DD_ENVIRONMENT_VARIABLES(VARIABLE_SPEC_WITH_COMMA, ~)}; + +template +struct LookupResultByType; + +template <> +struct LookupResultByType { + using type = Optional; +}; + +template <> +struct LookupResultByType { + using type = Optional; +}; + +template <> +struct LookupResultByType { + using type = Expected>; +}; + +template <> +struct LookupResultByType { + using type = Expected>; +}; -inline const char *const variable_names[] = { - LIST_ENVIRONMENT_VARIABLES(QUOTED_WITH_COMMA)}; +template <> +struct LookupResultByType { + using type = Optional; +}; -#undef QUOTED_WITH_COMMA +template <> +struct LookupResultByType { + using type = Optional; +}; + +template +struct VariableTraits; + +#define VARIABLE_TRAITS_VALUE(DATA, NAME, TYPE, DEFAULT_VALUE) \ + template <> \ + struct VariableTraits { \ + static constexpr VariableType variable_type = VariableType::TYPE; \ + static constexpr const char *name() { return QUOTED(NAME); } \ + using lookup_result = typename LookupResultByType::type; \ + }; + +DD_ENVIRONMENT_VARIABLES(VARIABLE_TRAITS_VALUE, ~) + +template +using LookupResult = typename VariableTraits::lookup_result; + +namespace detail { +template +inline constexpr bool unsupported_variable_type_v = false; + +template +Optional lookup_raw() { + const char *value = std::getenv(VariableTraits::name()); + if (!value) { + return nullopt; + } + return StringView{value}; +} + +Optional lookup_bool_from_raw(Optional value); +Expected> lookup_uint64_from_raw( + Optional value); +Expected> lookup_double_from_raw(Optional value); +} // namespace detail + +template +LookupResult lookup() { + constexpr VariableType type = VariableTraits::variable_type; + const auto raw = detail::lookup_raw(); + if constexpr (type == VariableType::STRING || type == VariableType::ARRAY || + type == VariableType::MAP) { + return raw; + } else if constexpr (type == VariableType::BOOLEAN) { + return detail::lookup_bool_from_raw(raw); + } else if constexpr (type == VariableType::INT) { + return detail::lookup_uint64_from_raw(raw); + } else if constexpr (type == VariableType::DECIMAL) { + return detail::lookup_double_from_raw(raw); + } else { + static_assert(detail::unsupported_variable_type_v, + "Unsupported environment variable type"); + } +} + +#undef VARIABLE_SPEC_WITH_COMMA +#undef VARIABLE_TRAITS_VALUE #undef QUOTED #undef QUOTED_IMPL -#undef WITH_COMMA -#undef LIST_ENVIRONMENT_VARIABLES +#undef VARIABLE_ENUM_VALUE + +// Return the metadata for the specified environment `variable`. +const VariableSpec &spec(Variable variable); // Return the name of the specified environment `variable`. 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 lookup(Variable variable); - std::string to_json(); } // namespace environment diff --git a/include/datadog/environment_registry.h b/include/datadog/environment_registry.h new file mode 100644 index 00000000..54118e29 --- /dev/null +++ b/include/datadog/environment_registry.h @@ -0,0 +1,71 @@ +#pragma once + +// Central registry for supported environment variables. +// All configurations must be registered here. +// +// This registry is the single source of truth for: +// - env variable name allowlist (`include/datadog/environment.h`) +// - generated metadata (`metadata/supported-configurations.json`) +// +// Each entry has: +// - NAME: environment variable symbol (e.g. DD_SERVICE) +// - TYPE: STRING | BOOLEAN | INT | DECIMAL | ARRAY | MAP +// - DEFAULT: literal default value or a marker token +// +// Marker tokens: +// - ENV_DEFAULT_RESOLVED_IN_CODE("...description...") +// The runtime default is resolved in C++ configuration finalization +// logic. The description is emitted as the "default" field in +// metadata/supported-configurations.json. + +#define DD_ENVIRONMENT_VARIABLES(MACRO, DATA) \ + MACRO(DATA, DD_AGENT_HOST, STRING, "localhost") \ + MACRO(DATA, DD_ENV, STRING, "") \ + MACRO(DATA, DD_INSTRUMENTATION_TELEMETRY_ENABLED, BOOLEAN, true) \ + MACRO(DATA, DD_PROPAGATION_STYLE_EXTRACT, ARRAY, \ + "datadog,tracecontext,baggage") \ + MACRO(DATA, DD_PROPAGATION_STYLE_INJECT, ARRAY, \ + "datadog,tracecontext,baggage") \ + MACRO(DATA, DD_REMOTE_CONFIGURATION_ENABLED, BOOLEAN, true) \ + MACRO(DATA, DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS, DECIMAL, 5.0) \ + MACRO(DATA, DD_SERVICE, STRING, \ + ENV_DEFAULT_RESOLVED_IN_CODE("Defaults to process name when unset.")) \ + MACRO(DATA, DD_SPAN_SAMPLING_RULES, ARRAY, "[]") \ + MACRO(DATA, DD_SPAN_SAMPLING_RULES_FILE, STRING, "") \ + MACRO(DATA, DD_TRACE_PROPAGATION_STYLE_EXTRACT, ARRAY, \ + "datadog,tracecontext,baggage") \ + MACRO(DATA, DD_TRACE_PROPAGATION_STYLE_INJECT, ARRAY, \ + "datadog,tracecontext,baggage") \ + MACRO(DATA, DD_TRACE_PROPAGATION_STYLE, ARRAY, \ + "datadog,tracecontext,baggage") \ + MACRO(DATA, DD_TAGS, MAP, "") \ + MACRO(DATA, DD_TRACE_AGENT_PORT, INT, 8126) \ + MACRO(DATA, DD_TRACE_AGENT_URL, STRING, \ + ENV_DEFAULT_RESOLVED_IN_CODE( \ + "If unset, built from DD_AGENT_HOST and DD_TRACE_AGENT_PORT, " \ + "then defaults to http://localhost:8126.")) \ + MACRO(DATA, DD_TRACE_DEBUG, BOOLEAN, false) \ + MACRO(DATA, DD_TRACE_ENABLED, BOOLEAN, true) \ + MACRO(DATA, DD_TRACE_RATE_LIMIT, DECIMAL, 100.0) \ + MACRO(DATA, DD_TRACE_REPORT_HOSTNAME, BOOLEAN, false) \ + MACRO(DATA, DD_TRACE_SAMPLE_RATE, DECIMAL, 1.0) \ + MACRO(DATA, DD_TRACE_SAMPLING_RULES, ARRAY, "[]") \ + MACRO(DATA, DD_TRACE_STARTUP_LOGS, BOOLEAN, true) \ + MACRO(DATA, DD_TRACE_TAGS_PROPAGATION_MAX_LENGTH, INT, 512) \ + MACRO(DATA, DD_VERSION, STRING, "") \ + MACRO(DATA, DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED, BOOLEAN, true) \ + MACRO(DATA, DD_TELEMETRY_HEARTBEAT_INTERVAL, DECIMAL, 10) \ + MACRO(DATA, DD_TELEMETRY_METRICS_ENABLED, BOOLEAN, true) \ + MACRO(DATA, DD_TELEMETRY_METRICS_INTERVAL_SECONDS, DECIMAL, 60) \ + MACRO(DATA, DD_TELEMETRY_DEBUG, BOOLEAN, false) \ + MACRO(DATA, DD_TRACE_BAGGAGE_MAX_ITEMS, INT, 64) \ + MACRO(DATA, DD_TRACE_BAGGAGE_MAX_BYTES, INT, 8192) \ + MACRO(DATA, DD_TELEMETRY_LOG_COLLECTION_ENABLED, BOOLEAN, true) \ + MACRO(DATA, DD_INSTRUMENTATION_INSTALL_ID, STRING, "") \ + MACRO(DATA, DD_INSTRUMENTATION_INSTALL_TYPE, STRING, "") \ + MACRO(DATA, DD_INSTRUMENTATION_INSTALL_TIME, STRING, "") \ + MACRO(DATA, DD_APM_TRACING_ENABLED, BOOLEAN, true) \ + MACRO(DATA, DD_TRACE_RESOURCE_RENAMING_ENABLED, BOOLEAN, false) \ + MACRO(DATA, DD_TRACE_RESOURCE_RENAMING_ALWAYS_SIMPLIFIED_ENDPOINT, BOOLEAN, \ + false) \ + MACRO(DATA, DD_EXTERNAL_ENV, STRING, "") diff --git a/metadata/supported-configurations.json b/metadata/supported-configurations.json new file mode 100644 index 00000000..1a67bfac --- /dev/null +++ b/metadata/supported-configurations.json @@ -0,0 +1,286 @@ +{ + "deprecations": {}, + "supportedConfigurations": { + "DD_AGENT_HOST": [ + { + "default": "localhost", + "implementation": "A", + "type": "string" + } + ], + "DD_APM_TRACING_ENABLED": [ + { + "default": "true", + "implementation": "A", + "type": "boolean" + } + ], + "DD_ENV": [ + { + "default": "", + "implementation": "A", + "type": "string" + } + ], + "DD_EXTERNAL_ENV": [ + { + "default": "", + "implementation": "A", + "type": "string" + } + ], + "DD_INSTRUMENTATION_INSTALL_ID": [ + { + "default": "", + "implementation": "A", + "type": "string" + } + ], + "DD_INSTRUMENTATION_INSTALL_TIME": [ + { + "default": "", + "implementation": "A", + "type": "string" + } + ], + "DD_INSTRUMENTATION_INSTALL_TYPE": [ + { + "default": "", + "implementation": "A", + "type": "string" + } + ], + "DD_INSTRUMENTATION_TELEMETRY_ENABLED": [ + { + "default": "true", + "implementation": "A", + "type": "boolean" + } + ], + "DD_PROPAGATION_STYLE_EXTRACT": [ + { + "default": "datadog,tracecontext,baggage", + "implementation": "A", + "type": "array" + } + ], + "DD_PROPAGATION_STYLE_INJECT": [ + { + "default": "datadog,tracecontext,baggage", + "implementation": "A", + "type": "array" + } + ], + "DD_REMOTE_CONFIGURATION_ENABLED": [ + { + "default": "true", + "implementation": "A", + "type": "boolean" + } + ], + "DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS": [ + { + "default": "5.0", + "implementation": "A", + "type": "decimal" + } + ], + "DD_SERVICE": [ + { + "default": "Defaults to process name when unset.", + "implementation": "A", + "type": "string" + } + ], + "DD_SPAN_SAMPLING_RULES": [ + { + "default": "[]", + "implementation": "A", + "type": "array" + } + ], + "DD_SPAN_SAMPLING_RULES_FILE": [ + { + "default": "", + "implementation": "A", + "type": "string" + } + ], + "DD_TAGS": [ + { + "default": "", + "implementation": "A", + "type": "map" + } + ], + "DD_TELEMETRY_DEBUG": [ + { + "default": "false", + "implementation": "A", + "type": "boolean" + } + ], + "DD_TELEMETRY_HEARTBEAT_INTERVAL": [ + { + "default": "10", + "implementation": "A", + "type": "decimal" + } + ], + "DD_TELEMETRY_LOG_COLLECTION_ENABLED": [ + { + "default": "true", + "implementation": "A", + "type": "boolean" + } + ], + "DD_TELEMETRY_METRICS_ENABLED": [ + { + "default": "true", + "implementation": "A", + "type": "boolean" + } + ], + "DD_TELEMETRY_METRICS_INTERVAL_SECONDS": [ + { + "default": "60", + "implementation": "A", + "type": "decimal" + } + ], + "DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED": [ + { + "default": "true", + "implementation": "A", + "type": "boolean" + } + ], + "DD_TRACE_AGENT_PORT": [ + { + "default": "8126", + "implementation": "A", + "type": "int" + } + ], + "DD_TRACE_AGENT_URL": [ + { + "default": "If unset, built from DD_AGENT_HOST and DD_TRACE_AGENT_PORT, then defaults to http://localhost:8126.", + "implementation": "A", + "type": "string" + } + ], + "DD_TRACE_BAGGAGE_MAX_BYTES": [ + { + "default": "8192", + "implementation": "A", + "type": "int" + } + ], + "DD_TRACE_BAGGAGE_MAX_ITEMS": [ + { + "default": "64", + "implementation": "A", + "type": "int" + } + ], + "DD_TRACE_DEBUG": [ + { + "default": "false", + "implementation": "A", + "type": "boolean" + } + ], + "DD_TRACE_ENABLED": [ + { + "default": "true", + "implementation": "A", + "type": "boolean" + } + ], + "DD_TRACE_PROPAGATION_STYLE": [ + { + "default": "datadog,tracecontext,baggage", + "implementation": "A", + "type": "array" + } + ], + "DD_TRACE_PROPAGATION_STYLE_EXTRACT": [ + { + "default": "datadog,tracecontext,baggage", + "implementation": "A", + "type": "array" + } + ], + "DD_TRACE_PROPAGATION_STYLE_INJECT": [ + { + "default": "datadog,tracecontext,baggage", + "implementation": "A", + "type": "array" + } + ], + "DD_TRACE_RATE_LIMIT": [ + { + "default": "100.0", + "implementation": "A", + "type": "decimal" + } + ], + "DD_TRACE_REPORT_HOSTNAME": [ + { + "default": "false", + "implementation": "A", + "type": "boolean" + } + ], + "DD_TRACE_RESOURCE_RENAMING_ALWAYS_SIMPLIFIED_ENDPOINT": [ + { + "default": "false", + "implementation": "A", + "type": "boolean" + } + ], + "DD_TRACE_RESOURCE_RENAMING_ENABLED": [ + { + "default": "false", + "implementation": "A", + "type": "boolean" + } + ], + "DD_TRACE_SAMPLE_RATE": [ + { + "default": "1.0", + "implementation": "A", + "type": "decimal" + } + ], + "DD_TRACE_SAMPLING_RULES": [ + { + "default": "[]", + "implementation": "A", + "type": "array" + } + ], + "DD_TRACE_STARTUP_LOGS": [ + { + "default": "true", + "implementation": "A", + "type": "boolean" + } + ], + "DD_TRACE_TAGS_PROPAGATION_MAX_LENGTH": [ + { + "default": "512", + "implementation": "A", + "type": "int" + } + ], + "DD_VERSION": [ + { + "default": "", + "implementation": "A", + "type": "string" + } + ] + }, + "version": "2" +} diff --git a/src/datadog/datadog_agent_config.cpp b/src/datadog/datadog_agent_config.cpp index 05b3b065..1dfc11d4 100644 --- a/src/datadog/datadog_agent_config.cpp +++ b/src/datadog/datadog_agent_config.cpp @@ -1,46 +1,54 @@ #include #include +#include #include #include #include +#include #include "default_http_client.h" -#include "parse_util.h" #include "platform_util.h" #include "threaded_event_scheduler.h" namespace datadog { namespace tracing { +namespace env = environment; + Expected load_datadog_agent_env_config() { DatadogAgentConfig env_config; - if (auto rc_enabled = lookup(environment::DD_REMOTE_CONFIGURATION_ENABLED)) { - env_config.remote_configuration_enabled = !falsy(*rc_enabled); + if (auto rc_enabled = env::lookup()) { + env_config.remote_configuration_enabled = *rc_enabled; } - if (auto raw_rc_poll_interval_value = - lookup(environment::DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS)) { - auto res = parse_double(*raw_rc_poll_interval_value); - if (auto error = res.if_error()) { - return error->with_prefix( - "DatadogAgent: Remote Configuration poll interval error "); - } - - env_config.remote_configuration_poll_interval_seconds = *res; + auto raw_rc_poll_interval_value = + env::lookup(); + if (auto error = raw_rc_poll_interval_value.if_error()) { + return error->with_prefix( + "DatadogAgent: Remote Configuration poll interval error "); + } else if (*raw_rc_poll_interval_value) { + env_config.remote_configuration_poll_interval_seconds = + **raw_rc_poll_interval_value; } - auto env_host = lookup(environment::DD_AGENT_HOST); - auto env_port = lookup(environment::DD_TRACE_AGENT_PORT); + const auto env_host = env::lookup(); + Optional env_port = nullopt; + const auto raw_env_port = env::lookup(); + if (auto* error = raw_env_port.if_error()) { + return error->with_prefix("DatadogAgent: Agent port parsing error "); + } else { + env_port = *raw_env_port; + } - if (auto url_env = lookup(environment::DD_TRACE_AGENT_URL)) { + if (auto url_env = env::lookup()) { env_config.url = std::string{*url_env}; } else if (env_host || env_port) { std::string configured_url = "http://"; append(configured_url, env_host.value_or("localhost")); configured_url += ':'; - append(configured_url, env_port.value_or("8126")); + configured_url += std::to_string(env_port.value_or(8126)); env_config.url = std::move(configured_url); } @@ -148,7 +156,7 @@ Expected finalize_config( // Starting Datadog Agent 7.62.0, the admission controller inject a unique // identifier through `DD_EXTERNAL_ENV`. This uid is used for origin // detection. - if (auto external_env = lookup(environment::DD_EXTERNAL_ENV)) { + if (auto external_env = env::lookup()) { result.admission_controller_uid = std::string(*external_env); } diff --git a/src/datadog/environment.cpp b/src/datadog/environment.cpp index 4dc3eb3f..c48c9de8 100644 --- a/src/datadog/environment.cpp +++ b/src/datadog/environment.cpp @@ -3,31 +3,60 @@ #include #include "json.hpp" +#include "parse_util.h" namespace datadog { namespace tracing { namespace environment { -StringView name(Variable variable) { return variable_names[variable]; } +namespace detail { +Optional lookup_bool_from_raw(Optional value) { + if (value) { + return !falsy(*value); + } + return nullopt; +} + +Expected> lookup_uint64_from_raw( + Optional value) { + if (!value) { + return Optional{}; + } + auto parsed = parse_uint64(*value, 10); + if (auto *error = parsed.if_error()) { + return *error; + } + return Optional{*parsed}; +} -Optional lookup(Variable variable) { - const char *name = variable_names[variable]; - const char *value = std::getenv(name); +Expected> lookup_double_from_raw(Optional value) { if (!value) { - return nullopt; + return Optional{}; + } + auto parsed = parse_double(*value); + if (auto *error = parsed.if_error()) { + return *error; } - return StringView{value}; + return Optional{*parsed}; } +} // namespace detail + +const VariableSpec &spec(Variable variable) { return variable_specs[variable]; } + +StringView name(Variable variable) { return spec(variable).name; } std::string to_json() { auto result = nlohmann::json::object({}); - for (const char *name : variable_names) { - if (const char *value = std::getenv(name)) { - result[name] = value; - } +#define ADD_ENV_TO_JSON_IF_SET(DATA, NAME, TYPE, DEFAULT_VALUE) \ + if (const char *value = std::getenv(VariableTraits::name())) { \ + result[VariableTraits::name()] = value; \ } + DD_ENVIRONMENT_VARIABLES(ADD_ENV_TO_JSON_IF_SET, ~) + +#undef ADD_ENV_TO_JSON_IF_SET + return result.dump(); } From 9e5b88ab9c6c9dce294f88e0cad58a8ef2551eb9 Mon Sep 17 00:00:00 2001 From: Damien Mehala Date: Thu, 26 Feb 2026 21:12:39 +0100 Subject: [PATCH 2/3] rework config inversion --- .github/workflows/dev.yml | 27 +- .gitignore | 1 - .gitlab-ci.yml | 6 +- CMakeLists.txt | 6 + CMakePresets.json | 2 + bin/check-environment-variables | 19 ++ cmake/deps/cxxopts.cmake | 11 + include/datadog/environment.h | 199 ++++++-------- include/datadog/environment_registry.h | 71 ----- metadata/supported-configurations.json | 286 ------------------- src/datadog/datadog_agent_config.cpp | 42 ++- src/datadog/environment.cpp | 49 +--- supported-configurations.json | 366 +++++++++++++++++++++++++ tools/config-inversion/CMakeLists.txt | 19 ++ tools/config-inversion/main.cpp | 80 ++++++ 15 files changed, 629 insertions(+), 555 deletions(-) create mode 100755 bin/check-environment-variables create mode 100644 cmake/deps/cxxopts.cmake delete mode 100644 include/datadog/environment_registry.h delete mode 100644 metadata/supported-configurations.json create mode 100644 supported-configurations.json create mode 100644 tools/config-inversion/CMakeLists.txt create mode 100644 tools/config-inversion/main.cpp diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index 2ae86d68..3857068d 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -2,27 +2,32 @@ name: "Development" on: [pull_request, workflow_dispatch, workflow_call] jobs: - format-and-verify-configurations: + verify: runs-on: ubuntu-22.04-arm container: image: datadog/docker-library:dd-trace-cpp-ci-23768e9-arm64 + env: + BUILD_DIR: .build steps: - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: Check format run: bin/check-format - name: Shellcheck run: find bin/ -executable -type f -print0 | xargs -0 shellcheck - - name: Verify environment variable allowlist + - name: Verify getenv usage run: bin/check-environment-variables + - name: Configure + run: bin/with-toolchain llvm cmake . -B ${BUILD_DIR} --preset ci-clang + - name: Build + run: cmake --build ${BUILD_DIR} -j --target config-inversion -v - name: Verify supported configurations metadata run: | tmp_dir="$(mktemp -d)" trap 'rm -rf "$tmp_dir"' EXIT - cp metadata/supported-configurations.json "$tmp_dir/supported-configurations.json" - bin/generate-supported-configurations - if ! diff -q "$tmp_dir/supported-configurations.json" metadata/supported-configurations.json >/dev/null 2>&1; then - echo "ERROR: metadata/supported-configurations.json got out of sync with implemented configurations. Please run bin/generate-supported-configurations locally." - diff -u "$tmp_dir/supported-configurations.json" metadata/supported-configurations.json || true + ./${BUILD_DIR}/tools/config-inversion/config-inversion --output-file "${tmp_dir}/ci-supported-configurations.json" + if ! diff -q "$tmp_dir/ci-supported-configurations.json" "supported-configurations.json" >/dev/null 2>&1; then + echo "ERROR: supported-configurations.json got out of sync with implemented configurations. Please run `./config-inversion --output-file supported-configurations.json` locally." + diff -u "$tmp_dir/supported-configurations.json" supported-configurations.json || true exit 1 fi @@ -39,7 +44,7 @@ jobs: - runner: ubuntu-22.04 arch: x64 docker-arch: amd64 - needs: format-and-verify-configurations + needs: verify runs-on: ${{ matrix.runner }} container: image: datadog/docker-library:dd-trace-cpp-ci-23768e9-${{matrix.docker-arch}} @@ -67,7 +72,7 @@ jobs: datadog-ci junit upload --service dd-trace-cpp --tags test.source.file:test/*.cpp .build/report.xml build-linux-bazel: - needs: format-and-verify-configurations + needs: verify strategy: fail-fast: false matrix: @@ -90,7 +95,7 @@ jobs: run: bin/with-toolchain ${{ matrix.toolchain }} bazelisk --bazelrc=${{ matrix.bazelrc }} build dd_trace_cpp build-windows-bazel: - needs: format-and-verify-configurations + needs: verify runs-on: windows-2022 defaults: run: @@ -111,7 +116,7 @@ jobs: run: bazelisk.exe --bazelrc=${{ matrix.bazelrc }} build dd_trace_cpp build-windows-cmake: - needs: format-and-verify-configurations + needs: verify strategy: fail-fast: false matrix: diff --git a/.gitignore b/.gitignore index 409fd98a..a36fe8c6 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,3 @@ MODULE.bazel.lock .cache/ .cursor/ .DS_Store -bin/.supported-configurations \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5978566f..a77a96af 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -20,7 +20,7 @@ validate_supported_configurations_v2_local_file: - when: on_success extends: .validate_supported_configurations_v2_local_file variables: - LOCAL_JSON_PATH: "metadata/supported-configurations.json" + LOCAL_JSON_PATH: "supported-configurations.json" BACKFILLED: false update_central_configurations_version_range_v2: @@ -30,6 +30,6 @@ update_central_configurations_version_range_v2: extends: .update_central_configurations_version_range_v2 variables: LOCAL_REPO_NAME: "dd-trace-cpp" - LOCAL_JSON_PATH: "metadata/supported-configurations.json" + LOCAL_JSON_PATH: "supported-configurations.json" LANGUAGE_NAME: "cpp" - MULTIPLE_RELEASE_LINES: "false" \ No newline at end of file + MULTIPLE_RELEASE_LINES: "false" diff --git a/CMakeLists.txt b/CMakeLists.txt index c432a352..c8f49148 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,7 @@ if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) option(DD_TRACE_BUILD_EXAMPLES "Build example programs" OFF) option(DD_TRACE_BUILD_TESTING "Build the unit tests (test/)" OFF) option(DD_TRACE_BUILD_FUZZERS "Build fuzzers" OFF) + option(DD_TRACE_BUILD_TOOLS "Build tools" OFF) option(DD_TRACE_BUILD_BENCHMARK "Build benchmark binaries" OFF) option(DD_TRACE_ENABLE_COVERAGE "Build code with code coverage profiling instrumentation" OFF) option(DD_TRACE_ENABLE_SANITIZE "Build with address sanitizer and undefined behavior sanitizer" OFF) @@ -98,6 +99,11 @@ if (DD_TRACE_BUILD_BENCHMARK) add_subdirectory(benchmark) endif () +if (DD_TRACE_BUILD_TOOLS) + include(cmake/deps/cxxopts.cmake) + add_subdirectory(tools/config-inversion) +endif () + add_library(dd-trace-cpp-objects OBJECT) add_library(dd-trace-cpp::obj ALIAS dd-trace-cpp-objects) diff --git a/CMakePresets.json b/CMakePresets.json index 57abbeed..abf0d98a 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -30,6 +30,7 @@ "DD_TRACE_ENABLE_SANITIZE": "ON", "DD_TRACE_BUILD_TESTING": "ON", "DD_TRACE_BUILD_EXAMPLES": "ON", + "DD_TRACE_BUILD_TOOLS": "ON", "DD_TRACE_BUILD_FUZZERS": "OFF" } }, @@ -39,6 +40,7 @@ "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug", "DD_TRACE_ENABLE_SANITIZE": "ON", + "DD_TRACE_BUILD_TOOLS": "ON", "DD_TRACE_BUILD_TESTING": "ON" } } diff --git a/bin/check-environment-variables b/bin/check-environment-variables new file mode 100755 index 00000000..07a7f27c --- /dev/null +++ b/bin/check-environment-variables @@ -0,0 +1,19 @@ +#!/bin/sh +# TODO +set -eu + +if grep -R -n \ + --include='*.c' \ + --include='*.cc' \ + --include='*.cpp' \ + --include='*.cxx' \ + --include='*.h' \ + --include='*.hpp' \ + --exclude='environment.cpp' \ + 'std::getenv' include src; then + echo "Check failed: std::getenv usage detected." + exit 1 +else + echo "Check passed: no std::getenv usage found." + exit 0 +fi diff --git a/cmake/deps/cxxopts.cmake b/cmake/deps/cxxopts.cmake new file mode 100644 index 00000000..7ac78121 --- /dev/null +++ b/cmake/deps/cxxopts.cmake @@ -0,0 +1,11 @@ +include(FetchContent) + +FetchContent_Declare(cxxopts + URL https://github.com/jarro2783/cxxopts/archive/refs/tags/v3.3.1.tar.gz + URL_HASH SHA256=3bfc70542c521d4b55a46429d808178916a579b28d048bd8c727ee76c39e2072 + FIND_PACKAGE_ARGS NAMES cxxopts + EXCLUDE_FROM_ALL + SYSTEM +) + +FetchContent_MakeAvailable(cxxopts) diff --git a/include/datadog/environment.h b/include/datadog/environment.h index baa33f58..f2846b37 100644 --- a/include/datadog/environment.h +++ b/include/datadog/environment.h @@ -9,146 +9,107 @@ // `name` returns the name of a specified `Variable`. // // `lookup` retrieves the value of `Variable` in the environment. - -#include -#include #include #include -#include -#include +#include namespace datadog { namespace tracing { namespace environment { -enum class VariableType { - STRING, - BOOLEAN, - INT, - DECIMAL, - ARRAY, - MAP, -}; - -struct VariableSpec { - StringView name; - VariableType type; -}; - -#define VARIABLE_ENUM_VALUE(DATA, NAME, TYPE, DEFAULT_VALUE) NAME, - -enum Variable { DD_ENVIRONMENT_VARIABLES(VARIABLE_ENUM_VALUE, ~) }; +// Central registry for supported environment variables. +// All configurations must be registered here. +// +// This registry is the single source of truth for: +// - env variable name allowlist (`include/datadog/environment.h`) +// - generated metadata (`metadata/supported-configurations.json`) +// +// Each entry has: +// - NAME: environment variable symbol (e.g. DD_SERVICE) +// - TYPE: STRING | BOOLEAN | INT | DECIMAL | ARRAY | MAP +// - DEFAULT: literal default value or a marker token +// +// Marker tokens: +// - ENV_DEFAULT_RESOLVED_IN_CODE("...description...") +// The runtime default is resolved in C++ configuration finalization +// logic. The description is emitted as the "default" field in +// metadata/supported-configurations.json. +#define DD_LIST_ENVIRONMENT_VARIABLES(MACRO) \ + MACRO(DD_AGENT_HOST, STRING, "localhost") \ + MACRO(DD_ENV, STRING, "") \ + MACRO(DD_INSTRUMENTATION_TELEMETRY_ENABLED, BOOLEAN, true) \ + MACRO(DD_PROPAGATION_STYLE_EXTRACT, ARRAY, "datadog,tracecontext,baggage") \ + MACRO(DD_PROPAGATION_STYLE_INJECT, ARRAY, "datadog,tracecontext,baggage") \ + MACRO(DD_REMOTE_CONFIGURATION_ENABLED, BOOLEAN, true) \ + MACRO(DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS, DECIMAL, 5.0) \ + MACRO(DD_SERVICE, STRING, \ + ENV_DEFAULT_RESOLVED_IN_CODE("Defaults to process name when unset.")) \ + MACRO(DD_SPAN_SAMPLING_RULES, ARRAY, "[]") \ + MACRO(DD_SPAN_SAMPLING_RULES_FILE, STRING, "") \ + MACRO(DD_TRACE_PROPAGATION_STYLE_EXTRACT, ARRAY, \ + "datadog,tracecontext,baggage") \ + MACRO(DD_TRACE_PROPAGATION_STYLE_INJECT, ARRAY, \ + "datadog,tracecontext,baggage") \ + MACRO(DD_TRACE_PROPAGATION_STYLE, ARRAY, "datadog,tracecontext,baggage") \ + MACRO(DD_TAGS, MAP, "") \ + MACRO(DD_TRACE_AGENT_PORT, INT, 8126) \ + MACRO(DD_TRACE_AGENT_URL, STRING, \ + ENV_DEFAULT_RESOLVED_IN_CODE( \ + "If unset, built from DD_AGENT_HOST and DD_TRACE_AGENT_PORT, " \ + "then defaults to http://localhost:8126.")) \ + MACRO(DD_TRACE_DEBUG, BOOLEAN, false) \ + MACRO(DD_TRACE_ENABLED, BOOLEAN, true) \ + MACRO(DD_TRACE_RATE_LIMIT, DECIMAL, 100.0) \ + MACRO(DD_TRACE_REPORT_HOSTNAME, BOOLEAN, false) \ + MACRO(DD_TRACE_SAMPLE_RATE, DECIMAL, 1.0) \ + MACRO(DD_TRACE_SAMPLING_RULES, ARRAY, "[]") \ + MACRO(DD_TRACE_STARTUP_LOGS, BOOLEAN, true) \ + MACRO(DD_TRACE_TAGS_PROPAGATION_MAX_LENGTH, INT, 512) \ + MACRO(DD_VERSION, STRING, "") \ + MACRO(DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED, BOOLEAN, true) \ + MACRO(DD_TELEMETRY_HEARTBEAT_INTERVAL, DECIMAL, 10) \ + MACRO(DD_TELEMETRY_METRICS_ENABLED, BOOLEAN, true) \ + MACRO(DD_TELEMETRY_METRICS_INTERVAL_SECONDS, DECIMAL, 60) \ + MACRO(DD_TELEMETRY_DEBUG, BOOLEAN, false) \ + MACRO(DD_TRACE_BAGGAGE_MAX_ITEMS, INT, 64) \ + MACRO(DD_TRACE_BAGGAGE_MAX_BYTES, INT, 8192) \ + MACRO(DD_TELEMETRY_LOG_COLLECTION_ENABLED, BOOLEAN, true) \ + MACRO(DD_INSTRUMENTATION_INSTALL_ID, STRING, "") \ + MACRO(DD_INSTRUMENTATION_INSTALL_TYPE, STRING, "") \ + MACRO(DD_INSTRUMENTATION_INSTALL_TIME, STRING, "") \ + MACRO(DD_APM_TRACING_ENABLED, BOOLEAN, true) \ + MACRO(DD_TRACE_RESOURCE_RENAMING_ENABLED, BOOLEAN, false) \ + MACRO(DD_TRACE_RESOURCE_RENAMING_ALWAYS_SIMPLIFIED_ENDPOINT, BOOLEAN, false) \ + MACRO(DD_EXTERNAL_ENV, STRING, "") + +#define ENV_DEFAULT_RESOLVED_IN_CODE(X) X +#define WITH_COMMA(ARG, TYPE, DEFAULT_VALUE) ARG, + +enum Variable { DD_LIST_ENVIRONMENT_VARIABLES(WITH_COMMA) }; // Quoting a macro argument requires this two-step. #define QUOTED_IMPL(ARG) #ARG #define QUOTED(ARG) QUOTED_IMPL(ARG) -#define VARIABLE_SPEC_WITH_COMMA(DATA, NAME, TYPE, DEFAULT_VALUE) \ - VariableSpec{StringView{QUOTED(NAME)}, VariableType::TYPE}, - -inline const VariableSpec variable_specs[] = { - DD_ENVIRONMENT_VARIABLES(VARIABLE_SPEC_WITH_COMMA, ~)}; - -template -struct LookupResultByType; - -template <> -struct LookupResultByType { - using type = Optional; -}; - -template <> -struct LookupResultByType { - using type = Optional; -}; - -template <> -struct LookupResultByType { - using type = Expected>; -}; +#define QUOTED_WITH_COMMA(ARG, TYPE, DEFAULT_VALUE) \ + WITH_COMMA(QUOTED(ARG), TYPE, DEFAULT_VALUE) -template <> -struct LookupResultByType { - using type = Expected>; -}; +inline const char *const variable_names[] = { + DD_LIST_ENVIRONMENT_VARIABLES(QUOTED_WITH_COMMA)}; -template <> -struct LookupResultByType { - using type = Optional; -}; - -template <> -struct LookupResultByType { - using type = Optional; -}; - -template -struct VariableTraits; - -#define VARIABLE_TRAITS_VALUE(DATA, NAME, TYPE, DEFAULT_VALUE) \ - template <> \ - struct VariableTraits { \ - static constexpr VariableType variable_type = VariableType::TYPE; \ - static constexpr const char *name() { return QUOTED(NAME); } \ - using lookup_result = typename LookupResultByType::type; \ - }; - -DD_ENVIRONMENT_VARIABLES(VARIABLE_TRAITS_VALUE, ~) - -template -using LookupResult = typename VariableTraits::lookup_result; - -namespace detail { -template -inline constexpr bool unsupported_variable_type_v = false; - -template -Optional lookup_raw() { - const char *value = std::getenv(VariableTraits::name()); - if (!value) { - return nullopt; - } - return StringView{value}; -} - -Optional lookup_bool_from_raw(Optional value); -Expected> lookup_uint64_from_raw( - Optional value); -Expected> lookup_double_from_raw(Optional value); -} // namespace detail - -template -LookupResult lookup() { - constexpr VariableType type = VariableTraits::variable_type; - const auto raw = detail::lookup_raw(); - if constexpr (type == VariableType::STRING || type == VariableType::ARRAY || - type == VariableType::MAP) { - return raw; - } else if constexpr (type == VariableType::BOOLEAN) { - return detail::lookup_bool_from_raw(raw); - } else if constexpr (type == VariableType::INT) { - return detail::lookup_uint64_from_raw(raw); - } else if constexpr (type == VariableType::DECIMAL) { - return detail::lookup_double_from_raw(raw); - } else { - static_assert(detail::unsupported_variable_type_v, - "Unsupported environment variable type"); - } -} - -#undef VARIABLE_SPEC_WITH_COMMA -#undef VARIABLE_TRAITS_VALUE #undef QUOTED #undef QUOTED_IMPL -#undef VARIABLE_ENUM_VALUE - -// Return the metadata for the specified environment `variable`. -const VariableSpec &spec(Variable variable); +#undef WITH_COMMA +#undef ENV_DEFAULT_RESOLVED_IN_CODE // Return the name of the specified environment `variable`. 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 lookup(Variable variable); + std::string to_json(); } // namespace environment diff --git a/include/datadog/environment_registry.h b/include/datadog/environment_registry.h deleted file mode 100644 index 54118e29..00000000 --- a/include/datadog/environment_registry.h +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once - -// Central registry for supported environment variables. -// All configurations must be registered here. -// -// This registry is the single source of truth for: -// - env variable name allowlist (`include/datadog/environment.h`) -// - generated metadata (`metadata/supported-configurations.json`) -// -// Each entry has: -// - NAME: environment variable symbol (e.g. DD_SERVICE) -// - TYPE: STRING | BOOLEAN | INT | DECIMAL | ARRAY | MAP -// - DEFAULT: literal default value or a marker token -// -// Marker tokens: -// - ENV_DEFAULT_RESOLVED_IN_CODE("...description...") -// The runtime default is resolved in C++ configuration finalization -// logic. The description is emitted as the "default" field in -// metadata/supported-configurations.json. - -#define DD_ENVIRONMENT_VARIABLES(MACRO, DATA) \ - MACRO(DATA, DD_AGENT_HOST, STRING, "localhost") \ - MACRO(DATA, DD_ENV, STRING, "") \ - MACRO(DATA, DD_INSTRUMENTATION_TELEMETRY_ENABLED, BOOLEAN, true) \ - MACRO(DATA, DD_PROPAGATION_STYLE_EXTRACT, ARRAY, \ - "datadog,tracecontext,baggage") \ - MACRO(DATA, DD_PROPAGATION_STYLE_INJECT, ARRAY, \ - "datadog,tracecontext,baggage") \ - MACRO(DATA, DD_REMOTE_CONFIGURATION_ENABLED, BOOLEAN, true) \ - MACRO(DATA, DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS, DECIMAL, 5.0) \ - MACRO(DATA, DD_SERVICE, STRING, \ - ENV_DEFAULT_RESOLVED_IN_CODE("Defaults to process name when unset.")) \ - MACRO(DATA, DD_SPAN_SAMPLING_RULES, ARRAY, "[]") \ - MACRO(DATA, DD_SPAN_SAMPLING_RULES_FILE, STRING, "") \ - MACRO(DATA, DD_TRACE_PROPAGATION_STYLE_EXTRACT, ARRAY, \ - "datadog,tracecontext,baggage") \ - MACRO(DATA, DD_TRACE_PROPAGATION_STYLE_INJECT, ARRAY, \ - "datadog,tracecontext,baggage") \ - MACRO(DATA, DD_TRACE_PROPAGATION_STYLE, ARRAY, \ - "datadog,tracecontext,baggage") \ - MACRO(DATA, DD_TAGS, MAP, "") \ - MACRO(DATA, DD_TRACE_AGENT_PORT, INT, 8126) \ - MACRO(DATA, DD_TRACE_AGENT_URL, STRING, \ - ENV_DEFAULT_RESOLVED_IN_CODE( \ - "If unset, built from DD_AGENT_HOST and DD_TRACE_AGENT_PORT, " \ - "then defaults to http://localhost:8126.")) \ - MACRO(DATA, DD_TRACE_DEBUG, BOOLEAN, false) \ - MACRO(DATA, DD_TRACE_ENABLED, BOOLEAN, true) \ - MACRO(DATA, DD_TRACE_RATE_LIMIT, DECIMAL, 100.0) \ - MACRO(DATA, DD_TRACE_REPORT_HOSTNAME, BOOLEAN, false) \ - MACRO(DATA, DD_TRACE_SAMPLE_RATE, DECIMAL, 1.0) \ - MACRO(DATA, DD_TRACE_SAMPLING_RULES, ARRAY, "[]") \ - MACRO(DATA, DD_TRACE_STARTUP_LOGS, BOOLEAN, true) \ - MACRO(DATA, DD_TRACE_TAGS_PROPAGATION_MAX_LENGTH, INT, 512) \ - MACRO(DATA, DD_VERSION, STRING, "") \ - MACRO(DATA, DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED, BOOLEAN, true) \ - MACRO(DATA, DD_TELEMETRY_HEARTBEAT_INTERVAL, DECIMAL, 10) \ - MACRO(DATA, DD_TELEMETRY_METRICS_ENABLED, BOOLEAN, true) \ - MACRO(DATA, DD_TELEMETRY_METRICS_INTERVAL_SECONDS, DECIMAL, 60) \ - MACRO(DATA, DD_TELEMETRY_DEBUG, BOOLEAN, false) \ - MACRO(DATA, DD_TRACE_BAGGAGE_MAX_ITEMS, INT, 64) \ - MACRO(DATA, DD_TRACE_BAGGAGE_MAX_BYTES, INT, 8192) \ - MACRO(DATA, DD_TELEMETRY_LOG_COLLECTION_ENABLED, BOOLEAN, true) \ - MACRO(DATA, DD_INSTRUMENTATION_INSTALL_ID, STRING, "") \ - MACRO(DATA, DD_INSTRUMENTATION_INSTALL_TYPE, STRING, "") \ - MACRO(DATA, DD_INSTRUMENTATION_INSTALL_TIME, STRING, "") \ - MACRO(DATA, DD_APM_TRACING_ENABLED, BOOLEAN, true) \ - MACRO(DATA, DD_TRACE_RESOURCE_RENAMING_ENABLED, BOOLEAN, false) \ - MACRO(DATA, DD_TRACE_RESOURCE_RENAMING_ALWAYS_SIMPLIFIED_ENDPOINT, BOOLEAN, \ - false) \ - MACRO(DATA, DD_EXTERNAL_ENV, STRING, "") diff --git a/metadata/supported-configurations.json b/metadata/supported-configurations.json deleted file mode 100644 index 1a67bfac..00000000 --- a/metadata/supported-configurations.json +++ /dev/null @@ -1,286 +0,0 @@ -{ - "deprecations": {}, - "supportedConfigurations": { - "DD_AGENT_HOST": [ - { - "default": "localhost", - "implementation": "A", - "type": "string" - } - ], - "DD_APM_TRACING_ENABLED": [ - { - "default": "true", - "implementation": "A", - "type": "boolean" - } - ], - "DD_ENV": [ - { - "default": "", - "implementation": "A", - "type": "string" - } - ], - "DD_EXTERNAL_ENV": [ - { - "default": "", - "implementation": "A", - "type": "string" - } - ], - "DD_INSTRUMENTATION_INSTALL_ID": [ - { - "default": "", - "implementation": "A", - "type": "string" - } - ], - "DD_INSTRUMENTATION_INSTALL_TIME": [ - { - "default": "", - "implementation": "A", - "type": "string" - } - ], - "DD_INSTRUMENTATION_INSTALL_TYPE": [ - { - "default": "", - "implementation": "A", - "type": "string" - } - ], - "DD_INSTRUMENTATION_TELEMETRY_ENABLED": [ - { - "default": "true", - "implementation": "A", - "type": "boolean" - } - ], - "DD_PROPAGATION_STYLE_EXTRACT": [ - { - "default": "datadog,tracecontext,baggage", - "implementation": "A", - "type": "array" - } - ], - "DD_PROPAGATION_STYLE_INJECT": [ - { - "default": "datadog,tracecontext,baggage", - "implementation": "A", - "type": "array" - } - ], - "DD_REMOTE_CONFIGURATION_ENABLED": [ - { - "default": "true", - "implementation": "A", - "type": "boolean" - } - ], - "DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS": [ - { - "default": "5.0", - "implementation": "A", - "type": "decimal" - } - ], - "DD_SERVICE": [ - { - "default": "Defaults to process name when unset.", - "implementation": "A", - "type": "string" - } - ], - "DD_SPAN_SAMPLING_RULES": [ - { - "default": "[]", - "implementation": "A", - "type": "array" - } - ], - "DD_SPAN_SAMPLING_RULES_FILE": [ - { - "default": "", - "implementation": "A", - "type": "string" - } - ], - "DD_TAGS": [ - { - "default": "", - "implementation": "A", - "type": "map" - } - ], - "DD_TELEMETRY_DEBUG": [ - { - "default": "false", - "implementation": "A", - "type": "boolean" - } - ], - "DD_TELEMETRY_HEARTBEAT_INTERVAL": [ - { - "default": "10", - "implementation": "A", - "type": "decimal" - } - ], - "DD_TELEMETRY_LOG_COLLECTION_ENABLED": [ - { - "default": "true", - "implementation": "A", - "type": "boolean" - } - ], - "DD_TELEMETRY_METRICS_ENABLED": [ - { - "default": "true", - "implementation": "A", - "type": "boolean" - } - ], - "DD_TELEMETRY_METRICS_INTERVAL_SECONDS": [ - { - "default": "60", - "implementation": "A", - "type": "decimal" - } - ], - "DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED": [ - { - "default": "true", - "implementation": "A", - "type": "boolean" - } - ], - "DD_TRACE_AGENT_PORT": [ - { - "default": "8126", - "implementation": "A", - "type": "int" - } - ], - "DD_TRACE_AGENT_URL": [ - { - "default": "If unset, built from DD_AGENT_HOST and DD_TRACE_AGENT_PORT, then defaults to http://localhost:8126.", - "implementation": "A", - "type": "string" - } - ], - "DD_TRACE_BAGGAGE_MAX_BYTES": [ - { - "default": "8192", - "implementation": "A", - "type": "int" - } - ], - "DD_TRACE_BAGGAGE_MAX_ITEMS": [ - { - "default": "64", - "implementation": "A", - "type": "int" - } - ], - "DD_TRACE_DEBUG": [ - { - "default": "false", - "implementation": "A", - "type": "boolean" - } - ], - "DD_TRACE_ENABLED": [ - { - "default": "true", - "implementation": "A", - "type": "boolean" - } - ], - "DD_TRACE_PROPAGATION_STYLE": [ - { - "default": "datadog,tracecontext,baggage", - "implementation": "A", - "type": "array" - } - ], - "DD_TRACE_PROPAGATION_STYLE_EXTRACT": [ - { - "default": "datadog,tracecontext,baggage", - "implementation": "A", - "type": "array" - } - ], - "DD_TRACE_PROPAGATION_STYLE_INJECT": [ - { - "default": "datadog,tracecontext,baggage", - "implementation": "A", - "type": "array" - } - ], - "DD_TRACE_RATE_LIMIT": [ - { - "default": "100.0", - "implementation": "A", - "type": "decimal" - } - ], - "DD_TRACE_REPORT_HOSTNAME": [ - { - "default": "false", - "implementation": "A", - "type": "boolean" - } - ], - "DD_TRACE_RESOURCE_RENAMING_ALWAYS_SIMPLIFIED_ENDPOINT": [ - { - "default": "false", - "implementation": "A", - "type": "boolean" - } - ], - "DD_TRACE_RESOURCE_RENAMING_ENABLED": [ - { - "default": "false", - "implementation": "A", - "type": "boolean" - } - ], - "DD_TRACE_SAMPLE_RATE": [ - { - "default": "1.0", - "implementation": "A", - "type": "decimal" - } - ], - "DD_TRACE_SAMPLING_RULES": [ - { - "default": "[]", - "implementation": "A", - "type": "array" - } - ], - "DD_TRACE_STARTUP_LOGS": [ - { - "default": "true", - "implementation": "A", - "type": "boolean" - } - ], - "DD_TRACE_TAGS_PROPAGATION_MAX_LENGTH": [ - { - "default": "512", - "implementation": "A", - "type": "int" - } - ], - "DD_VERSION": [ - { - "default": "", - "implementation": "A", - "type": "string" - } - ] - }, - "version": "2" -} diff --git a/src/datadog/datadog_agent_config.cpp b/src/datadog/datadog_agent_config.cpp index 1dfc11d4..05b3b065 100644 --- a/src/datadog/datadog_agent_config.cpp +++ b/src/datadog/datadog_agent_config.cpp @@ -1,54 +1,46 @@ #include #include -#include #include #include #include -#include #include "default_http_client.h" +#include "parse_util.h" #include "platform_util.h" #include "threaded_event_scheduler.h" namespace datadog { namespace tracing { -namespace env = environment; - Expected load_datadog_agent_env_config() { DatadogAgentConfig env_config; - if (auto rc_enabled = env::lookup()) { - env_config.remote_configuration_enabled = *rc_enabled; + if (auto rc_enabled = lookup(environment::DD_REMOTE_CONFIGURATION_ENABLED)) { + env_config.remote_configuration_enabled = !falsy(*rc_enabled); } - auto raw_rc_poll_interval_value = - env::lookup(); - if (auto error = raw_rc_poll_interval_value.if_error()) { - return error->with_prefix( - "DatadogAgent: Remote Configuration poll interval error "); - } else if (*raw_rc_poll_interval_value) { - env_config.remote_configuration_poll_interval_seconds = - **raw_rc_poll_interval_value; - } + if (auto raw_rc_poll_interval_value = + lookup(environment::DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS)) { + auto res = parse_double(*raw_rc_poll_interval_value); + if (auto error = res.if_error()) { + return error->with_prefix( + "DatadogAgent: Remote Configuration poll interval error "); + } - const auto env_host = env::lookup(); - Optional env_port = nullopt; - const auto raw_env_port = env::lookup(); - if (auto* error = raw_env_port.if_error()) { - return error->with_prefix("DatadogAgent: Agent port parsing error "); - } else { - env_port = *raw_env_port; + env_config.remote_configuration_poll_interval_seconds = *res; } - if (auto url_env = env::lookup()) { + auto env_host = lookup(environment::DD_AGENT_HOST); + auto env_port = lookup(environment::DD_TRACE_AGENT_PORT); + + if (auto url_env = lookup(environment::DD_TRACE_AGENT_URL)) { env_config.url = std::string{*url_env}; } else if (env_host || env_port) { std::string configured_url = "http://"; append(configured_url, env_host.value_or("localhost")); configured_url += ':'; - configured_url += std::to_string(env_port.value_or(8126)); + append(configured_url, env_port.value_or("8126")); env_config.url = std::move(configured_url); } @@ -156,7 +148,7 @@ Expected finalize_config( // Starting Datadog Agent 7.62.0, the admission controller inject a unique // identifier through `DD_EXTERNAL_ENV`. This uid is used for origin // detection. - if (auto external_env = env::lookup()) { + if (auto external_env = lookup(environment::DD_EXTERNAL_ENV)) { result.admission_controller_uid = std::string(*external_env); } diff --git a/src/datadog/environment.cpp b/src/datadog/environment.cpp index c48c9de8..4dc3eb3f 100644 --- a/src/datadog/environment.cpp +++ b/src/datadog/environment.cpp @@ -3,60 +3,31 @@ #include #include "json.hpp" -#include "parse_util.h" namespace datadog { namespace tracing { namespace environment { -namespace detail { -Optional lookup_bool_from_raw(Optional value) { - if (value) { - return !falsy(*value); - } - return nullopt; -} - -Expected> lookup_uint64_from_raw( - Optional value) { - if (!value) { - return Optional{}; - } - auto parsed = parse_uint64(*value, 10); - if (auto *error = parsed.if_error()) { - return *error; - } - return Optional{*parsed}; -} +StringView name(Variable variable) { return variable_names[variable]; } -Expected> lookup_double_from_raw(Optional value) { +Optional lookup(Variable variable) { + const char *name = variable_names[variable]; + const char *value = std::getenv(name); if (!value) { - return Optional{}; - } - auto parsed = parse_double(*value); - if (auto *error = parsed.if_error()) { - return *error; + return nullopt; } - return Optional{*parsed}; + return StringView{value}; } -} // namespace detail - -const VariableSpec &spec(Variable variable) { return variable_specs[variable]; } - -StringView name(Variable variable) { return spec(variable).name; } std::string to_json() { auto result = nlohmann::json::object({}); -#define ADD_ENV_TO_JSON_IF_SET(DATA, NAME, TYPE, DEFAULT_VALUE) \ - if (const char *value = std::getenv(VariableTraits::name())) { \ - result[VariableTraits::name()] = value; \ + for (const char *name : variable_names) { + if (const char *value = std::getenv(name)) { + result[name] = value; + } } - DD_ENVIRONMENT_VARIABLES(ADD_ENV_TO_JSON_IF_SET, ~) - -#undef ADD_ENV_TO_JSON_IF_SET - return result.dump(); } diff --git a/supported-configurations.json b/supported-configurations.json new file mode 100644 index 00000000..b3bcc5e0 --- /dev/null +++ b/supported-configurations.json @@ -0,0 +1,366 @@ +{ + "deprecations": [], + "supportedConfigurations": [ + { + "DD_AGENT_HOST": [ + { + "default": "localhost", + "implementation": "A", + "type": "STRING" + } + ] + }, + { + "DD_ENV": [ + { + "default": "", + "implementation": "A", + "type": "STRING" + } + ] + }, + { + "DD_INSTRUMENTATION_TELEMETRY_ENABLED": [ + { + "default": "1", + "implementation": "A", + "type": "BOOLEAN" + } + ] + }, + { + "DD_PROPAGATION_STYLE_EXTRACT": [ + { + "default": "datadog,tracecontext,baggage", + "implementation": "A", + "type": "ARRAY" + } + ] + }, + { + "DD_PROPAGATION_STYLE_INJECT": [ + { + "default": "datadog,tracecontext,baggage", + "implementation": "A", + "type": "ARRAY" + } + ] + }, + { + "DD_REMOTE_CONFIGURATION_ENABLED": [ + { + "default": "1", + "implementation": "A", + "type": "BOOLEAN" + } + ] + }, + { + "DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS": [ + { + "default": "5", + "implementation": "A", + "type": "DECIMAL" + } + ] + }, + { + "DD_SERVICE": [ + { + "default": "", + "implementation": "A", + "type": "STRING" + } + ] + }, + { + "DD_SPAN_SAMPLING_RULES": [ + { + "default": "[]", + "implementation": "A", + "type": "ARRAY" + } + ] + }, + { + "DD_SPAN_SAMPLING_RULES_FILE": [ + { + "default": "", + "implementation": "A", + "type": "STRING" + } + ] + }, + { + "DD_TRACE_PROPAGATION_STYLE_EXTRACT": [ + { + "default": "datadog,tracecontext,baggage", + "implementation": "A", + "type": "ARRAY" + } + ] + }, + { + "DD_TRACE_PROPAGATION_STYLE_INJECT": [ + { + "default": "datadog,tracecontext,baggage", + "implementation": "A", + "type": "ARRAY" + } + ] + }, + { + "DD_TRACE_PROPAGATION_STYLE": [ + { + "default": "datadog,tracecontext,baggage", + "implementation": "A", + "type": "ARRAY" + } + ] + }, + { + "DD_TAGS": [ + { + "default": "", + "implementation": "A", + "type": "MAP" + } + ] + }, + { + "DD_TRACE_AGENT_PORT": [ + { + "default": "8126", + "implementation": "A", + "type": "INT" + } + ] + }, + { + "DD_TRACE_AGENT_URL": [ + { + "default": "", + "implementation": "A", + "type": "STRING" + } + ] + }, + { + "DD_TRACE_DEBUG": [ + { + "default": "0", + "implementation": "A", + "type": "BOOLEAN" + } + ] + }, + { + "DD_TRACE_ENABLED": [ + { + "default": "1", + "implementation": "A", + "type": "BOOLEAN" + } + ] + }, + { + "DD_TRACE_RATE_LIMIT": [ + { + "default": "100", + "implementation": "A", + "type": "DECIMAL" + } + ] + }, + { + "DD_TRACE_REPORT_HOSTNAME": [ + { + "default": "0", + "implementation": "A", + "type": "BOOLEAN" + } + ] + }, + { + "DD_TRACE_SAMPLE_RATE": [ + { + "default": "1", + "implementation": "A", + "type": "DECIMAL" + } + ] + }, + { + "DD_TRACE_SAMPLING_RULES": [ + { + "default": "[]", + "implementation": "A", + "type": "ARRAY" + } + ] + }, + { + "DD_TRACE_STARTUP_LOGS": [ + { + "default": "1", + "implementation": "A", + "type": "BOOLEAN" + } + ] + }, + { + "DD_TRACE_TAGS_PROPAGATION_MAX_LENGTH": [ + { + "default": "512", + "implementation": "A", + "type": "INT" + } + ] + }, + { + "DD_VERSION": [ + { + "default": "", + "implementation": "A", + "type": "STRING" + } + ] + }, + { + "DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED": [ + { + "default": "1", + "implementation": "A", + "type": "BOOLEAN" + } + ] + }, + { + "DD_TELEMETRY_HEARTBEAT_INTERVAL": [ + { + "default": "10", + "implementation": "A", + "type": "DECIMAL" + } + ] + }, + { + "DD_TELEMETRY_METRICS_ENABLED": [ + { + "default": "1", + "implementation": "A", + "type": "BOOLEAN" + } + ] + }, + { + "DD_TELEMETRY_METRICS_INTERVAL_SECONDS": [ + { + "default": "60", + "implementation": "A", + "type": "DECIMAL" + } + ] + }, + { + "DD_TELEMETRY_DEBUG": [ + { + "default": "0", + "implementation": "A", + "type": "BOOLEAN" + } + ] + }, + { + "DD_TRACE_BAGGAGE_MAX_ITEMS": [ + { + "default": "64", + "implementation": "A", + "type": "INT" + } + ] + }, + { + "DD_TRACE_BAGGAGE_MAX_BYTES": [ + { + "default": "8192", + "implementation": "A", + "type": "INT" + } + ] + }, + { + "DD_TELEMETRY_LOG_COLLECTION_ENABLED": [ + { + "default": "1", + "implementation": "A", + "type": "BOOLEAN" + } + ] + }, + { + "DD_INSTRUMENTATION_INSTALL_ID": [ + { + "default": "", + "implementation": "A", + "type": "STRING" + } + ] + }, + { + "DD_INSTRUMENTATION_INSTALL_TYPE": [ + { + "default": "", + "implementation": "A", + "type": "STRING" + } + ] + }, + { + "DD_INSTRUMENTATION_INSTALL_TIME": [ + { + "default": "", + "implementation": "A", + "type": "STRING" + } + ] + }, + { + "DD_APM_TRACING_ENABLED": [ + { + "default": "1", + "implementation": "A", + "type": "BOOLEAN" + } + ] + }, + { + "DD_TRACE_RESOURCE_RENAMING_ENABLED": [ + { + "default": "0", + "implementation": "A", + "type": "BOOLEAN" + } + ] + }, + { + "DD_TRACE_RESOURCE_RENAMING_ALWAYS_SIMPLIFIED_ENDPOINT": [ + { + "default": "0", + "implementation": "A", + "type": "BOOLEAN" + } + ] + }, + { + "DD_EXTERNAL_ENV": [ + { + "default": "", + "implementation": "A", + "type": "STRING" + } + ] + } + ], + "version": "2" +} \ No newline at end of file diff --git a/tools/config-inversion/CMakeLists.txt b/tools/config-inversion/CMakeLists.txt new file mode 100644 index 00000000..394df7af --- /dev/null +++ b/tools/config-inversion/CMakeLists.txt @@ -0,0 +1,19 @@ +add_executable(config-inversion main.cpp) + +target_compile_features(config-inversion + PUBLIC + cxx_std_17 +) + +target_include_directories(config-inversion + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/include +) + +target_link_libraries(config-inversion + PRIVATE + nlohmann_json::nlohmann_json + cxxopts::cxxopts + dd-trace-cpp::specs +) diff --git a/tools/config-inversion/main.cpp b/tools/config-inversion/main.cpp new file mode 100644 index 00000000..9578b12e --- /dev/null +++ b/tools/config-inversion/main.cpp @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include +#include + +#include "datadog/environment.h" + +namespace fs = std::filesystem; +namespace env = datadog::tracing::environment; + +template +std::string to_string_any(const T& value) { + std::ostringstream oss; + oss << value; + return oss.str(); +} + +nlohmann::json build_configuration() { + nlohmann::json j; + j["version"] = "2"; + + auto supported_configurations = nlohmann::json::array(); + +#define QUOTED_IMPL(ARG) #ARG +#define QUOTED(ARG) QUOTED_IMPL(ARG) + +#define ENV_DEFAULT_RESOLVED_IN_CODE(X) "" + +#define X(NAME, TYPE, DEFAULT_VALUE) \ + do { \ + auto obj = nlohmann::json::object(); \ + obj["default"] = to_string_any(DEFAULT_VALUE); \ + obj["implementation"] = "A"; \ + obj["type"] = QUOTED(TYPE); \ + supported_configurations.emplace_back( \ + nlohmann::json{{QUOTED(NAME), {obj}}}); \ + } while (0); + + DD_LIST_ENVIRONMENT_VARIABLES(X) +#undef X +#undef ENV_DEFAULT_RESOLVED_IN_CODE + + auto deprecated_configurations = nlohmann::json::array(); + + j["supportedConfigurations"] = supported_configurations; + j["deprecations"] = deprecated_configurations; + + return j; +} + +int main(int argc, char** argv) { + cxxopts::Options options("generate-configuration", + "A tool to generate a JSON file with Datadog " + "configuration supported by the C++ tracer."); + + options.add_options()("o,output-file", + "Location where the JSON file will be written", + cxxopts::value())("h,help", "Print usage"); + + auto result = options.parse(argc, argv); + + if (result.count("output-file") == 0 || result.count("help")) { + std::cout << options.help() << std::endl; + return 0; + } + + const fs::path output_file = result["output-file"].as(); + + const auto j = build_configuration(); + std::ofstream file(output_file, std::ios::binary); + if (!file) { + std::cerr << "Unable to write configuration file"; + return 1; + } + + file << j.dump(2); + return 0; +} From daeb826e60d2773b516d97861f8e8f3263dd14cb Mon Sep 17 00:00:00 2001 From: Damien Mehala Date: Fri, 27 Feb 2026 15:46:59 +0100 Subject: [PATCH 3/3] fix --- supported-configurations.json | 645 ++++++++++++++------------------ tools/config-inversion/main.cpp | 20 +- 2 files changed, 290 insertions(+), 375 deletions(-) diff --git a/supported-configurations.json b/supported-configurations.json index b3bcc5e0..4ee3558a 100644 --- a/supported-configurations.json +++ b/supported-configurations.json @@ -1,366 +1,285 @@ { - "deprecations": [], - "supportedConfigurations": [ - { - "DD_AGENT_HOST": [ - { - "default": "localhost", - "implementation": "A", - "type": "STRING" - } - ] - }, - { - "DD_ENV": [ - { - "default": "", - "implementation": "A", - "type": "STRING" - } - ] - }, - { - "DD_INSTRUMENTATION_TELEMETRY_ENABLED": [ - { - "default": "1", - "implementation": "A", - "type": "BOOLEAN" - } - ] - }, - { - "DD_PROPAGATION_STYLE_EXTRACT": [ - { - "default": "datadog,tracecontext,baggage", - "implementation": "A", - "type": "ARRAY" - } - ] - }, - { - "DD_PROPAGATION_STYLE_INJECT": [ - { - "default": "datadog,tracecontext,baggage", - "implementation": "A", - "type": "ARRAY" - } - ] - }, - { - "DD_REMOTE_CONFIGURATION_ENABLED": [ - { - "default": "1", - "implementation": "A", - "type": "BOOLEAN" - } - ] - }, - { - "DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS": [ - { - "default": "5", - "implementation": "A", - "type": "DECIMAL" - } - ] - }, - { - "DD_SERVICE": [ - { - "default": "", - "implementation": "A", - "type": "STRING" - } - ] - }, - { - "DD_SPAN_SAMPLING_RULES": [ - { - "default": "[]", - "implementation": "A", - "type": "ARRAY" - } - ] - }, - { - "DD_SPAN_SAMPLING_RULES_FILE": [ - { - "default": "", - "implementation": "A", - "type": "STRING" - } - ] - }, - { - "DD_TRACE_PROPAGATION_STYLE_EXTRACT": [ - { - "default": "datadog,tracecontext,baggage", - "implementation": "A", - "type": "ARRAY" - } - ] - }, - { - "DD_TRACE_PROPAGATION_STYLE_INJECT": [ - { - "default": "datadog,tracecontext,baggage", - "implementation": "A", - "type": "ARRAY" - } - ] - }, - { - "DD_TRACE_PROPAGATION_STYLE": [ - { - "default": "datadog,tracecontext,baggage", - "implementation": "A", - "type": "ARRAY" - } - ] - }, - { - "DD_TAGS": [ - { - "default": "", - "implementation": "A", - "type": "MAP" - } - ] - }, - { - "DD_TRACE_AGENT_PORT": [ - { - "default": "8126", - "implementation": "A", - "type": "INT" - } - ] - }, - { - "DD_TRACE_AGENT_URL": [ - { - "default": "", - "implementation": "A", - "type": "STRING" - } - ] - }, - { - "DD_TRACE_DEBUG": [ - { - "default": "0", - "implementation": "A", - "type": "BOOLEAN" - } - ] - }, - { - "DD_TRACE_ENABLED": [ - { - "default": "1", - "implementation": "A", - "type": "BOOLEAN" - } - ] - }, - { - "DD_TRACE_RATE_LIMIT": [ - { - "default": "100", - "implementation": "A", - "type": "DECIMAL" - } - ] - }, - { - "DD_TRACE_REPORT_HOSTNAME": [ - { - "default": "0", - "implementation": "A", - "type": "BOOLEAN" - } - ] - }, - { - "DD_TRACE_SAMPLE_RATE": [ - { - "default": "1", - "implementation": "A", - "type": "DECIMAL" - } - ] - }, - { - "DD_TRACE_SAMPLING_RULES": [ - { - "default": "[]", - "implementation": "A", - "type": "ARRAY" - } - ] - }, - { - "DD_TRACE_STARTUP_LOGS": [ - { - "default": "1", - "implementation": "A", - "type": "BOOLEAN" - } - ] - }, - { - "DD_TRACE_TAGS_PROPAGATION_MAX_LENGTH": [ - { - "default": "512", - "implementation": "A", - "type": "INT" - } - ] - }, - { - "DD_VERSION": [ - { - "default": "", - "implementation": "A", - "type": "STRING" - } - ] - }, - { - "DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED": [ - { - "default": "1", - "implementation": "A", - "type": "BOOLEAN" - } - ] - }, - { - "DD_TELEMETRY_HEARTBEAT_INTERVAL": [ - { - "default": "10", - "implementation": "A", - "type": "DECIMAL" - } - ] - }, - { - "DD_TELEMETRY_METRICS_ENABLED": [ - { - "default": "1", - "implementation": "A", - "type": "BOOLEAN" - } - ] - }, - { - "DD_TELEMETRY_METRICS_INTERVAL_SECONDS": [ - { - "default": "60", - "implementation": "A", - "type": "DECIMAL" - } - ] - }, - { - "DD_TELEMETRY_DEBUG": [ - { - "default": "0", - "implementation": "A", - "type": "BOOLEAN" - } - ] - }, - { - "DD_TRACE_BAGGAGE_MAX_ITEMS": [ - { - "default": "64", - "implementation": "A", - "type": "INT" - } - ] - }, - { - "DD_TRACE_BAGGAGE_MAX_BYTES": [ - { - "default": "8192", - "implementation": "A", - "type": "INT" - } - ] - }, - { - "DD_TELEMETRY_LOG_COLLECTION_ENABLED": [ - { - "default": "1", - "implementation": "A", - "type": "BOOLEAN" - } - ] - }, - { - "DD_INSTRUMENTATION_INSTALL_ID": [ - { - "default": "", - "implementation": "A", - "type": "STRING" - } - ] - }, - { - "DD_INSTRUMENTATION_INSTALL_TYPE": [ - { - "default": "", - "implementation": "A", - "type": "STRING" - } - ] - }, - { - "DD_INSTRUMENTATION_INSTALL_TIME": [ - { - "default": "", - "implementation": "A", - "type": "STRING" - } - ] - }, - { - "DD_APM_TRACING_ENABLED": [ - { - "default": "1", - "implementation": "A", - "type": "BOOLEAN" - } - ] - }, - { - "DD_TRACE_RESOURCE_RENAMING_ENABLED": [ - { - "default": "0", - "implementation": "A", - "type": "BOOLEAN" - } - ] - }, - { - "DD_TRACE_RESOURCE_RENAMING_ALWAYS_SIMPLIFIED_ENDPOINT": [ - { - "default": "0", - "implementation": "A", - "type": "BOOLEAN" - } - ] - }, - { - "DD_EXTERNAL_ENV": [ - { - "default": "", - "implementation": "A", - "type": "STRING" - } - ] - } - ], + "supportedConfigurations": { + "DD_AGENT_HOST": [ + { + "default": "localhost", + "implementation": "A", + "type": "STRING" + } + ], + "DD_APM_TRACING_ENABLED": [ + { + "default": "1", + "implementation": "A", + "type": "BOOLEAN" + } + ], + "DD_ENV": [ + { + "default": "", + "implementation": "A", + "type": "STRING" + } + ], + "DD_EXTERNAL_ENV": [ + { + "default": "", + "implementation": "A", + "type": "STRING" + } + ], + "DD_INSTRUMENTATION_INSTALL_ID": [ + { + "default": "", + "implementation": "A", + "type": "STRING" + } + ], + "DD_INSTRUMENTATION_INSTALL_TIME": [ + { + "default": "", + "implementation": "A", + "type": "STRING" + } + ], + "DD_INSTRUMENTATION_INSTALL_TYPE": [ + { + "default": "", + "implementation": "A", + "type": "STRING" + } + ], + "DD_INSTRUMENTATION_TELEMETRY_ENABLED": [ + { + "default": "1", + "implementation": "A", + "type": "BOOLEAN" + } + ], + "DD_PROPAGATION_STYLE_EXTRACT": [ + { + "default": "datadog,tracecontext,baggage", + "implementation": "A", + "type": "ARRAY" + } + ], + "DD_PROPAGATION_STYLE_INJECT": [ + { + "default": "datadog,tracecontext,baggage", + "implementation": "A", + "type": "ARRAY" + } + ], + "DD_REMOTE_CONFIGURATION_ENABLED": [ + { + "default": "1", + "implementation": "A", + "type": "BOOLEAN" + } + ], + "DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS": [ + { + "default": "5", + "implementation": "A", + "type": "DECIMAL" + } + ], + "DD_SERVICE": [ + { + "default": "", + "implementation": "A", + "type": "STRING" + } + ], + "DD_SPAN_SAMPLING_RULES": [ + { + "default": "[]", + "implementation": "A", + "type": "ARRAY" + } + ], + "DD_SPAN_SAMPLING_RULES_FILE": [ + { + "default": "", + "implementation": "A", + "type": "STRING" + } + ], + "DD_TAGS": [ + { + "default": "", + "implementation": "A", + "type": "MAP" + } + ], + "DD_TELEMETRY_DEBUG": [ + { + "default": "0", + "implementation": "A", + "type": "BOOLEAN" + } + ], + "DD_TELEMETRY_HEARTBEAT_INTERVAL": [ + { + "default": "10", + "implementation": "A", + "type": "DECIMAL" + } + ], + "DD_TELEMETRY_LOG_COLLECTION_ENABLED": [ + { + "default": "1", + "implementation": "A", + "type": "BOOLEAN" + } + ], + "DD_TELEMETRY_METRICS_ENABLED": [ + { + "default": "1", + "implementation": "A", + "type": "BOOLEAN" + } + ], + "DD_TELEMETRY_METRICS_INTERVAL_SECONDS": [ + { + "default": "60", + "implementation": "A", + "type": "DECIMAL" + } + ], + "DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED": [ + { + "default": "1", + "implementation": "A", + "type": "BOOLEAN" + } + ], + "DD_TRACE_AGENT_PORT": [ + { + "default": "8126", + "implementation": "A", + "type": "INT" + } + ], + "DD_TRACE_AGENT_URL": [ + { + "default": "", + "implementation": "A", + "type": "STRING" + } + ], + "DD_TRACE_BAGGAGE_MAX_BYTES": [ + { + "default": "8192", + "implementation": "A", + "type": "INT" + } + ], + "DD_TRACE_BAGGAGE_MAX_ITEMS": [ + { + "default": "64", + "implementation": "A", + "type": "INT" + } + ], + "DD_TRACE_DEBUG": [ + { + "default": "0", + "implementation": "A", + "type": "BOOLEAN" + } + ], + "DD_TRACE_ENABLED": [ + { + "default": "1", + "implementation": "A", + "type": "BOOLEAN" + } + ], + "DD_TRACE_PROPAGATION_STYLE": [ + { + "default": "datadog,tracecontext,baggage", + "implementation": "A", + "type": "ARRAY" + } + ], + "DD_TRACE_PROPAGATION_STYLE_EXTRACT": [ + { + "default": "datadog,tracecontext,baggage", + "implementation": "A", + "type": "ARRAY" + } + ], + "DD_TRACE_PROPAGATION_STYLE_INJECT": [ + { + "default": "datadog,tracecontext,baggage", + "implementation": "A", + "type": "ARRAY" + } + ], + "DD_TRACE_RATE_LIMIT": [ + { + "default": "100", + "implementation": "A", + "type": "DECIMAL" + } + ], + "DD_TRACE_REPORT_HOSTNAME": [ + { + "default": "0", + "implementation": "A", + "type": "BOOLEAN" + } + ], + "DD_TRACE_RESOURCE_RENAMING_ALWAYS_SIMPLIFIED_ENDPOINT": [ + { + "default": "0", + "implementation": "A", + "type": "BOOLEAN" + } + ], + "DD_TRACE_RESOURCE_RENAMING_ENABLED": [ + { + "default": "0", + "implementation": "A", + "type": "BOOLEAN" + } + ], + "DD_TRACE_SAMPLE_RATE": [ + { + "default": "1", + "implementation": "A", + "type": "DECIMAL" + } + ], + "DD_TRACE_SAMPLING_RULES": [ + { + "default": "[]", + "implementation": "A", + "type": "ARRAY" + } + ], + "DD_TRACE_STARTUP_LOGS": [ + { + "default": "1", + "implementation": "A", + "type": "BOOLEAN" + } + ], + "DD_TRACE_TAGS_PROPAGATION_MAX_LENGTH": [ + { + "default": "512", + "implementation": "A", + "type": "INT" + } + ], + "DD_VERSION": [ + { + "default": "", + "implementation": "A", + "type": "STRING" + } + ] + }, "version": "2" } \ No newline at end of file diff --git a/tools/config-inversion/main.cpp b/tools/config-inversion/main.cpp index 9578b12e..1bef85dd 100644 --- a/tools/config-inversion/main.cpp +++ b/tools/config-inversion/main.cpp @@ -21,31 +21,27 @@ nlohmann::json build_configuration() { nlohmann::json j; j["version"] = "2"; - auto supported_configurations = nlohmann::json::array(); + auto supported_configurations = nlohmann::json::object(); #define QUOTED_IMPL(ARG) #ARG #define QUOTED(ARG) QUOTED_IMPL(ARG) #define ENV_DEFAULT_RESOLVED_IN_CODE(X) "" -#define X(NAME, TYPE, DEFAULT_VALUE) \ - do { \ - auto obj = nlohmann::json::object(); \ - obj["default"] = to_string_any(DEFAULT_VALUE); \ - obj["implementation"] = "A"; \ - obj["type"] = QUOTED(TYPE); \ - supported_configurations.emplace_back( \ - nlohmann::json{{QUOTED(NAME), {obj}}}); \ +#define X(NAME, TYPE, DEFAULT_VALUE) \ + do { \ + auto obj = nlohmann::json::object(); \ + obj["default"] = to_string_any(DEFAULT_VALUE); \ + obj["implementation"] = "A"; \ + obj["type"] = QUOTED(TYPE); \ + supported_configurations[QUOTED(NAME)] = nlohmann::json::array({obj}); \ } while (0); DD_LIST_ENVIRONMENT_VARIABLES(X) #undef X #undef ENV_DEFAULT_RESOLVED_IN_CODE - auto deprecated_configurations = nlohmann::json::array(); - j["supportedConfigurations"] = supported_configurations; - j["deprecations"] = deprecated_configurations; return j; }