Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
cc_library(
name = "dd_trace_cpp",
srcs = [
"src/datadog/common/hash.cpp",
"src/datadog/telemetry/configuration.cpp",
"src/datadog/telemetry/metrics.cpp",
"src/datadog/telemetry/log.h",
"src/datadog/telemetry/telemetry.cpp",
"src/datadog/telemetry/telemetry_impl.h",
"src/datadog/telemetry/telemetry_impl.cpp",
"src/datadog/telemetry/metric_context.h",
"src/datadog/baggage.cpp",
"src/datadog/base64.cpp",
"src/datadog/cerr_logger.cpp",
Expand Down Expand Up @@ -41,6 +42,7 @@ cc_library(
"src/datadog/string_util.cpp",
"src/datadog/tag_propagation.cpp",
"src/datadog/tags.cpp",
"src/datadog/telemetry_metrics.cpp",
"src/datadog/threaded_event_scheduler.cpp",
"src/datadog/tracer_config.cpp",
"src/datadog/tracer.cpp",
Expand All @@ -50,6 +52,7 @@ cc_library(
"src/datadog/trace_segment.cpp",
"src/datadog/version.cpp",
"src/datadog/w3c_propagation.cpp",
"src/datadog/common/hash.h",
"src/datadog/base64.h",
"src/datadog/config_manager.h",
"src/datadog/collector_response.h",
Expand All @@ -74,6 +77,7 @@ cc_library(
"src/datadog/string_util.h",
"src/datadog/tag_propagation.h",
"src/datadog/tags.h",
"src/datadog/telemetry_metrics.h",
"src/datadog/threaded_event_scheduler.h",
"src/datadog/trace_sampler.h",
"src/datadog/w3c_propagation.h",
Expand Down
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ target_sources(dd_trace_cpp-objects
BASE_DIRS include
FILES ${public_header_files}
PRIVATE
src/datadog/common/hash.cpp
src/datadog/telemetry/configuration.cpp
src/datadog/telemetry/metrics.cpp
src/datadog/telemetry/telemetry.cpp
src/datadog/telemetry/telemetry_impl.cpp
src/datadog/baggage.cpp
Expand Down Expand Up @@ -150,6 +150,7 @@ target_sources(dd_trace_cpp-objects
src/datadog/trace_sampler_config.cpp
src/datadog/trace_sampler.cpp
src/datadog/trace_segment.cpp
src/datadog/telemetry_metrics.cpp
src/datadog/version.cpp
src/datadog/w3c_propagation.cpp
)
Expand Down
156 changes: 22 additions & 134 deletions include/datadog/telemetry/metrics.h
Original file line number Diff line number Diff line change
@@ -1,146 +1,34 @@
#pragma once

// This component provides an interface, `Metric`, and specific classes for
// Counter and Gauge metrics. A metric has a name, type, and set of key:value
// tags associated with it. Metrics can be general to APM or language-specific.
// General metrics have `common` set to `true`, and language-specific metrics
// have `common` set to `false`.

#include <atomic>
#include <string>
#include <vector>

namespace datadog {
namespace telemetry {

class Metric {
// The name of the metric that will be published. A transformation occurs
// based on the name and whether it is "common" or "language-specific" when it
// is recorded.
std::string name_;
// The type of the metric. This will currently be count or gauge.
std::string type_;
// Namespace of the metric.
std::string scope_;
// Tags associated with this specific instance of the metric.
std::vector<std::string> tags_;
// This affects the transformation of the metric name, where it can be a
// common telemetry metric, or a language-specific metric that is prefixed
// with the language name.
bool common_;

protected:
std::atomic<uint64_t> value_ = 0;
Metric(std::string name, std::string type, std::string scope,
std::vector<std::string> tags, bool common);

Metric(Metric&& rhs)
: name_(std::move(rhs.name_)),
type_(std::move(rhs.type_)),
scope_(std::move(rhs.scope_)),
tags_(std::move(rhs.tags_)) {
rhs.value_.store(value_.exchange(rhs.value_));
}

Metric& operator=(Metric&& rhs) {
if (&rhs != this) {
std::swap(name_, rhs.name_);
std::swap(type_, rhs.type_);
std::swap(scope_, rhs.scope_);
std::swap(tags_, rhs.tags_);
rhs.value_.store(value_.exchange(rhs.value_));
}
return *this;
}

public:
// Accessors for name, type, tags, common and capture_and_reset_value are used
// when producing the JSON message for reporting metrics.
std::string name();
std::string type();
std::string scope();
std::vector<std::string> tags();
bool common();
uint64_t value();
uint64_t capture_and_reset_value();
};

// A count metric is used for measuring activity, and has methods for adding a
// number of actions, or incrementing the current number of actions by 1.
class CounterMetric : public Metric {
public:
CounterMetric(std::string name, std::string scope,
std::vector<std::string> tags, bool common);
void inc();
void add(uint64_t amount);
namespace details {
enum class MetricType : char { counter, rate, distribution };
}

/// TODO: pre-compute hash?
template <details::MetricType T>
struct Metric final {
/// The type of the metric.
static constexpr details::MetricType type = T;
/// The name of the metric that will be published. A transformation occurs
/// based on the name and whether it is "common" or "language-specific" when
/// it is recorded.
std::string name;
/// Namespace of the metric.
std::string scope;
/// This affects the transformation of the metric name, where it can be a
/// common telemetry metric, or a language-specific metric that is prefixed
/// with the language name.
bool common;
};

// A gauge metric is used for measuring state, and mas methods to set the
// current state, add or subtract from it, or increment/decrement the current
// state by 1.
class GaugeMetric : public Metric {
public:
GaugeMetric(std::string name, std::string scope,
std::vector<std::string> tags, bool common);
void set(uint64_t value);
void inc();
void add(uint64_t amount);
void dec();
void sub(uint64_t amount);
};

// This structure contains all the metrics that are exposed by tracer
// telemetry.
struct DefaultMetrics {
struct {
telemetry::CounterMetric spans_created = {
"spans_created", "tracers", {}, true};
telemetry::CounterMetric spans_finished = {
"spans_finished", "tracers", {}, true};

telemetry::CounterMetric trace_segments_created_new = {
"trace_segments_created", "tracers", {"new_continued:new"}, true};
telemetry::CounterMetric trace_segments_created_continued = {
"trace_segments_created", "tracers", {"new_continued:continued"}, true};
telemetry::CounterMetric trace_segments_closed = {
"trace_segments_closed", "tracers", {}, true};
telemetry::CounterMetric baggage_items_exceeded = {
"context_header.truncated",
"tracers",
{{"truncation_reason:baggage_item_count_exceeded"}},
true,
};
telemetry::CounterMetric baggage_bytes_exceeded = {
"context_header.truncated",
"tracers",
{{"truncation_reason:baggage_byte_count_exceeded"}},
true,
};
} tracer;
struct {
telemetry::CounterMetric requests = {
"trace_api.requests", "tracers", {}, true};

telemetry::CounterMetric responses_1xx = {
"trace_api.responses", "tracers", {"status_code:1xx"}, true};
telemetry::CounterMetric responses_2xx = {
"trace_api.responses", "tracers", {"status_code:2xx"}, true};
telemetry::CounterMetric responses_3xx = {
"trace_api.responses", "tracers", {"status_code:3xx"}, true};
telemetry::CounterMetric responses_4xx = {
"trace_api.responses", "tracers", {"status_code:4xx"}, true};
telemetry::CounterMetric responses_5xx = {
"trace_api.responses", "tracers", {"status_code:5xx"}, true};

telemetry::CounterMetric errors_timeout = {
"trace_api.errors", "tracers", {"type:timeout"}, true};
telemetry::CounterMetric errors_network = {
"trace_api.errors", "tracers", {"type:network"}, true};
telemetry::CounterMetric errors_status_code = {
"trace_api.errors", "tracers", {"type:status_code"}, true};

} trace_api;
};
using Counter = Metric<details::MetricType::counter>;
using Rate = Metric<details::MetricType::rate>;
using Distribution = Metric<details::MetricType::distribution>;

} // namespace telemetry
} // namespace datadog
90 changes: 85 additions & 5 deletions include/datadog/telemetry/telemetry.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ namespace datadog::telemetry {
void init(FinalizedConfiguration configuration,
std::shared_ptr<tracing::Logger> logger,
std::shared_ptr<tracing::HTTPClient> client,
std::vector<std::shared_ptr<Metric>> metrics,
std::shared_ptr<tracing::EventScheduler> event_scheduler,
tracing::HTTPClient::URL agent_url,
tracing::Clock clock = tracing::default_clock);
Expand All @@ -58,10 +57,6 @@ void send_configuration_change();
void capture_configuration_change(
const std::vector<tracing::ConfigMetadata>& new_configuration);

/// Provides access to the telemetry metrics for updating the values.
/// This value should not be stored.
DefaultMetrics& metrics();

/// Report internal warning message to Datadog.
///
/// @param message The warning message to log.
Expand All @@ -78,4 +73,89 @@ void report_error_log(std::string message);
/// @param stacktrace Stacktrace leading to the error.
void report_error_log(std::string message, std::string stacktrace);

/// The `counter` namespace provides functions to track values.
/// Counters can be useful for tracking the total number of an event occurring
/// in one time interval. For example, the amount of requests, errors or jobs
/// processed every 10 seconds.
namespace counter {

/// Increments the specified counter by 1.
///
/// @param `counter` the counter to increment.
void increment(const Counter& counter);

/// Increments the specified counter by 1.
///
/// @param `counter` the counter to increment.
/// @param `tags` the distribution tags.
void increment(const Counter& counter, const std::vector<std::string>& tags);

/// Decrements the specified counter by 1.
///
/// @param `counter` the counter to decrement.
void decrement(const Counter& counter);

/// Decrements the specified counter by 1.
///
/// @param `counter` the counter to decrement.
/// @param `tags` the distribution tags.
void decrement(const Counter& counter, const std::vector<std::string>& tags);

/// Sets the counter to a specific value.
///
/// @param `counter` the counter to update.
/// @param `value` the value to assign to the counter.
void set(const Counter& counter, uint64_t value);

/// Sets the counter to a specific value.
///
/// @param `counter` the counter to update.
/// @param `tags` the distribution tags.
/// @param `value` the value to assign to the counter.
void set(const Counter& counter, const std::vector<std::string>& tags,
uint64_t value);

} // namespace counter

/// The `rate` namespace provides support for rate metrics-values.
/// Rates can be useful for tracking the total number of an event occurrences in
/// one time interval. For example, the number of requests per second.
namespace rate {

/// Sets the rate to a specific value.
///
/// @param `rate` the rate to update.
/// @param `value` the value to assign to the counter.
void set(const Rate& rate, uint64_t value);

/// Sets the rate to a specific value.
///
/// @param `rate` the rate to update.
/// @param `tags` the distribution tags.
/// @param `value` the value to assign to the counter.
void set(const Rate& rate, const std::vector<std::string>&, uint64_t value);

} // namespace rate

/// The `distribution` namespace provides support for statistical distribution.
/// Distribution can be useful for tracking things like response times or
/// payload sizes.
namespace distribution {

/// Adds a value to the distribution.
///
/// @param `distribution` the distribution to update.
/// @param `value` the value to add to the distribution.
void add(const Distribution& distribution, uint64_t value);

/// Adds a value to the distribution.
///
/// @param `distribution` the distribution to update.
/// @param `tags` the distribution tags.
/// @param `value` the value to add to the distribution.
void add(const Distribution& distribution, const std::vector<std::string>& tags,
uint64_t value);

} // namespace distribution

} // namespace datadog::telemetry
Loading