Skip to content

Commit 445f045

Browse files
khanayan123claude
andcommitted
feat(telemetry): implement app-extended-heartbeat event
Add support for the app-extended-heartbeat telemetry event per the telemetry v2 API spec. The event fires periodically (default 24h) and includes the full configuration payload, matching app-started. The interval is configurable via DD_TELEMETRY_EXTENDED_HEARTBEAT_INTERVAL (integer seconds) to enable system testing with shorter intervals. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 910e3d5 commit 445f045

5 files changed

Lines changed: 57 additions & 0 deletions

File tree

include/datadog/environment.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ namespace environment {
6969
MACRO(DD_VERSION, STRING, "") \
7070
MACRO(DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED, BOOLEAN, true) \
7171
MACRO(DD_TELEMETRY_HEARTBEAT_INTERVAL, DECIMAL, 10) \
72+
MACRO(DD_TELEMETRY_EXTENDED_HEARTBEAT_INTERVAL, INT, 86400) \
7273
MACRO(DD_TELEMETRY_METRICS_ENABLED, BOOLEAN, true) \
7374
MACRO(DD_TELEMETRY_METRICS_INTERVAL_SECONDS, DECIMAL, 60) \
7475
MACRO(DD_TELEMETRY_DEBUG, BOOLEAN, false) \

include/datadog/telemetry/configuration.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ struct Configuration {
2929
// Interval at which the heartbeat payload will be sent.
3030
// Can be overriden by `DD_TELEMETRY_HEARTBEAT_INTERVAL` environment variable.
3131
tracing::Optional<double> heartbeat_interval_seconds;
32+
// Interval at which the extended heartbeat payload will be sent.
33+
// Can be overriden by `DD_TELEMETRY_EXTENDED_HEARTBEAT_INTERVAL` environment
34+
// variable. Default: 86400 seconds (24 hours).
35+
tracing::Optional<int> extended_heartbeat_interval_seconds;
3236
// `integration_name` is the name of the product integrating this library.
3337
// Example: "nginx", "envoy" or "istio".
3438
tracing::Optional<std::string> integration_name;
@@ -52,6 +56,7 @@ struct FinalizedConfiguration {
5256
bool report_logs;
5357
std::chrono::steady_clock::duration metrics_interval;
5458
std::chrono::steady_clock::duration heartbeat_interval;
59+
std::chrono::steady_clock::duration extended_heartbeat_interval;
5560
std::string integration_name;
5661
std::string integration_version;
5762
std::vector<Product> products;

src/datadog/telemetry/configuration.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,15 @@ tracing::Expected<Configuration> load_telemetry_env_config() {
4848
env_cfg.heartbeat_interval_seconds = *maybe_value;
4949
}
5050

51+
if (auto extended_heartbeat_interval_seconds =
52+
lookup(environment::DD_TELEMETRY_EXTENDED_HEARTBEAT_INTERVAL)) {
53+
auto maybe_value = parse_double(*extended_heartbeat_interval_seconds);
54+
if (auto error = maybe_value.if_error()) {
55+
return *error;
56+
}
57+
env_cfg.extended_heartbeat_interval_seconds = static_cast<int>(*maybe_value);
58+
}
59+
5160
return env_cfg;
5261
}
5362

@@ -112,6 +121,19 @@ tracing::Expected<FinalizedConfiguration> finalize_config(
112121
std::chrono::duration_cast<std::chrono::milliseconds>(
113122
std::chrono::duration<double>(heartbeat_interval.second));
114123

124+
// extended_heartbeat_interval_seconds
125+
auto extended_heartbeat_interval =
126+
pick(env_config->extended_heartbeat_interval_seconds,
127+
user_config.extended_heartbeat_interval_seconds, 86400);
128+
if (extended_heartbeat_interval.second <= 0) {
129+
return Error{
130+
Error::Code::OUT_OF_RANGE_INTEGER,
131+
"Telemetry extended heartbeat interval must be a positive value"};
132+
}
133+
result.extended_heartbeat_interval =
134+
std::chrono::duration_cast<std::chrono::milliseconds>(
135+
std::chrono::seconds(extended_heartbeat_interval.second));
136+
115137
// integration_name
116138
std::tie(origin, result.integration_name) =
117139
pick(env_config->integration_name, user_config.integration_name,

src/datadog/telemetry/telemetry_impl.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,10 @@ void Telemetry::schedule_tasks() {
223223
config_.heartbeat_interval,
224224
[this]() { send_payload("app-heartbeat", heartbeat_and_telemetry()); }));
225225

226+
tasks_.emplace_back(scheduler_->schedule_recurring_event(
227+
config_.extended_heartbeat_interval,
228+
[this]() { send_payload("app-extended-heartbeat", extended_heartbeat_payload()); }));
229+
226230
if (config_.report_metrics) {
227231
tasks_.emplace_back(scheduler_->schedule_recurring_event(
228232
config_.metrics_interval, [this]() mutable { capture_metrics(); }));
@@ -678,6 +682,28 @@ std::string Telemetry::app_started_payload() {
678682
return batch.dump();
679683
}
680684

685+
std::string Telemetry::extended_heartbeat_payload() {
686+
auto configuration_json = nlohmann::json::array();
687+
688+
for (const auto& product : config_.products) {
689+
for (const auto& [_, config_metadatas] : product.configurations) {
690+
for (const auto& config_metadata : config_metadatas) {
691+
configuration_json.emplace_back(
692+
generate_configuration_field(config_metadata));
693+
}
694+
}
695+
}
696+
697+
auto extended_hb_msg = nlohmann::json{
698+
{"request_type", "app-extended-heartbeat"},
699+
{"payload", nlohmann::json{{"configuration", configuration_json}}},
700+
};
701+
702+
auto batch = generate_telemetry_body("message-batch");
703+
batch["payload"] = nlohmann::json::array({std::move(extended_hb_msg)});
704+
return batch.dump();
705+
}
706+
681707
nlohmann::json Telemetry::generate_telemetry_body(std::string request_type) {
682708
std::time_t tracer_time = std::chrono::duration_cast<std::chrono::seconds>(
683709
clock_().wall.time_since_epoch())

src/datadog/telemetry/telemetry_impl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ class Telemetry final {
152152
// Constructs a messsage-batch containing `app-heartbeat`, and if metrics
153153
// have been modified, a `generate-metrics` message.
154154
std::string heartbeat_and_telemetry();
155+
// Constructs a message-batch containing `app-extended-heartbeat` with the
156+
// full configuration payload.
157+
std::string extended_heartbeat_payload();
155158
// Constructs a message-batch containing `app-closing`, and if metrics have
156159
// been modified, a `generate-metrics` message.
157160
std::string app_closing_payload();

0 commit comments

Comments
 (0)