Add end-to-end test for app-extended-heartbeat telemetry event#6338
Draft
khanayan123 wants to merge 46 commits intomainfrom
Draft
Add end-to-end test for app-extended-heartbeat telemetry event#6338khanayan123 wants to merge 46 commits intomainfrom
khanayan123 wants to merge 46 commits intomainfrom
Conversation
Add comprehensive parametric test suite for app-extended-heartbeat telemetry event across all SDK languages. Tests verify timing, payload structure, consistency, and compliance with API spec. Tests added: - test_extended_heartbeat_emission: Verifies interval timing - test_extended_heartbeat_sequence: Validates multiple events - test_extended_heartbeat_payload_content: Checks required fields - test_extended_heartbeat_matches_app_started: Ensures consistency - test_extended_heartbeat_excludes_products_and_install_signature - test_extended_heartbeat_default_interval: Validates 24h default All tests run parametrically across 9 SDK languages (Go, Java, .NET, C++, PHP, Ruby, Rust, Python, Node.js). Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Contributor
|
|
Register comprehensive parametric tests for app-extended-heartbeat event validation across all SDK languages. Tests verify: - Periodic emission timing (24h default, configurable) - Payload structure (config, deps, integrations) - Consistency with app-started event - Proper field exclusions (products, install_signature) Language version markers: - Go: v1.73.0-dev - Java: v1.40.0 - Node.js: v5.0.0 - Python: v2.0.0 - Ruby: v2.1.0-dev - C++: v0.2.0-dev - PHP: v1.0.0-dev - .NET: missing_feature (intentionally skipped - no forked runtime-id issues) Tests use fast intervals (0.3-0.5s) for CI efficiency. Test location: tests/parametric/test_telemetry.py::Test_ExtendedHeartbeat (lines 1256-1514) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Changed Test_ExtendedHeartbeat manifest entries from development version strings (e.g., v1.73.0-dev, v2.1.0-dev) to missing_feature to follow repository conventions. Development versions should not be specified in manifests. Tests for unreleased features should use missing_feature until the feature is actually released in a production version. Changes: - cpp.yml: v0.2.0-dev → missing_feature - golang.yml: v1.73.0-dev → missing_feature - nodejs.yml: '>=5.0.0' → missing_feature - php.yml: v1.0.0-dev → missing_feature - ruby.yml: v2.1.0-dev → missing_feature 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
…tionality Replace 6 complex test methods with a single simplified test that focuses on the core requirement: comparing configurations across telemetry events. The new test: - Grabs app-started, app-extended-heartbeat, and app-client-configuration-change events - Extracts configuration data from each - Asserts configs match between app-started and app-extended-heartbeat - Optionally validates config-change event configs match as well This reduces test complexity from ~260 lines to ~40 lines while maintaining coverage of the critical functionality. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Configure manifests to run app-extended-heartbeat tests only on Node.js for initial validation: - Enable Node.js: *ref_5_0_0 (>=5.0.0) - Disable Python: v2.0.0 -> missing_feature - Disable Java: v1.40.0 -> missing_feature - Keep all others disabled: missing_feature (cpp, dotnet, php, golang, ruby) This allows focused testing of Node.js implementation before enabling other languages. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add SLF001 exception for test_telemetry.py to allow _get_telemetry_event usage - Fix nodejs.yml manifest to use '>=5.0.0' instead of non-existent anchor - All linting checks now pass (mypy, ruff, yamlfmt, yamllint, shellcheck) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
Java tracer supports configurable extended heartbeat interval via DD_TELEMETRY_EXTENDED_HEARTBEAT_INTERVAL, so enable the parametric tests.
Resolve merge conflicts in manifests/java.yml, manifests/ruby.yml, and tests/parametric/test_telemetry.py. Keep Test_ExtendedHeartbeat additions while incorporating main's telemetry key normalization and stable configuration origin updates. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Revert pyproject.toml changes (not needed for this PR) and remove DD_TELEMETRY_HEARTBEAT_INTERVAL from Test_ExtendedHeartbeat since we only need to configure the extended heartbeat interval. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use integer interval (1s) for Java compatibility (getLong) - Assert configs as superset with value matching, order-agnostic - Build expected config from app-started + config-change overlay - Collect all config-change events, not just the last one Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This was referenced Mar 31, 2026
gh-worker-dd-mergequeue-cf854d bot
pushed a commit
to DataDog/dd-trace-py
that referenced
this pull request
Mar 31, 2026
…eat payload (#17203) ## Summary Fix the extended heartbeat payload key from `"configurations"` (plural) to `"configuration"` (singular) to match the [telemetry v2 API spec](https://github.com/DataDog/instrumentation-telemetry-api-docs/blob/main/GeneratedDocumentation/ApiDocs/v2/SchemaDocumentation/Schemas/app_extended_heartbeat.md) and align with other SDKs (Java, .NET, Node.js). ## Changes - **`ddtrace/internal/telemetry/writer.py`**: `payload["configurations"]` → `payload["configuration"]` - **`tests/telemetry/test_telemetry.py`**: Updated test assertions to match ## Motivation Cross-SDK system tests validate that `app-extended-heartbeat` payloads use the same schema. The spec and all other SDKs use `"configuration"` (singular). This mismatch would cause system test & dropped telemetry payloads failures for Python. ## Related - System test PR: DataDog/system-tests#6338 - Original Python implementation: #16628 Co-authored-by: ayan.khan <ayan.khan@datadoghq.com>
Resolve merge conflict in manifests/ruby.yml (kept both Test_ExtendedHeartbeat and updated Test_Stable_Configuration_Origin). Fix ruff lint issues: D209 docstring closing quotes and SLF001 private member access noqa annotations in test_telemetry.py. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
cbeauchesne
reviewed
Apr 1, 2026
Collaborator
cbeauchesne
left a comment
There was a problem hiding this comment.
There is already test on heartbeats in DEFAULT scenario.
If you plan to test only one or two set of parameters, then the end-to-end DEFAULT scenario is a best fit from a quality POV as the coverage is by far more complete.
We can chat more about what are the good/bad use cases for parametric/end-to-end if you want, just ping me !
gh-worker-dd-mergequeue-cf854d bot
pushed a commit
to DataDog/libdatadog
that referenced
this pull request
Apr 1, 2026
…cheduler (#1824) ## Summary Wire up the `DD_TELEMETRY_EXTENDED_HEARTBEAT_INTERVAL` config value to the telemetry scheduler. The env var was already parsed into `config.telemetry_extended_heartbeat_interval` but the scheduler hardcoded `Duration::from_secs(60 * 60 * 24)` instead of using it. Default remains 24h this only enables system tests to use a shorter interval to validate the `app-extended-heartbeat` event fires correctly. ## Changes - **`libdd-telemetry/src/worker/mod.rs`**: Replace hardcoded `60 * 60 * 24` with `config.telemetry_extended_heartbeat_interval` ## Motivation Cross-SDK system tests need to set a short extended heartbeat interval (e.g., 2s) to validate parity of the `app-extended-heartbeat` telemetry event across all SDKs. Without this fix, PHP and other libdatadog consumers cannot be system-tested for this feature. ## Related - System test PR: DataDog/system-tests#6338 Co-authored-by: edmund.kump <edmund.kump@datadoghq.com>
Add Test_ExtendedHeartbeat to tests/test_telemetry.py for the DEFAULT scenario, validating that extended heartbeat config is a superset of app-started plus any config changes. Set DD_TELEMETRY_EXTENDED_HEARTBEAT_INTERVAL env var in weblog containers. Add manifest entries for all libraries. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move DD_TELEMETRY_EXTENDED_HEARTBEAT_INTERVAL from base container env to the DEFAULT scenario weblog_env where it belongs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The extended heartbeat validation is better suited as an end-to-end test in the DEFAULT scenario where it exercises the full tracer stack. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Relax the superset assertion to only validate that configs present in both app-started and app-extended-heartbeat have matching values. Some tracers may not track all configs in _sent_configs, so a strict superset check causes false failures. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ogic" This reverts commit 1bfb4b8.
Use the last app-extended-heartbeat that appears after the last app-client-configuration-change in the telemetry stream. This ensures the heartbeat has had a chance to include all lazily registered configs (e.g. DD_LLMOBS_EVALUATOR_SAMPLING_RULES in Python which is registered during LLMObs.enable()). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
b0c8500 to
388375a
Compare
The TELEMETRY_EXTENDED_HEARTBEAT scenario runs only this test, so the weblog is up for just a few seconds. Add a setup method that triggers a weblog request and waits 10s to ensure all lazy configs are registered and an extended heartbeat fires after the last config-change event. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix pytest setup method naming (setup_<name> matches test_<name>). Use interfaces.library.wait_for() to wait for the first extended heartbeat event, then sleep 5s to allow lazily registered configs to flush and a subsequent extended heartbeat to include them. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The wait_for callback iterates all interface data, including entries without request.content. Use safe dict access to avoid AttributeError. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
gh-worker-dd-mergequeue-cf854d bot
pushed a commit
to DataDog/dd-trace-go
that referenced
this pull request
Apr 2, 2026
… support (#4621) ## Summary Read `DD_TELEMETRY_EXTENDED_HEARTBEAT_INTERVAL` from the environment to allow configuring the extended heartbeat interval. This is only added so system tests can use a short interval to validate `app-extended-heartbeat` parity across all SDK tracers. Default remains 24h. ## Changes - **`internal/telemetry/client_config.go`**: Read `DD_TELEMETRY_EXTENDED_HEARTBEAT_INTERVAL` via `FloatEnv`, following the same pattern as `DD_TELEMETRY_HEARTBEAT_INTERVAL` ## Related - System test PR: DataDog/system-tests#6338 - Telemetry v2 API spec: https://github.com/DataDog/instrumentation-telemetry-api-docs/blob/main/GeneratedDocumentation/ApiDocs/v2/SchemaDocumentation/Schemas/app_extended_heartbeat.md Co-authored-by: ayan.khan <ayan.khan@datadoghq.com>
wait_for iterates all interface data including non-telemetry entries that lack request.content, causing AttributeError. Use time.sleep(15) which is the established pattern for telemetry setup methods. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use the SDK-provided tracer_time to determine which config events the extended heartbeat could have seen. Only compare against app-started and config-change events with tracer_time <= the extended heartbeat's tracer_time. This avoids false failures from lazily registered configs that arrive after the heartbeat. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Some weblogs (e.g. gunicorn with Python) fork workers that each have their own telemetry writer with a different runtime_id and different _sent_configs state. Filter all events by the runtime_id from app-started to ensure we compare events from the same process. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Instead of filtering by runtime_id, collect configs from ALL extended heartbeats and verify that every config from app-started/config-change was reported by at least one extended heartbeat with a tracer_time >= when the config was first reported. This handles forked workers (e.g. gunicorn) where different processes have different runtime_ids and different _sent_configs state. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Drop tracer_time ordering checks — configs can appear in heartbeats before they are re-reported in config-change events (e.g. remote config updates). Simply verify every config name from app-started and config-change events appears in at least one extended heartbeat. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Follow the pattern of other telemetry setup methods which just trigger a weblog request without sleeping. The test checks across all collected heartbeats so no explicit wait is needed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Set golang manifest to >2.7.1 (latest is v2.7.1, next release will include extended heartbeat support). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
dd-trace-go's extended heartbeat only includes configs from app-started, not from app-client-configuration-change events. The heartbeatEnricher.Transform() only handles AppStarted, AppDependenciesLoaded, and AppIntegrationChange payloads. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
gh-worker-dd-mergequeue-cf854d bot
pushed a commit
to DataDog/dd-trace-go
that referenced
this pull request
Apr 8, 2026
…entire config state (#4633) ### What does this PR do? Replace the push-based config accumulation in `heartbeatEnricher` with a pull model that reads the full config state on demand from the `configuration` data source. **Problem:** `heartbeatEnricher` had an `AppStarted` case to capture startup configs, but it was unreachable because `appStartedReducer` consumed the `AppStarted` payload before `heartbeatEnricher` could see it. The extended heartbeat was missing all startup configurations. **Solution:** The `configuration` data source now retains all registered configs (using a `pending` set to track deltas for `Payload()`) and exposes an `All()` method. `heartbeatEnricher` calls `getConfigs()` when emitting the extended heartbeat to get the full current state directly from the source of truth. **Changes:** - `configuration.go` — Single map with `pending` set. `Add()` writes to config and marks pending. `Payload()` extracts only pending keys. New `All()` returns full accumulated state. - `internal/mapper/default.go` — `NewDefaultMapper` accepts `func() []transport.ConfKeyValue`. `heartbeatEnricher` pulls configs on demand instead of accumulating from pipeline. Removed `AppStarted` case. - `client.go` — Passes `configuration.All` to `NewDefaultMapper`. - `client_test.go` — Added integration tests for extended heartbeat config inclusion (single, multiple, dedup). ### Motivation Discovered while adding `app-extended-heartbeat` system tests in [DataDog/system-tests#6338](DataDog/system-tests#6338). The extended heartbeat was missing startup configs because `appStartedReducer` consumed them before `heartbeatEnricher` could see them. Rather than work around the pipeline ordering issue, this PR fixes the root cause by having `heartbeatEnricher` read config state directly from the source of truth. API spec for reference: https://github.com/DataDog/instrumentation-telemetry-api-docs/blob/main/GeneratedDocumentation/ApiDocs/v2/SchemaDocumentation/Schemas/app_extended_heartbeat.md Co-authored-by: ayan.khan <ayan.khan@datadoghq.com>
dd-trace-js merged support for DD_TELEMETRY_EXTENDED_HEARTBEAT_INTERVAL. Set manifest to >5.96.0 (latest is v5.96.0). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6980c96 to
9d3aa89
Compare
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PHP telemetry runs via a sidecar process which does not emit app-extended-heartbeat events yet, even though libdatadog supports the DD_TELEMETRY_EXTENDED_HEARTBEAT_INTERVAL env var. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add a new
TELEMETRY_EXTENDED_HEARTBEATend-to-end scenario that validates theapp-extended-heartbeattelemetry event across all SDK languages (Go, Java, .NET, C++, PHP, Ruby, Rust, Python, Node.js).Changes
New scenario & test
utils/_context/_scenarios/__init__.py: NewTELEMETRY_EXTENDED_HEARTBEATscenario with shortened intervals (DD_TELEMETRY_HEARTBEAT_INTERVAL=1,DD_TELEMETRY_EXTENDED_HEARTBEAT_INTERVAL=2) so the event fires within test timeoutstests/test_telemetry.py: NewTest_ExtendedHeartbeatclass — asserts that every config reported inapp-startedorapp-client-configuration-changeis eventually included in at least oneapp-extended-heartbeateventutils/_features.py: Wired to existing feature flagapp_extended_heartbeat_event(feature 77)Manifest updates
Test_ExtendedHeartbeatat the appropriate tracer versionsTelemetry test fixes (drive-by)
DD_*) and legacy config namesTest plan
TELEMETRY_EXTENDED_HEARTBEATscenario across enabled languagesTest_ExtendedHeartbeatcorrectly detects missing configs whenapp-extended-heartbeatevents are present🤖 Generated with Claude Code