Skip to content

Commit e777070

Browse files
authored
[part 5] refactor!(telemetry): use configured intervals (#203)
* [part 5] refactor!(telemetry): use configured intervals Previously, telemetry metrics were collected every 10 seconds and heartbeats were sent every 60 seconds, matching the default configuration. However, these intervals can be customized via environment variables or code. This commit updates the telemetry logic to use the configured intervals—whether set through environment variables or directly in the code—ensuring that metrics , heartbeat and logs messages are sent accordingly.
1 parent 18afd17 commit e777070

File tree

2 files changed

+123
-30
lines changed

2 files changed

+123
-30
lines changed

src/datadog/telemetry/telemetry_impl.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -94,18 +94,15 @@ Telemetry::Telemetry(FinalizedConfiguration config,
9494
}
9595

9696
void Telemetry::schedule_tasks() {
97-
// Only schedule this if telemetry is enabled.
98-
// Every 10 seconds, have the tracer telemetry capture the metrics
99-
// values. Every 60 seconds, also report those values to the datadog
100-
// agent.
10197
tasks_.emplace_back(scheduler_->schedule_recurring_event(
102-
std::chrono::seconds(10), [this, n = 0]() mutable {
103-
n++;
104-
tracer_telemetry_->capture_metrics();
105-
if (n % 6 == 0) {
106-
send_heartbeat_and_telemetry();
107-
}
108-
}));
98+
config_.heartbeat_interval,
99+
[this]() { send_heartbeat_and_telemetry(); }));
100+
101+
if (config_.report_metrics) {
102+
tasks_.emplace_back(scheduler_->schedule_recurring_event(
103+
config_.metrics_interval,
104+
[this]() mutable { tracer_telemetry_->capture_metrics(); }));
105+
}
109106
}
110107

111108
Telemetry::~Telemetry() {
@@ -198,14 +195,17 @@ Telemetry& Telemetry::operator=(Telemetry&& rhs) {
198195
}
199196

200197
void Telemetry::log_error(std::string message) {
198+
if (!config_.report_logs) return;
201199
tracer_telemetry_->log(std::move(message), LogLevel::ERROR);
202200
}
203201

204202
void Telemetry::log_error(std::string message, std::string stacktrace) {
203+
if (!config_.report_logs) return;
205204
tracer_telemetry_->log(std::move(message), LogLevel::ERROR, stacktrace);
206205
}
207206

208207
void Telemetry::log_warning(std::string message) {
208+
if (!config_.report_logs) return;
209209
tracer_telemetry_->log(std::move(message), LogLevel::WARNING);
210210
}
211211

test/telemetry/test_telemetry.cpp

Lines changed: 112 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@
1010

1111
#include "datadog/runtime_id.h"
1212
#include "datadog/telemetry/telemetry_impl.h"
13-
#include "mocks/event_schedulers.h"
1413
#include "mocks/http_clients.h"
1514
#include "mocks/loggers.h"
1615
#include "test.h"
1716

1817
using namespace datadog::tracing;
1918
using namespace datadog::telemetry;
19+
using namespace std::chrono_literals;
2020

2121
namespace {
2222
bool is_valid_telemetry_payload(const nlohmann::json& json) {
@@ -31,6 +31,43 @@ bool is_valid_telemetry_payload(const nlohmann::json& json) {
3131
json.contains("/host"_json_pointer);
3232
}
3333

34+
struct FakeEventScheduler : public EventScheduler {
35+
size_t count_tasks = 0;
36+
std::function<void()> heartbeat_callback = nullptr;
37+
std::function<void()> metrics_callback = nullptr;
38+
Optional<std::chrono::steady_clock::duration> heartbeat_interval;
39+
Optional<std::chrono::steady_clock::duration> metrics_interval;
40+
bool cancelled = false;
41+
42+
// NOTE: White box testing. This is a limitation of the event scheduler API.
43+
Cancel schedule_recurring_event(std::chrono::steady_clock::duration interval,
44+
std::function<void()> callback) override {
45+
if (count_tasks == 0) {
46+
heartbeat_callback = callback;
47+
heartbeat_interval = interval;
48+
} else if (count_tasks == 1) {
49+
metrics_callback = callback;
50+
metrics_interval = interval;
51+
}
52+
count_tasks++;
53+
return [this]() { cancelled = true; };
54+
}
55+
56+
void trigger_heartbeat() {
57+
assert(heartbeat_callback != nullptr);
58+
heartbeat_callback();
59+
}
60+
61+
void trigger_metrics_capture() {
62+
assert(metrics_callback != nullptr);
63+
metrics_callback();
64+
}
65+
66+
std::string config() const override {
67+
return nlohmann::json::object({{"type", "FakeEventScheduler"}}).dump();
68+
}
69+
};
70+
3471
} // namespace
3572

3673
TEST_CASE("Tracer telemetry", "[telemetry]") {
@@ -43,27 +80,13 @@ TEST_CASE("Tracer telemetry", "[telemetry]") {
4380

4481
auto logger = std::make_shared<MockLogger>();
4582
auto client = std::make_shared<MockHTTPClient>();
46-
auto scheduler = std::make_shared<MockEventScheduler>();
47-
48-
auto trigger_heartbeat = [&]() {
49-
// White box testing. The current implementation send a heartbeat every 60s
50-
// and the task is executed every 10s.
51-
// TODO(@dmehala): should depends on the config
52-
scheduler->event_callback();
53-
scheduler->event_callback();
54-
scheduler->event_callback();
55-
scheduler->event_callback();
56-
scheduler->event_callback();
57-
scheduler->event_callback();
58-
};
83+
auto scheduler = std::make_shared<FakeEventScheduler>();
5984

6085
const TracerSignature tracer_signature{
6186
/* runtime_id = */ RuntimeID::generate(),
6287
/* service = */ "testsvc",
6388
/* environment = */ "test"};
6489

65-
const std::string ignore{""};
66-
6790
auto url = HTTPClient::URL::parse("http://localhost:8000");
6891
Telemetry telemetry{*finalize_config(),
6992
logger,
@@ -227,7 +250,7 @@ TEST_CASE("Tracer telemetry", "[telemetry]") {
227250

228251
SECTION("generates a heartbeat message") {
229252
client->clear();
230-
trigger_heartbeat();
253+
scheduler->trigger_heartbeat();
231254

232255
auto heartbeat_message = client->request_body;
233256
auto message_batch = nlohmann::json::parse(heartbeat_message);
@@ -240,7 +263,8 @@ TEST_CASE("Tracer telemetry", "[telemetry]") {
240263
SECTION("captures metrics and sends generate-metrics payload") {
241264
telemetry.metrics().tracer.trace_segments_created_new.inc();
242265
REQUIRE(telemetry.metrics().tracer.trace_segments_created_new.value() == 1);
243-
trigger_heartbeat();
266+
scheduler->trigger_metrics_capture();
267+
scheduler->trigger_heartbeat();
244268

245269
REQUIRE(telemetry.metrics().tracer.trace_segments_created_new.value() == 0);
246270

@@ -322,7 +346,7 @@ TEST_CASE("Tracer telemetry", "[telemetry]") {
322346

323347
client->clear();
324348
test_case.apply(telemetry, test_case.input, test_case.stacktrace);
325-
trigger_heartbeat();
349+
scheduler->trigger_heartbeat();
326350

327351
auto message_batch = nlohmann::json::parse(client->request_body);
328352
REQUIRE(is_valid_telemetry_payload(message_batch));
@@ -345,3 +369,72 @@ TEST_CASE("Tracer telemetry", "[telemetry]") {
345369
}
346370
}
347371
}
372+
373+
TEST_CASE("Tracer telemetry configuration", "[telemetry]") {
374+
// Cases:
375+
// - when `report_metrics` is set to false. No metrics are reported.
376+
// - when `report_logs` is set to false. No logs are reported.
377+
// - respects interval defined.
378+
// - telemetry disabled doesn't send anything.
379+
380+
auto logger = std::make_shared<MockLogger>();
381+
auto client = std::make_shared<MockHTTPClient>();
382+
auto scheduler = std::make_shared<FakeEventScheduler>();
383+
std::vector<std::shared_ptr<Metric>> metrics;
384+
385+
const TracerSignature tracer_signature{
386+
/* runtime_id = */ RuntimeID::generate(),
387+
/* service = */ "testsvc",
388+
/* environment = */ "test"};
389+
390+
auto url = HTTPClient::URL::parse("http://localhost:8000");
391+
392+
SECTION("disabling metrics reporting do not collect metrics") {
393+
Configuration cfg;
394+
cfg.report_metrics = false;
395+
396+
auto final_cfg = finalize_config(cfg);
397+
REQUIRE(final_cfg);
398+
399+
Telemetry telemetry(*final_cfg, logger, client, metrics, scheduler, *url);
400+
CHECK(scheduler->metrics_callback == nullptr);
401+
CHECK(scheduler->metrics_interval == nullopt);
402+
}
403+
404+
SECTION("intervals are respected") {
405+
Configuration cfg;
406+
cfg.metrics_interval_seconds = .5;
407+
cfg.heartbeat_interval_seconds = 30;
408+
409+
auto final_cfg = finalize_config(cfg);
410+
REQUIRE(final_cfg);
411+
412+
Telemetry telemetry(*final_cfg, logger, client, metrics, scheduler, *url);
413+
CHECK(scheduler->metrics_callback != nullptr);
414+
CHECK(scheduler->metrics_interval == 500ms);
415+
416+
CHECK(scheduler->heartbeat_callback != nullptr);
417+
CHECK(scheduler->metrics_interval != 30s);
418+
}
419+
420+
SECTION("disabling logs reporting do not collect logs") {
421+
client->clear();
422+
423+
Configuration cfg;
424+
cfg.report_logs = false;
425+
426+
auto final_cfg = finalize_config(cfg);
427+
REQUIRE(final_cfg);
428+
429+
Telemetry telemetry(*final_cfg, logger, client, metrics, scheduler, *url);
430+
telemetry.log_error("error");
431+
432+
// NOTE(@dmehala): logs are sent with an heartbeat.
433+
scheduler->trigger_heartbeat();
434+
435+
auto message_batch = nlohmann::json::parse(client->request_body);
436+
REQUIRE(is_valid_telemetry_payload(message_batch));
437+
REQUIRE(message_batch["payload"].size() == 1);
438+
CHECK(message_batch["payload"][0]["request_type"] == "app-heartbeat");
439+
}
440+
}

0 commit comments

Comments
 (0)