Skip to content

Commit fe21e68

Browse files
authored
fix(telemetry): send app-started asynchronously (#218)
This addresses a regression introduced in dd-trace-cpp#205 that caused a noticeable delay during the first initialization of the library.
1 parent a328a6d commit fe21e68

File tree

3 files changed

+82
-36
lines changed

3 files changed

+82
-36
lines changed

src/datadog/telemetry/telemetry.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ TelemetryProxy make_telemetry(const Ctor_param& init) {
4242

4343
TelemetryProxy& instance(
4444
const tracing::Optional<Ctor_param>& init = tracing::nullopt) {
45-
static TelemetryProxy telemetry(make_telemetry(*init));
45+
static TelemetryProxy telemetry = make_telemetry(*init);
4646
return telemetry;
4747
}
4848

src/datadog/telemetry/telemetry_impl.cpp

Lines changed: 75 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -208,16 +208,14 @@ Telemetry::Telemetry(FinalizedConfiguration config,
208208
clock_(std::move(clock)),
209209
scheduler_(event_scheduler),
210210
host_info_(get_host_info()) {
211-
send_telemetry("app-started", app_started());
212-
http_client_->drain(clock_().tick + request_timeout);
211+
app_started();
213212
schedule_tasks();
214213
}
215214

216215
void Telemetry::schedule_tasks() {
217216
tasks_.emplace_back(scheduler_->schedule_recurring_event(
218-
config_.heartbeat_interval, [this]() {
219-
send_telemetry("app-heartbeat", heartbeat_and_telemetry());
220-
}));
217+
config_.heartbeat_interval,
218+
[this]() { send_payload("app-heartbeat", heartbeat_and_telemetry()); }));
221219

222220
if (config_.report_metrics) {
223221
tasks_.emplace_back(scheduler_->schedule_recurring_event(
@@ -228,11 +226,7 @@ void Telemetry::schedule_tasks() {
228226
Telemetry::~Telemetry() {
229227
if (!tasks_.empty()) {
230228
cancel_tasks(tasks_);
231-
capture_metrics();
232-
// The app-closing message is bundled with a message containing the
233-
// final metric values.
234-
send_telemetry("app-closing", app_closing());
235-
http_client_->drain(clock_().tick + request_timeout);
229+
app_closing();
236230
}
237231
}
238232

@@ -298,31 +292,80 @@ void Telemetry::log_warning(std::string message) {
298292
log(std::move(message), LogLevel::WARNING);
299293
}
300294

301-
void Telemetry::send_telemetry(StringView request_type, std::string payload) {
295+
void Telemetry::app_started() {
296+
auto payload = app_started_payload();
297+
298+
auto on_headers = [payload_size = payload.size(),
299+
debug_enabled = config_.debug](DictWriter& headers) {
300+
headers.set("Content-Type", "application/json");
301+
headers.set("Content-Length", std::to_string(payload_size));
302+
headers.set("DD-Telemetry-API-Version", "v2");
303+
headers.set("DD-Client-Library-Language", "cpp");
304+
headers.set("DD-Client-Library-Version", tracer_version);
305+
headers.set("DD-Telemetry-Request-Type", "app-started");
306+
if (debug_enabled) {
307+
headers.set("DD-Telemetry-Debug-Enabled", "true");
308+
}
309+
};
310+
311+
auto on_response = [logger = logger_](int response_status, const DictReader&,
312+
std::string response_body) {
313+
if (response_status < 200 || response_status >= 300) {
314+
logger->log_error([&](auto& stream) {
315+
stream << "Unexpected telemetry response status " << response_status
316+
<< " with body (if any, starts on next line):\n"
317+
<< response_body;
318+
});
319+
}
320+
};
321+
322+
auto on_error = [logger = logger_](Error error) {
323+
logger->log_error(error.with_prefix(
324+
"Error occurred during HTTP request for telemetry: "));
325+
};
326+
327+
increment_counter(internal_metrics::requests, {"endpoint:agent"});
328+
add_datapoint(internal_metrics::bytes_sent, {"endpoint:agent"},
329+
payload.size());
330+
331+
auto post_result =
332+
http_client_->post(telemetry_endpoint_, on_headers, std::move(payload),
333+
std::move(on_response), std::move(on_error),
334+
clock_().tick + request_timeout);
335+
if (auto* error = post_result.if_error()) {
336+
increment_counter(internal_metrics::errors,
337+
{"type:network", "endpoint:agent"});
338+
logger_->log_error(
339+
error->with_prefix("Unexpected error submitting telemetry event: "));
340+
}
341+
}
342+
343+
void Telemetry::app_closing() {
344+
// Capture metrics in-between two ticks to be sent with the last payload.
345+
capture_metrics();
346+
347+
send_payload("app-closing", app_closing_payload());
348+
http_client_->drain(clock_().tick + request_timeout);
349+
}
350+
351+
void Telemetry::send_payload(StringView request_type, std::string payload) {
302352
auto set_telemetry_headers = [request_type, payload_size = payload.size(),
303-
debug_enabled = config_.debug,
304-
tracer_signature =
305-
&tracer_signature_](DictWriter& headers) {
306-
/*
307-
TODO:
308-
Datadog-Container-ID
309-
*/
353+
debug_enabled =
354+
config_.debug](DictWriter& headers) {
310355
headers.set("Content-Type", "application/json");
311356
headers.set("Content-Length", std::to_string(payload_size));
312357
headers.set("DD-Telemetry-API-Version", "v2");
313358
headers.set("DD-Client-Library-Language", "cpp");
314-
headers.set("DD-Client-Library-Version", tracer_signature->library_version);
359+
headers.set("DD-Client-Library-Version", tracer_version);
315360
headers.set("DD-Telemetry-Request-Type", request_type);
316-
317361
if (debug_enabled) {
318362
headers.set("DD-Telemetry-Debug-Enabled", "true");
319363
}
320364
};
321365

322-
auto telemetry_on_response = [this, logger = logger_](
323-
int response_status,
324-
const DictReader& /*response_headers*/,
325-
std::string response_body) {
366+
auto on_response = [this, logger = logger_](int response_status,
367+
const DictReader&,
368+
std::string response_body) {
326369
if (response_status >= 500) {
327370
increment_counter(internal_metrics::responses,
328371
{"status_code:5xx", "endpoint:agent"});
@@ -350,7 +393,7 @@ void Telemetry::send_telemetry(StringView request_type, std::string payload) {
350393
};
351394

352395
// Callback for unsuccessful telemetry HTTP requests.
353-
auto telemetry_on_error = [this, logger = logger_](Error error) {
396+
auto on_error = [this, logger = logger_](Error error) {
354397
increment_counter(internal_metrics::errors,
355398
{"type:network", "endpoint:agent"});
356399
logger->log_error(error.with_prefix(
@@ -361,10 +404,10 @@ void Telemetry::send_telemetry(StringView request_type, std::string payload) {
361404
add_datapoint(internal_metrics::bytes_sent, {"endpoint:agent"},
362405
payload.size());
363406

364-
auto post_result = http_client_->post(
365-
telemetry_endpoint_, set_telemetry_headers, std::move(payload),
366-
std::move(telemetry_on_response), std::move(telemetry_on_error),
367-
clock_().tick + request_timeout);
407+
auto post_result =
408+
http_client_->post(telemetry_endpoint_, set_telemetry_headers,
409+
std::move(payload), std::move(on_response),
410+
std::move(on_error), clock_().tick + request_timeout);
368411
if (auto* error = post_result.if_error()) {
369412
increment_counter(internal_metrics::errors,
370413
{"type:network", "endpoint:agent"});
@@ -390,7 +433,7 @@ void Telemetry::send_configuration_change() {
390433
telemetry_body["payload"] =
391434
nlohmann::json{{"configuration", configuration_json}};
392435

393-
send_telemetry("app-client-configuration-change", telemetry_body.dump());
436+
send_payload("app-client-configuration-change", telemetry_body.dump());
394437
}
395438

396439
std::string Telemetry::heartbeat_and_telemetry() {
@@ -475,7 +518,7 @@ std::string Telemetry::heartbeat_and_telemetry() {
475518
return message_batch_payload;
476519
}
477520

478-
std::string Telemetry::app_closing() {
521+
std::string Telemetry::app_closing_payload() {
479522
auto batch_payloads = nlohmann::json::array();
480523

481524
auto app_closing = nlohmann::json::object({
@@ -532,7 +575,7 @@ std::string Telemetry::app_closing() {
532575
return message_batch_payload;
533576
}
534577

535-
std::string Telemetry::app_started() {
578+
std::string Telemetry::app_started_payload() {
536579
auto configuration_json = nlohmann::json::array();
537580
auto product_json = nlohmann::json::object();
538581

src/datadog/telemetry/telemetry_impl.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,10 @@ class Telemetry final {
129129
const std::vector<std::string>& tags, uint64_t value);
130130

131131
private:
132-
void send_telemetry(tracing::StringView request_type, std::string payload);
132+
void app_started();
133+
void app_closing();
134+
135+
void send_payload(tracing::StringView request_type, std::string payload);
133136

134137
void schedule_tasks();
135138

@@ -144,13 +147,13 @@ class Telemetry final {
144147

145148
// Constructs an `app-started` message using information provided when
146149
// constructed and the tracer_config value passed in.
147-
std::string app_started();
150+
std::string app_started_payload();
148151
// Constructs a messsage-batch containing `app-heartbeat`, and if metrics
149152
// have been modified, a `generate-metrics` message.
150153
std::string heartbeat_and_telemetry();
151154
// Constructs a message-batch containing `app-closing`, and if metrics have
152155
// been modified, a `generate-metrics` message.
153-
std::string app_closing();
156+
std::string app_closing_payload();
154157
};
155158

156159
} // namespace datadog::telemetry

0 commit comments

Comments
 (0)