Send APM_TRACING configs as sdk_config when the library advertises SDK_CONFIGURATION - #7628
Send APM_TRACING configs as sdk_config when the library advertises SDK_CONFIGURATION#7628rachelyangdog wants to merge 1 commit into
Conversation
|
|
|
Update: two bugs found in the first CI run, both fixed in 79eb84b1. Capability bit 49 is ambiguous today (this is the interesting one)
// CapabilitySDKConfiguration is the capability for remotely configuring any in-scope
// SDK setting at runtime via a single, env-var-keyed capability bit
CapabilitySDKConfiguration = Capability{
Name: "SDK_CONFIGURATION",
bitIndex: 49,
}But libdatadog gives the same bit to a different capability: DDOG_REMOTE_CONFIG_CAPABILITIES_ASM_RAW_RESPONSE_BODY = 49,dd-trace-php ships that enum, so it advertises bit 49 today while still reading Fix: the switch now also requires the per-setting APM_TRACING capabilities to be gone. Dropping
Important The bit collision itself still needs an owner. libdatadog and dd-source disagree about bit 49, and dd-trace-js#9392 is about to start using it for real. One of the two has to move before 2. Stale-ACK race in the parametric helper
That failed Fix: resolve the payload shape at the top of Not caused by this PR
Testing
|
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4b083d711e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "dynamic_instrumentation_enabled": "DD_DYNAMIC_INSTRUMENTATION_ENABLED", | ||
| "dynamic_sampling_enabled": None, | ||
| "exception_replay_enabled": "DD_EXCEPTION_REPLAY_ENABLED", | ||
| "live_debugging_enabled": None, |
There was a problem hiding this comment.
What are the settings "that only ever existed as a remote config and has no environment variable counterpart"? Can we just delete them from this list, then?
…K_CONFIGURATION (#7628) ### Motivation [dd-trace-js#9392](DataDog/dd-trace-js#9392) is the first library to move to the unified **Config at Runtime** contract, and it fails 7 system-tests jobs: - `DEBUGGER_INPRODUCT_ENABLEMENT` × 5 weblogs — `Test_Debugger_InProduct_Enablement_Dynamic_Instrumentation::test_inproduct_enablement_di` - `PARAMETRIC` × 2 — 10 behaviour tests + 7 capability tests in `test_dynamic_configuration.py` That PR swaps the whole APM_TRACING contract: | | before | after | | --- | --- | --- | | capabilities | `APM_TRACING_SAMPLE_RATE`, `_LOGS_INJECTION`, `_HTTP_HEADER_TAGS`, `_CUSTOM_TAGS`, `_ENABLED`, `_SAMPLE_RULES`, `_ENABLE_DYNAMIC_INSTRUMENTATION`, `_ENABLE_CODE_ORIGIN`, `_ENABLE_LIVE_DEBUGGING` | `SDK_CONFIGURATION` (bit 49) | | payload | `lib_config: {dynamic_instrumentation_enabled: true}` | `sdk_config: {service_name, env, config: [{key: "DD_DYNAMIC_INSTRUMENTATION_ENABLED", value: "true"}]}` | The `lib_config` branch is **removed**, not kept as a fallback — `RCClientManager.addConfig` only reads `conf.sdk_config?.config`. system-tests only ever emits `lib_config`, so every APM_TRACING config becomes a no-op: DI is never enabled, probes never reach `EMITTING`, and the test fails. ### What does this PR do? The RC helpers now read the capability bit the library advertises on `/v0.7/config` and, when `SDK_CONFIGURATION` is set, send the same settings in the new shape. `service_target` is untouched — it still drives matching and priority. - **`utils/_remote_config.py`** — `to_sdk_config_payload()` rewrites an APM_TRACING config from `lib_config` to `sdk_config`: each setting keyed by its canonical `DD_*` name, serialized to its environment variable form (booleans, sample rate, `tracing_header_tags` → `"h:tag,…"`, `tracing_tags` → `"k:v,…"`, `tracing_service_mapping` → `"a:b,…"`, `tracing_sampling_rules` → JSON with the `[{key, value_glob}]` tag clauses folded into a map). `library_supports_sdk_configuration()` reads the bit. - **The two APM_TRACING builders** take `use_sdk_config`; the `send_*` wrappers detect it. `lib_config` stays the internal representation and `prev_payloads` keeps it, so the "empty config keeps the previous value" inheritance the debugger helpers rely on is unchanged. - **`tests/parametric/test_dynamic_configuration.py`** — translation happens in `_set_rc`, the single choke point that owns `test_agent`. `assert_rc_capability()` accepts the legacy per-setting bit **or** `SDK_CONFIGURATION`, since one bit now covers them all. - **`tests/parametric/capabilities.yml`** — nodejs's per-setting bits scoped to `<7.0.0-0`. - **`tests/test_library_conf.py`** — `Test_HeaderTags_DynamicConfig` routed through the same translation (`missing_feature` for nodejs today, but it builds its own APM_TRACING payload). - **`tests/test_the_test/test_remote_config.py`** — 7 unit tests covering the translation, the value serializers, and that the mapping stays exhaustive over what the builders can emit. **Nothing changes for any library that does not advertise the bit** — today that is every library, including nodejs on `main`. ### Notes for reviewers - **`capabilities.yml`**: `SDK_CONFIGURATION` is deliberately *not* listed as expected yet. dd-trace-js `main` is `7.0.0-pre` and does not advertise it until #9392 lands; a pre-release is allowed to report capabilities beyond the expected set, so the `<7.0.0-0` bound alone covers both sides of the transition without a chicken-and-egg break. A follow-up should add `'>=7.0.0-0': [SDK_CONFIGURATION]` once #9392 merges. The bound assumes the removal ships in 7.0.0; if a 7.0.0 is cut before #9392 lands, the bound needs moving. - **`dynamic_sampling_enabled` and `live_debugging_enabled`** are remote-config-only settings with no environment variable, so they cannot be expressed as `sdk_config` and are dropped for libraries on the new contract. Both are already ignored by dd-trace-js, so nothing regresses; the mapping records them explicitly as `None` rather than guessing a name. - **`provenance` on sampling rules** is carried through in the `DD_TRACE_SAMPLING_RULES` JSON. dd-trace-js's `SamplingRule` reads it, so `_dd.p.dm` `-11`/`-12` should still be produced through the env-var path — worth confirming on the #9392 run, as it is a library-side behaviour, not a payload one. ### Testing - `./run.sh TEST_THE_TEST` — 445 passed - `./format.sh` — clean - Replayed the 4-step RC sequence of `test_inproduct_enablement_di` through the js reader's allowlist/merge logic: unset → `{}`, enable → `DD_DYNAMIC_INSTRUMENTATION_ENABLED=true`, empty → inherits `true`, disable → `false`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Original commits: * 3dfdf77 Send APM_TRACING configs as sdk_config when the library supports it * 79eb84b Only switch to sdk_config once the per-setting capabilities are gone * 4b083d7 Merge branch 'main' into rachel.yang/rc-sdk-configuration-payload * a6d1cf1 Send sdk_config.config as a flat map, not a list of key/value pairs * 23eb101 Address review: require APM_TRACING evidence, share one resolver * 7b06755 Merge remote-tracking branch 'origin/main' into rachel.yang/rc-sdk-configuration-payload * 626430b Merge branch 'main' into rachel.yang/rc-sdk-configuration-payload Signed-off-by: Rachel Yang <rachel.yang@datadoghq.com>
626430b to
3c9f304
Compare
Motivation
dd-trace-js#9392 is the first library to move to the unified Config at Runtime contract, and it fails 7 system-tests jobs:
DEBUGGER_INPRODUCT_ENABLEMENT× 5 weblogs —Test_Debugger_InProduct_Enablement_Dynamic_Instrumentation::test_inproduct_enablement_diPARAMETRIC× 2 — 10 behaviour tests + 7 capability tests intest_dynamic_configuration.pyThat PR swaps the whole APM_TRACING contract:
APM_TRACING_SAMPLE_RATE,_LOGS_INJECTION,_HTTP_HEADER_TAGS,_CUSTOM_TAGS,_ENABLED,_SAMPLE_RULES,_ENABLE_DYNAMIC_INSTRUMENTATION,_ENABLE_CODE_ORIGIN,_ENABLE_LIVE_DEBUGGINGSDK_CONFIGURATION(bit 49)lib_config: {dynamic_instrumentation_enabled: true}sdk_config: {service_name, env, config: [{key: "DD_DYNAMIC_INSTRUMENTATION_ENABLED", value: "true"}]}The
lib_configbranch is removed, not kept as a fallback —RCClientManager.addConfigonly readsconf.sdk_config?.config. system-tests only ever emitslib_config, so every APM_TRACING config becomes a no-op: DI is never enabled, probes never reachEMITTING, and the test fails.What does this PR do?
The RC helpers now read the capability bit the library advertises on
/v0.7/configand, whenSDK_CONFIGURATIONis set, send the same settings in the new shape.service_targetis untouched — it still drives matching and priority.utils/_remote_config.py—to_sdk_config_payload()rewrites an APM_TRACING config fromlib_configtosdk_config: each setting keyed by its canonicalDD_*name, serialized to its environment variable form (booleans, sample rate,tracing_header_tags→"h:tag,…",tracing_tags→"k:v,…",tracing_service_mapping→"a:b,…",tracing_sampling_rules→ JSON with the[{key, value_glob}]tag clauses folded into a map).library_supports_sdk_configuration()reads the bit.use_sdk_config; thesend_*wrappers detect it.lib_configstays the internal representation andprev_payloadskeeps it, so the "empty config keeps the previous value" inheritance the debugger helpers rely on is unchanged.tests/parametric/test_dynamic_configuration.py— translation happens in_set_rc, the single choke point that ownstest_agent.assert_rc_capability()accepts the legacy per-setting bit orSDK_CONFIGURATION, since one bit now covers them all.tests/parametric/capabilities.yml— nodejs's per-setting bits scoped to<7.0.0-0.tests/test_library_conf.py—Test_HeaderTags_DynamicConfigrouted through the same translation (missing_featurefor nodejs today, but it builds its own APM_TRACING payload).tests/test_the_test/test_remote_config.py— 7 unit tests covering the translation, the value serializers, and that the mapping stays exhaustive over what the builders can emit.Nothing changes for any library that does not advertise the bit — today that is every library, including nodejs on
main.Notes for reviewers
capabilities.yml:SDK_CONFIGURATIONis deliberately not listed as expected yet. dd-trace-jsmainis7.0.0-preand does not advertise it until #9392 lands; a pre-release is allowed to report capabilities beyond the expected set, so the<7.0.0-0bound alone covers both sides of the transition without a chicken-and-egg break. A follow-up should add'>=7.0.0-0': [SDK_CONFIGURATION]once #9392 merges. The bound assumes the removal ships in 7.0.0; if a 7.0.0 is cut before #9392 lands, the bound needs moving.dynamic_sampling_enabledandlive_debugging_enabledare remote-config-only settings with no environment variable, so they cannot be expressed assdk_configand are dropped for libraries on the new contract. Both are already ignored by dd-trace-js, so nothing regresses; the mapping records them explicitly asNonerather than guessing a name.provenanceon sampling rules is carried through in theDD_TRACE_SAMPLING_RULESJSON. dd-trace-js'sSamplingRulereads it, so_dd.p.dm-11/-12should still be produced through the env-var path — worth confirming on the #9392 run, as it is a library-side behaviour, not a payload one.Testing
./run.sh TEST_THE_TEST— 445 passed./format.sh— cleantest_inproduct_enablement_dithrough the js reader's allowlist/merge logic: unset →{}, enable →DD_DYNAMIC_INSTRUMENTATION_ENABLED=true, empty → inheritstrue, disable →false.🤖 Generated with Claude Code