Skip to content

Commit f8cacf4

Browse files
authored
feat: Report host information in telemetry (#118)
- Collect informations on the Operating System and the CPU architecture. - Report those informations through APM Telemetry.
1 parent 9647240 commit f8cacf4

File tree

7 files changed

+165
-42
lines changed

7 files changed

+165
-42
lines changed

src/datadog/datadog_agent.cpp

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
#include "string_view.h"
1919
#include "trace_sampler.h"
2020
#include "tracer.h"
21-
#include "version.h"
2221

2322
namespace datadog {
2423
namespace tracing {
@@ -163,7 +162,8 @@ DatadogAgent::DatadogAgent(
163162
flush_interval_(config.flush_interval),
164163
request_timeout_(config.request_timeout),
165164
shutdown_timeout_(config.shutdown_timeout),
166-
remote_config_(tracer_signature, config_manager) {
165+
remote_config_(tracer_signature, config_manager),
166+
tracer_signature_(tracer_signature) {
167167
assert(logger_);
168168
assert(tracer_telemetry_);
169169

@@ -290,8 +290,10 @@ void DatadogAgent::flush() {
290290
auto set_request_headers = [&](DictWriter& headers) {
291291
headers.set("Content-Type", "application/msgpack");
292292
headers.set("Datadog-Meta-Lang", "cpp");
293-
headers.set("Datadog-Meta-Lang-Version", std::to_string(__cplusplus));
294-
headers.set("Datadog-Meta-Tracer-Version", tracer_version);
293+
headers.set("Datadog-Meta-Lang-Version",
294+
tracer_signature_.library_language_version);
295+
headers.set("Datadog-Meta-Tracer-Version",
296+
tracer_signature_.library_version);
295297
headers.set("X-Datadog-Trace-Count", std::to_string(trace_chunks.size()));
296298
};
297299

@@ -366,9 +368,30 @@ void DatadogAgent::flush() {
366368
}
367369
}
368370

369-
void DatadogAgent::send_telemetry(std::string payload) {
371+
void DatadogAgent::send_telemetry(StringView request_type,
372+
std::string payload) {
373+
auto set_telemetry_headers = [request_type, payload_size = payload.size(),
374+
debug_enabled = tracer_telemetry_->debug(),
375+
tracer_signature =
376+
&tracer_signature_](DictWriter& headers) {
377+
/*
378+
TODO:
379+
Datadog-Container-ID
380+
*/
381+
headers.set("Content-Type", "application/json");
382+
headers.set("Content-Length", std::to_string(payload_size));
383+
headers.set("DD-Telemetry-API-Version", "v2");
384+
headers.set("DD-Client-Library-Language", "cpp");
385+
headers.set("DD-Client-Library-Version", tracer_signature->library_version);
386+
headers.set("DD-Telemetry-Request-Type", request_type);
387+
388+
if (debug_enabled) {
389+
headers.set("DD-Telemetry-Debug-Enabled", "true");
390+
}
391+
};
392+
370393
auto post_result =
371-
http_client_->post(telemetry_endpoint_, set_content_type_json,
394+
http_client_->post(telemetry_endpoint_, set_telemetry_headers,
372395
std::move(payload), telemetry_on_response_,
373396
telemetry_on_error_, clock_().tick + request_timeout_);
374397
if (auto* error = post_result.if_error()) {
@@ -379,20 +402,22 @@ void DatadogAgent::send_telemetry(std::string payload) {
379402

380403
void DatadogAgent::send_app_started(
381404
const std::unordered_map<ConfigName, ConfigMetadata>& config_metadata) {
382-
send_telemetry(tracer_telemetry_->app_started(config_metadata));
405+
send_telemetry("app-started",
406+
tracer_telemetry_->app_started(config_metadata));
383407
}
384408

385409
void DatadogAgent::send_heartbeat_and_telemetry() {
386-
send_telemetry(tracer_telemetry_->heartbeat_and_telemetry());
410+
send_telemetry("app-heartbeat", tracer_telemetry_->heartbeat_and_telemetry());
387411
}
388412

389413
void DatadogAgent::send_app_closing() {
390-
send_telemetry(tracer_telemetry_->app_closing());
414+
send_telemetry("app-closing", tracer_telemetry_->app_closing());
391415
}
392416

393417
void DatadogAgent::send_configuration_change(
394418
const std::vector<ConfigMetadata>& config) {
395-
send_telemetry(tracer_telemetry_->configuration_change(config));
419+
send_telemetry("app-client-configuration-change",
420+
tracer_telemetry_->configuration_change(config));
396421
}
397422

398423
void DatadogAgent::get_and_apply_remote_configuration_updates() {

src/datadog/datadog_agent.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "http_client.h"
1818
#include "metrics.h"
1919
#include "remote_config.h"
20+
#include "tracer_signature.h"
2021
#include "tracer_telemetry.h"
2122

2223
namespace datadog {
@@ -55,9 +56,10 @@ class DatadogAgent : public Collector {
5556
std::chrono::steady_clock::duration shutdown_timeout_;
5657

5758
RemoteConfigurationManager remote_config_;
59+
TracerSignature tracer_signature_;
5860

5961
void flush();
60-
void send_telemetry(std::string);
62+
void send_telemetry(StringView, std::string);
6163
void send_heartbeat_and_telemetry();
6264
void send_app_closing();
6365

src/datadog/platform_util.cpp

Lines changed: 92 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,114 @@
11
#include "platform_util.h"
22

3-
#ifdef _MSC_VER
4-
#include <processthreadsapi.h>
5-
#include <winsock.h>
6-
#else
73
#include <pthread.h>
4+
#include <sys/types.h>
5+
#include <sys/utsname.h>
86
#include <unistd.h>
7+
8+
#include <fstream>
9+
10+
#include "string_util.h"
11+
12+
#if defined(__x86_64__) || defined(_M_X64)
13+
#define DD_SDK_CPU_ARCH "x86_64"
14+
#elif defined(i386) || defined(__i386__) || defined(__i386) || defined(_M_IX86)
15+
#define DD_SDK_CPU_ARCH "x86"
16+
#elif defined(__aarch64__) || defined(_M_ARM64)
17+
#define DD_SDK_CPU_ARCH "arm64"
18+
#else
19+
#define DD_SDK_CPU_ARCH "unknown"
20+
#endif
21+
22+
#if defined(__APPLE__)
23+
#include <sys/sysctl.h>
24+
#define DD_SDK_OS "Darwin"
25+
#define DD_SDK_KERNEL "Darwin"
26+
#elif defined(__linux__) || defined(__unix__)
27+
#define DD_SDK_OS "GNU/Linux"
28+
#define DD_SDK_KERNEL "Linux"
29+
#else
30+
#define DD_SDK_OS "unknown"
931
#endif
1032

1133
namespace datadog {
1234
namespace tracing {
35+
namespace {
1336

14-
Optional<std::string> get_hostname() {
15-
char buffer[256];
16-
if (::gethostname(buffer, sizeof buffer)) {
17-
return nullopt;
18-
}
19-
return buffer;
37+
#if defined(__APPLE__)
38+
std::string get_os_version() {
39+
char os_version[20] = "";
40+
size_t len = sizeof(os_version);
41+
42+
sysctlbyname("kern.osproductversion", os_version, &len, NULL, 0);
43+
return os_version;
2044
}
45+
#elif defined(__linux__)
46+
std::string get_os_version() {
47+
std::ifstream os_release_file("/etc/os-release");
48+
if (!os_release_file.is_open()) {
49+
return "";
50+
}
51+
52+
std::string line;
2153

22-
int get_process_id() {
23-
#ifdef _MSC_VER
24-
return GetCurrentProcessId();
54+
while (std::getline(os_release_file, line)) {
55+
size_t pos = line.find('=');
56+
if (pos == std::string::npos) {
57+
continue;
58+
}
59+
60+
std::string key = line.substr(0, pos);
61+
to_lower(key);
62+
if (key == "version") {
63+
std::string value = line.substr(pos + 1);
64+
return value;
65+
}
66+
}
67+
68+
return "";
69+
}
2570
#else
26-
return ::getpid();
71+
std::string get_os_version() { return ""; }
2772
#endif
73+
74+
#if defined(__APPLE__) || defined(__linux__)
75+
76+
HostInfo _get_host_info() {
77+
HostInfo res;
78+
79+
struct utsname buffer;
80+
if (uname(&buffer) != 0) {
81+
return res;
82+
}
83+
84+
res.os = DD_SDK_OS;
85+
res.os_version = get_os_version();
86+
res.hostname = buffer.nodename;
87+
res.cpu_architecture = DD_SDK_CPU_ARCH;
88+
res.kernel_name = DD_SDK_KERNEL;
89+
res.kernel_version = buffer.version;
90+
res.kernel_release = buffer.release;
91+
92+
return res;
2893
}
2994

95+
#endif
96+
97+
} // namespace
98+
99+
HostInfo get_host_info() {
100+
static const HostInfo host_info = _get_host_info();
101+
return host_info;
102+
}
103+
104+
std::string get_hostname() { return get_host_info().hostname; }
105+
106+
int get_process_id() { return ::getpid(); }
107+
30108
int at_fork_in_child(void (*on_fork)()) {
31-
// Windows does not have `fork`, and so this is not relevant there.
32-
#ifdef _MSC_VER
33-
return 0;
34-
#else
35109
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_atfork.html
36110
return pthread_atfork(/*before fork*/ nullptr, /*in parent*/ nullptr,
37111
/*in child*/ on_fork);
38-
#endif
39112
}
40113

41114
} // namespace tracing

src/datadog/platform_util.h

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,25 @@
44

55
#include <string>
66

7-
#include "optional.h"
8-
97
namespace datadog {
108
namespace tracing {
119

12-
Optional<std::string> get_hostname();
10+
// Hold host information mainly used for telemetry purposes
11+
// and for identifying a tracer.
12+
struct HostInfo final {
13+
std::string os;
14+
std::string os_version;
15+
std::string hostname;
16+
std::string cpu_architecture;
17+
std::string kernel_name;
18+
std::string kernel_version;
19+
std::string kernel_release;
20+
};
21+
22+
// Returns host information. Lazy.
23+
HostInfo get_host_info();
24+
25+
std::string get_hostname();
1326

1427
int get_process_id();
1528

src/datadog/tracer.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,11 @@ Tracer::Tracer(const FinalizedTracerConfig& config,
5151
clock_(config.clock),
5252
injection_styles_(config.injection_styles),
5353
extraction_styles_(config.extraction_styles),
54-
hostname_(config.report_hostname ? get_hostname() : nullopt),
5554
tags_header_max_size_(config.tags_header_size),
5655
sampling_delegation_enabled_(config.delegate_trace_sampling) {
56+
if (config.report_hostname) {
57+
hostname_ = get_hostname();
58+
}
5759
if (auto* collector =
5860
std::get_if<std::shared_ptr<Collector>>(&config.collector)) {
5961
collector_ = *collector;

src/datadog/tracer_telemetry.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ TracerTelemetry::TracerTelemetry(bool enabled, const Clock& clock,
6060
: enabled_(enabled),
6161
clock_(clock),
6262
logger_(logger),
63+
host_info_(get_host_info()),
6364
tracer_signature_(tracer_signature),
64-
hostname_(get_hostname().value_or("hostname-unavailable")),
6565
integration_name_(integration_name),
6666
integration_version_(integration_version) {
6767
if (enabled_) {
@@ -120,10 +120,16 @@ nlohmann::json TracerTelemetry::generate_telemetry_body(
120120
{"language_name", tracer_signature_.library_language},
121121
{"language_version", tracer_signature_.library_language_version},
122122
})},
123-
// TODO: host information (os, os_version, kernel, etc)
124-
{"host", nlohmann::json::object({
125-
{"hostname", hostname_},
126-
})},
123+
{"host",
124+
{
125+
{"hostname", host_info_.hostname},
126+
{"os", host_info_.os},
127+
{"os_version", host_info_.os_version},
128+
{"architecture", host_info_.cpu_architecture},
129+
{"kernel_name", host_info_.kernel_name},
130+
{"kernel_version", host_info_.kernel_version},
131+
{"kernel_release", host_info_.kernel_release},
132+
}},
127133
});
128134
}
129135

src/datadog/tracer_telemetry.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "config.h"
3535
#include "json.hpp"
3636
#include "metrics.h"
37+
#include "platform_util.h"
3738
#include "runtime_id.h"
3839
#include "tracer_signature.h"
3940

@@ -48,8 +49,8 @@ class TracerTelemetry {
4849
bool debug_ = false;
4950
Clock clock_;
5051
std::shared_ptr<Logger> logger_;
52+
HostInfo host_info_;
5153
TracerSignature tracer_signature_;
52-
std::string hostname_;
5354
std::string integration_name_;
5455
std::string integration_version_;
5556
// Track sequence id per payload generated
@@ -115,10 +116,11 @@ class TracerTelemetry {
115116
const TracerSignature& tracer_signature,
116117
const std::string& integration_name,
117118
const std::string& integration_version);
118-
bool enabled() { return enabled_; };
119+
inline bool enabled() { return enabled_; }
120+
inline bool debug() { return debug_; }
119121
// Provides access to the telemetry metrics for updating the values.
120122
// This value should not be stored.
121-
auto& metrics() { return metrics_; };
123+
auto& metrics() { return metrics_; }
122124
// Constructs an `app-started` message using information provided when
123125
// constructed and the tracer_config value passed in.
124126
std::string app_started(

0 commit comments

Comments
 (0)