Skip to content

Commit 6618c75

Browse files
committed
WIP. Working API, limited metrics, missing tags for metrics
1 parent 45c3c05 commit 6618c75

File tree

12 files changed

+427
-19
lines changed

12 files changed

+427
-19
lines changed

CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ target_sources(dd_trace_cpp-objects PRIVATE
110110
src/datadog/id_generator.cpp
111111
src/datadog/limiter.cpp
112112
src/datadog/logger.cpp
113+
src/datadog/metrics.cpp
113114
src/datadog/msgpack.cpp
114115
src/datadog/null_collector.cpp
115116
src/datadog/parse_util.cpp
@@ -127,6 +128,7 @@ target_sources(dd_trace_cpp-objects PRIVATE
127128
src/datadog/tags.cpp
128129
src/datadog/threaded_event_scheduler.cpp
129130
src/datadog/tracer_config.cpp
131+
src/datadog/tracer_telemetry.cpp
130132
src/datadog/tracer.cpp
131133
src/datadog/trace_id.cpp
132134
src/datadog/trace_sampler_config.cpp
@@ -165,6 +167,7 @@ target_sources(dd_trace_cpp-objects PUBLIC
165167
src/datadog/json.hpp
166168
src/datadog/limiter.h
167169
src/datadog/logger.h
170+
src/datadog/metrics.h
168171
src/datadog/msgpack.h
169172
src/datadog/null_collector.h
170173
src/datadog/optional.h
@@ -189,6 +192,7 @@ target_sources(dd_trace_cpp-objects PUBLIC
189192
src/datadog/tags.h
190193
src/datadog/threaded_event_scheduler.h
191194
src/datadog/tracer_config.h
195+
src/datadog/tracer_telemetry.h
192196
src/datadog/tracer.h
193197
src/datadog/trace_id.h
194198
src/datadog/trace_sampler_config.h

src/datadog/datadog_agent.cpp

Lines changed: 110 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,20 @@ namespace tracing {
2222
namespace {
2323

2424
const StringView traces_api_path = "/v0.4/traces";
25+
const StringView telemetry_v2_path = "/telemetry/proxy/api/v2/apmtelemetry";
2526

2627
HTTPClient::URL traces_endpoint(const HTTPClient::URL& agent_url) {
2728
auto traces_url = agent_url;
2829
append(traces_url.path, traces_api_path);
2930
return traces_url;
3031
}
3132

33+
HTTPClient::URL telemetry_endpoint(const HTTPClient::URL& agent_url) {
34+
auto telemetry_v2_url = agent_url;
35+
append(telemetry_v2_url.path, telemetry_v2_path);
36+
return telemetry_v2_url;
37+
}
38+
3239
Expected<void> msgpack_encode(
3340
std::string& destination,
3441
const std::vector<DatadogAgent::TraceChunk>& trace_chunks) {
@@ -124,18 +131,30 @@ std::variant<CollectorResponse, std::string> parse_agent_traces_response(
124131

125132
} // namespace
126133

127-
DatadogAgent::DatadogAgent(const FinalizedDatadogAgentConfig& config,
128-
const Clock& clock,
129-
const std::shared_ptr<Logger>& logger)
130-
: clock_(clock),
134+
DatadogAgent::DatadogAgent(
135+
const FinalizedDatadogAgentConfig& config,
136+
const std::shared_ptr<TracerTelemetry>& tracer_telemetry,
137+
const Clock& clock, const std::shared_ptr<Logger>& logger)
138+
: tracer_telemetry_(tracer_telemetry),
139+
clock_(clock),
131140
logger_(logger),
132141
traces_endpoint_(traces_endpoint(config.url)),
142+
telemetry_endpoint_(telemetry_endpoint(config.url)),
133143
http_client_(config.http_client),
134144
event_scheduler_(config.event_scheduler),
135145
cancel_scheduled_flush_(event_scheduler_->schedule_recurring_event(
136146
config.flush_interval, [this]() { flush(); })),
147+
cancel_heartbeat_timer_(event_scheduler_->schedule_recurring_event(
148+
std::chrono::seconds(10), [this, n=0]() mutable {
149+
n++;
150+
tracer_telemetry_->captureMetrics();
151+
if (n%6 == 0) {
152+
sendHeartbeatAndTelemetry();
153+
}
154+
})),
137155
flush_interval_(config.flush_interval) {
138156
assert(logger_);
157+
sendAppStarted();
139158
}
140159

141160
DatadogAgent::~DatadogAgent() {
@@ -154,7 +173,6 @@ Expected<void> DatadogAgent::send(
154173
}
155174

156175
nlohmann::json DatadogAgent::config_json() const {
157-
const auto& url = traces_endpoint_; // brevity
158176
const auto flush_interval_milliseconds =
159177
std::chrono::duration_cast<std::chrono::milliseconds>(flush_interval_)
160178
.count();
@@ -163,7 +181,8 @@ nlohmann::json DatadogAgent::config_json() const {
163181
return nlohmann::json::object({
164182
{"type", "datadog::tracing::DatadogAgent"},
165183
{"config", nlohmann::json::object({
166-
{"url", (url.scheme + "://" + url.authority + url.path)},
184+
{"traces_url", (traces_endpoint_.scheme + "://" + traces_endpoint_.authority + traces_endpoint_.path)},
185+
{"telemetry_url", (telemetry_endpoint_.scheme + "://" + telemetry_endpoint_.authority + telemetry_endpoint_.path)},
167186
{"flush_interval_milliseconds", flush_interval_milliseconds},
168187
{"http_client", http_client_->config_json()},
169188
{"event_scheduler", event_scheduler_->config_json()},
@@ -251,10 +270,11 @@ void DatadogAgent::flush() {
251270
// request or retrieving the response. It's invoked
252271
// asynchronously.
253272
auto on_error = [logger = logger_](Error error) {
254-
logger->log_error(
255-
error.with_prefix("Error occurred during HTTP request: "));
273+
logger->log_error(error.with_prefix(
274+
"Error occurred during HTTP request for submitting traces: "));
256275
};
257276

277+
tracer_telemetry_->trace_api_requests().inc();
258278
auto post_result = http_client_->post(
259279
traces_endpoint_, std::move(set_request_headers), std::move(body),
260280
std::move(on_response), std::move(on_error));
@@ -263,5 +283,87 @@ void DatadogAgent::flush() {
263283
}
264284
}
265285

286+
void DatadogAgent::sendAppStarted() {
287+
auto payload = tracer_telemetry_->appStarted();
288+
auto set_request_headers = [&](DictWriter& headers) {
289+
headers.set("Content-Type", "application/json");
290+
};
291+
292+
// Callback for a successful HTTP request, to examine HTTP status.
293+
auto on_response = [logger = logger_](int response_status,
294+
const DictReader& /*response_headers*/,
295+
std::string response_body) {
296+
if (response_status < 200 || response_status >= 300) {
297+
logger->log_error([&](auto& stream) {
298+
stream << "Unexpected telemetry response status " << response_status
299+
<< " with body (starts on next line):\n"
300+
<< response_body;
301+
});
302+
return;
303+
} else {
304+
logger->log_error([&](auto& stream) {
305+
stream << "Successful telemetry submission with response status " << response_status
306+
<< " and body (starts on next line):\n"
307+
<< response_body;
308+
});
309+
}
310+
311+
};
312+
313+
// Callback for unsuccessful HTTP request.
314+
auto on_error = [logger = logger_](Error error) {
315+
logger->log_error(error.with_prefix(
316+
"Error occurred during HTTP request for telemetry: "));
317+
};
318+
319+
auto post_result = http_client_->post(
320+
telemetry_endpoint_, std::move(set_request_headers), std::move(payload),
321+
std::move(on_response), std::move(on_error));
322+
if (auto* error = post_result.if_error()) {
323+
logger_->log_error(*error);
324+
}
325+
}
326+
327+
void DatadogAgent::sendHeartbeatAndTelemetry() {
328+
auto payload = tracer_telemetry_->heartbeatAndTelemetry();
329+
auto set_request_headers = [&](DictWriter& headers) {
330+
headers.set("Content-Type", "application/json");
331+
};
332+
333+
// Callback for a successful HTTP request, to examine HTTP status.
334+
auto on_response = [logger = logger_](int response_status,
335+
const DictReader& /*response_headers*/,
336+
std::string response_body) {
337+
if (response_status < 200 || response_status >= 300) {
338+
logger->log_error([&](auto& stream) {
339+
stream << "Unexpected telemetry response status " << response_status
340+
<< " with body (starts on next line):\n"
341+
<< response_body;
342+
});
343+
return;
344+
} else {
345+
logger->log_error([&](auto& stream) {
346+
stream << "Successful telemetry submission with response status " << response_status
347+
<< " and body (starts on next line):\n"
348+
<< response_body;
349+
});
350+
}
351+
352+
};
353+
354+
// Callback for unsuccessful HTTP request.
355+
auto on_error = [logger = logger_](Error error) {
356+
logger->log_error(error.with_prefix(
357+
"Error occurred during HTTP request for telemetry: "));
358+
};
359+
360+
auto post_result = http_client_->post(
361+
telemetry_endpoint_, std::move(set_request_headers), std::move(payload),
362+
std::move(on_response), std::move(on_error));
363+
if (auto* error = post_result.if_error()) {
364+
logger_->log_error(*error);
365+
}
366+
}
367+
266368
} // namespace tracing
267369
} // namespace datadog

src/datadog/datadog_agent.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "collector.h"
1515
#include "event_scheduler.h"
1616
#include "http_client.h"
17+
#include "tracer_telemetry.h"
1718

1819
namespace datadog {
1920
namespace tracing {
@@ -32,25 +33,31 @@ class DatadogAgent : public Collector {
3233

3334
private:
3435
std::mutex mutex_;
36+
std::shared_ptr<TracerTelemetry> tracer_telemetry_;
3537
Clock clock_;
3638
std::shared_ptr<Logger> logger_;
3739
std::vector<TraceChunk> trace_chunks_;
3840
HTTPClient::URL traces_endpoint_;
41+
HTTPClient::URL telemetry_endpoint_;
3942
std::shared_ptr<HTTPClient> http_client_;
4043
std::shared_ptr<EventScheduler> event_scheduler_;
4144
EventScheduler::Cancel cancel_scheduled_flush_;
45+
EventScheduler::Cancel cancel_heartbeat_timer_;
4246
std::chrono::steady_clock::duration flush_interval_;
4347

4448
void flush();
4549

4650
public:
47-
DatadogAgent(const FinalizedDatadogAgentConfig&, const Clock& clock,
51+
DatadogAgent(const FinalizedDatadogAgentConfig&,
52+
const std::shared_ptr<TracerTelemetry>&, const Clock& clock,
4853
const std::shared_ptr<Logger>&);
4954
~DatadogAgent();
5055

5156
Expected<void> send(
5257
std::vector<std::unique_ptr<SpanData>>&& spans,
5358
const std::shared_ptr<TraceSampler>& response_handler) override;
59+
void sendAppStarted();
60+
void sendHeartbeatAndTelemetry();
5461

5562
nlohmann::json config_json() const override;
5663
};

src/datadog/metrics.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#include "metrics.h"
2+
3+
#include "json.hpp"
4+
5+
namespace datadog {
6+
namespace tracing {
7+
8+
Metric::Metric(std::string name, std::string type, bool common) : name_(name), type_(type), common_(common) {}
9+
std::string Metric::name() { return name_; }
10+
std::string Metric::type() { return type_; }
11+
bool Metric::common() { return common_; }
12+
uint64_t Metric::value() { return value_; }
13+
14+
CounterMetric::CounterMetric(std::string name, bool common) : Metric(name, "count", common) {}
15+
void CounterMetric::inc() { add(1); }
16+
void CounterMetric::add(uint64_t amount) { value_ += amount; }
17+
18+
GaugeMetric::GaugeMetric(std::string name, bool common) : Metric(name, "gauge", common) {}
19+
void GaugeMetric::set(uint64_t value) { value_ = value; }
20+
void GaugeMetric::inc() { add(1); }
21+
void GaugeMetric::add(uint64_t amount) { value_ += amount; }
22+
void GaugeMetric::dec() { sub(1); }
23+
void GaugeMetric::sub(uint64_t amount) {
24+
if (amount > value_) {
25+
value_ = 0;
26+
} else {
27+
value_ -= amount;
28+
}
29+
}
30+
31+
} // namespace tracing
32+
} // namespace datadog

src/datadog/metrics.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#pragma once
2+
3+
#include <atomic>
4+
5+
#include "json_fwd.hpp"
6+
#include "string_view.h"
7+
8+
namespace datadog {
9+
namespace tracing {
10+
11+
class Metric {
12+
std::string name_;
13+
std::string type_;
14+
bool common_;
15+
protected:
16+
std::atomic<uint64_t> value_ = 0;
17+
Metric(std::string name, std::string type, bool common);
18+
public:
19+
std::string name();
20+
std::string type();
21+
bool common();
22+
uint64_t value();
23+
};
24+
25+
class CounterMetric : public Metric {
26+
public:
27+
CounterMetric(std::string name, bool common);
28+
void inc();
29+
void add(uint64_t amount);
30+
};
31+
32+
class GaugeMetric : public Metric {
33+
public:
34+
GaugeMetric(std::string name, bool common);
35+
void set(uint64_t value);
36+
void inc();
37+
void add(uint64_t amount);
38+
void dec();
39+
void sub(uint64_t amount);
40+
};
41+
42+
} // namespace tracing
43+
} // namespace datadog

src/datadog/trace_segment.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ void inject_trace_tags(
8383
TraceSegment::TraceSegment(
8484
const std::shared_ptr<Logger>& logger,
8585
const std::shared_ptr<Collector>& collector,
86+
const std::shared_ptr<TracerTelemetry>& tracer_telemetry,
8687
const std::shared_ptr<TraceSampler>& trace_sampler,
8788
const std::shared_ptr<SpanSampler>& span_sampler,
8889
const std::shared_ptr<const SpanDefaults>& defaults,
@@ -96,6 +97,7 @@ TraceSegment::TraceSegment(
9697
std::unique_ptr<SpanData> local_root)
9798
: logger_(logger),
9899
collector_(collector),
100+
tracer_telemetry_(tracer_telemetry),
99101
trace_sampler_(trace_sampler),
100102
span_sampler_(span_sampler),
101103
defaults_(defaults),
@@ -111,10 +113,14 @@ TraceSegment::TraceSegment(
111113
std::move(additional_datadog_w3c_tracestate)) {
112114
assert(logger_);
113115
assert(collector_);
116+
assert(tracer_telemetry_);
114117
assert(trace_sampler_);
115118
assert(span_sampler_);
116119
assert(defaults_);
117120

121+
tracer_telemetry_->traces_started().inc();
122+
tracer_telemetry_->active_traces().inc();
123+
118124
register_span(std::move(local_root));
119125
}
120126

@@ -135,12 +141,18 @@ Optional<SamplingDecision> TraceSegment::sampling_decision() const {
135141
Logger& TraceSegment::logger() const { return *logger_; }
136142

137143
void TraceSegment::register_span(std::unique_ptr<SpanData> span) {
144+
tracer_telemetry_->spans_started().inc();
145+
tracer_telemetry_->active_spans().inc();
146+
138147
std::lock_guard<std::mutex> lock(mutex_);
139148
assert(spans_.empty() || num_finished_spans_ < spans_.size());
140149
spans_.emplace_back(std::move(span));
141150
}
142151

143152
void TraceSegment::span_finished() {
153+
tracer_telemetry_->spans_finished().inc();
154+
tracer_telemetry_->active_spans().dec();
155+
144156
{
145157
std::lock_guard<std::mutex> lock(mutex_);
146158
++num_finished_spans_;
@@ -220,6 +232,9 @@ void TraceSegment::span_finished() {
220232
logger_->log_error(
221233
error->with_prefix("Error sending spans to collector: "));
222234
}
235+
236+
tracer_telemetry_->traces_finished().inc();
237+
tracer_telemetry_->active_traces().dec();
223238
}
224239

225240
void TraceSegment::override_sampling_priority(int priority) {

0 commit comments

Comments
 (0)