@@ -227,6 +227,11 @@ void Telemetry::schedule_tasks() {
227227 tasks_.emplace_back (scheduler_->schedule_recurring_event (
228228 config_.metrics_interval , [this ]() mutable { capture_metrics (); }));
229229 }
230+
231+ tasks_.emplace_back (scheduler_->schedule_recurring_event (
232+ config_.extended_heartbeat_interval , [this ]() {
233+ send_payload (" app-extended-heartbeat" , extended_heartbeat_payload ());
234+ }));
230235}
231236
232237Telemetry::~Telemetry () {
@@ -251,6 +256,7 @@ Telemetry::Telemetry(Telemetry&& rhs)
251256 distributions_(std::move(rhs.distributions_)),
252257 seq_id_(rhs.seq_id_),
253258 config_seq_ids_(rhs.config_seq_ids_),
259+ all_configurations_(rhs.all_configurations_),
254260 host_info_(rhs.host_info_) {
255261 cancel_tasks (rhs.tasks_ );
256262 schedule_tasks ();
@@ -274,6 +280,7 @@ Telemetry& Telemetry::operator=(Telemetry&& rhs) {
274280 std::swap (distributions_, rhs.distributions_ );
275281 std::swap (seq_id_, rhs.seq_id_ );
276282 std::swap (config_seq_ids_, rhs.config_seq_ids_ );
283+ std::swap (all_configurations_, rhs.all_configurations_ );
277284 std::swap (host_info_, rhs.host_info_ );
278285 schedule_tasks ();
279286 }
@@ -678,6 +685,24 @@ std::string Telemetry::app_started_payload() {
678685 return batch.dump ();
679686}
680687
688+ std::string Telemetry::extended_heartbeat_payload () {
689+ auto configuration_json = nlohmann::json::array ();
690+
691+ for (const auto & [name, config_metadata] : all_configurations_) {
692+ configuration_json.emplace_back (
693+ serialize_configuration_field (config_metadata, config_seq_ids_[name]));
694+ }
695+
696+ auto extended_hb_msg = nlohmann::json{
697+ {" request_type" , " app-extended-heartbeat" },
698+ {" payload" , nlohmann::json{{" configuration" , configuration_json}}},
699+ };
700+
701+ auto batch = generate_telemetry_body (" message-batch" );
702+ batch[" payload" ] = nlohmann::json::array ({std::move (extended_hb_msg)});
703+ return batch.dump ();
704+ }
705+
681706nlohmann::json Telemetry::generate_telemetry_body (std::string request_type) {
682707 std::time_t tracer_time = std::chrono::duration_cast<std::chrono::seconds>(
683708 clock_ ().wall .time_since_epoch ())
@@ -711,13 +736,8 @@ nlohmann::json Telemetry::generate_telemetry_body(std::string request_type) {
711736 });
712737}
713738
714- nlohmann::json Telemetry::generate_configuration_field (
715- const ConfigMetadata& config_metadata) {
716- // NOTE(@dmehala): `seq_id` should start at 1 so that the go backend can
717- // detect between non set fields.
718- config_seq_ids_[config_metadata.name ] += 1 ;
719- auto seq_id = config_seq_ids_[config_metadata.name ];
720-
739+ nlohmann::json Telemetry::serialize_configuration_field (
740+ const ConfigMetadata& config_metadata, std::size_t seq_id) {
721741 auto j = nlohmann::json{{" name" , to_string (config_metadata.name )},
722742 {" value" , config_metadata.value },
723743 {" seq_id" , seq_id}};
@@ -749,6 +769,16 @@ nlohmann::json Telemetry::generate_configuration_field(
749769 return j;
750770}
751771
772+ nlohmann::json Telemetry::generate_configuration_field (
773+ const ConfigMetadata& config_metadata) {
774+ // NOTE(@dmehala): `seq_id` should start at 1 so that the go backend can
775+ // detect between non set fields.
776+ config_seq_ids_[config_metadata.name ] += 1 ;
777+ all_configurations_[config_metadata.name ] = config_metadata;
778+ return serialize_configuration_field (config_metadata,
779+ config_seq_ids_[config_metadata.name ]);
780+ }
781+
752782void Telemetry::capture_configuration_change (
753783 const std::vector<tracing::ConfigMetadata>& new_configuration) {
754784 configuration_snapshot_.insert (configuration_snapshot_.begin (),
0 commit comments