LCOV - code coverage report
Current view: top level - datadog - tracer_telemetry.cpp (source / functions) Hit Total Coverage
Test: filtered.info Lines: 133 147 90.5 %
Date: 2024-01-03 20:30:12 Functions: 6 6 100.0 %

          Line data    Source code
       1             : #include "tracer_telemetry.h"
       2             : 
       3             : #include "logger.h"
       4             : #include "platform_util.h"
       5             : #include "span_defaults.h"
       6             : #include "version.h"
       7             : 
       8             : namespace datadog {
       9             : namespace tracing {
      10             : 
      11         607 : TracerTelemetry::TracerTelemetry(bool enabled, const Clock& clock,
      12             :                                  const std::shared_ptr<Logger>& logger,
      13         607 :                                  const TracerSignature& tracer_signature)
      14         607 :     : enabled_(enabled),
      15         607 :       clock_(clock),
      16         607 :       logger_(logger),
      17         607 :       tracer_signature_(tracer_signature),
      18        1214 :       hostname_(get_hostname().value_or("hostname-unavailable")) {
      19         607 :   if (enabled_) {
      20             :     // Register all the metrics that we're tracking by adding them to the
      21             :     // metrics_snapshots_ container. This allows for simpler iteration logic
      22             :     // when using the values in `generate-metrics` messages.
      23         196 :     metrics_snapshots_.emplace_back(metrics_.tracer.spans_created,
      24         392 :                                     MetricSnapshot{});
      25         196 :     metrics_snapshots_.emplace_back(metrics_.tracer.spans_finished,
      26         392 :                                     MetricSnapshot{});
      27         196 :     metrics_snapshots_.emplace_back(metrics_.tracer.trace_segments_created_new,
      28         392 :                                     MetricSnapshot{});
      29         392 :     metrics_snapshots_.emplace_back(
      30         196 :         metrics_.tracer.trace_segments_created_continued, MetricSnapshot{});
      31         196 :     metrics_snapshots_.emplace_back(metrics_.tracer.trace_segments_closed,
      32         392 :                                     MetricSnapshot{});
      33         196 :     metrics_snapshots_.emplace_back(metrics_.trace_api.requests,
      34         392 :                                     MetricSnapshot{});
      35         196 :     metrics_snapshots_.emplace_back(metrics_.trace_api.responses_1xx,
      36         392 :                                     MetricSnapshot{});
      37         196 :     metrics_snapshots_.emplace_back(metrics_.trace_api.responses_2xx,
      38         392 :                                     MetricSnapshot{});
      39         196 :     metrics_snapshots_.emplace_back(metrics_.trace_api.responses_3xx,
      40         392 :                                     MetricSnapshot{});
      41         196 :     metrics_snapshots_.emplace_back(metrics_.trace_api.responses_4xx,
      42         392 :                                     MetricSnapshot{});
      43         196 :     metrics_snapshots_.emplace_back(metrics_.trace_api.responses_5xx,
      44         392 :                                     MetricSnapshot{});
      45         196 :     metrics_snapshots_.emplace_back(metrics_.trace_api.errors_timeout,
      46         392 :                                     MetricSnapshot{});
      47         196 :     metrics_snapshots_.emplace_back(metrics_.trace_api.errors_network,
      48         392 :                                     MetricSnapshot{});
      49         196 :     metrics_snapshots_.emplace_back(metrics_.trace_api.errors_status_code,
      50         392 :                                     MetricSnapshot{});
      51             :   }
      52         607 : }
      53             : 
      54          40 : nlohmann::json TracerTelemetry::generate_telemetry_body(
      55             :     std::string request_type) {
      56          40 :   std::time_t tracer_time = std::chrono::duration_cast<std::chrono::seconds>(
      57          40 :                                 clock_().wall.time_since_epoch())
      58          40 :                                 .count();
      59          40 :   seq_id_++;
      60        1000 :   return nlohmann::json::object({
      61             :       {"api_version", "v2"},
      62          40 :       {"seq_id", seq_id_},
      63             :       {"request_type", request_type},
      64             :       {"tracer_time", tracer_time},
      65          40 :       {"runtime_id", tracer_signature_.runtime_id().string()},
      66          40 :       {"debug", debug_},
      67             :       {"application",
      68        1040 :        nlohmann::json::object({
      69          80 :            {"service_name", tracer_signature_.default_service()},
      70          80 :            {"env", tracer_signature_.default_environment()},
      71          80 :            {"tracer_version", tracer_signature_.library_version()},
      72          80 :            {"language_name", tracer_signature_.library_language()},
      73          80 :            {"language_version", tracer_signature_.library_language_version()},
      74             :        })},
      75             :       // TODO: host information (os, os_version, kernel, etc)
      76         240 :       {"host", nlohmann::json::object({
      77          40 :                    {"hostname", hostname_},
      78             :                })},
      79        1240 :   });
      80             : }
      81             : 
      82          19 : std::string TracerTelemetry::app_started() {
      83          38 :   auto telemetry_body = generate_telemetry_body("app-started");
      84             :   // TODO: environment variables or finalized config details
      85         114 :   telemetry_body["payload"] = nlohmann::json::object({
      86          38 :       {"configuration", nlohmann::json::array({})},
      87             : 
      88          19 :   });
      89          19 :   auto app_started_payload = telemetry_body.dump();
      90          38 :   return app_started_payload;
      91          19 : }
      92             : 
      93          19 : void TracerTelemetry::capture_metrics() {
      94          19 :   std::time_t timepoint = std::chrono::duration_cast<std::chrono::seconds>(
      95          19 :                               clock_().wall.time_since_epoch())
      96          19 :                               .count();
      97         285 :   for (auto& m : metrics_snapshots_) {
      98         266 :     auto value = m.first.get().capture_and_reset_value();
      99         266 :     if (value == 0) {
     100         230 :       continue;
     101             :     }
     102          36 :     m.second.emplace_back(timepoint, value);
     103             :   }
     104          19 : }
     105             : 
     106           2 : std::string TracerTelemetry::heartbeat_and_telemetry() {
     107           2 :   auto batch_payloads = nlohmann::json::array();
     108             : 
     109           8 :   auto heartbeat = nlohmann::json::object({
     110             :       {"request_type", "app-heartbeat"},
     111           4 :   });
     112           2 :   batch_payloads.emplace_back(std::move(heartbeat));
     113             : 
     114           2 :   auto metrics = nlohmann::json::array();
     115          30 :   for (auto& m : metrics_snapshots_) {
     116          28 :     auto& metric = m.first.get();
     117          28 :     auto& points = m.second;
     118          28 :     if (!points.empty()) {
     119           1 :       auto type = metric.type();
     120           1 :       if (type == "count") {
     121          23 :         metrics.emplace_back(nlohmann::json::object({
     122           2 :             {"metric", metric.name()},
     123           2 :             {"tags", metric.tags()},
     124           2 :             {"type", metric.type()},
     125             :             {"points", points},
     126           2 :             {"common", metric.common()},
     127             :         }));
     128           0 :       } else if (type == "gauge") {
     129             :         // gauge metrics have a interval
     130           0 :         metrics.emplace_back(nlohmann::json::object({
     131           0 :             {"metric", metric.name()},
     132           0 :             {"tags", metric.tags()},
     133           0 :             {"type", metric.type()},
     134           0 :             {"interval", 10},
     135             :             {"points", points},
     136           0 :             {"common", metric.common()},
     137             :         }));
     138             :       }
     139           1 :     }
     140          28 :     points.clear();
     141             :   }
     142             : 
     143           2 :   if (!metrics.empty()) {
     144           7 :     auto generate_metrics = nlohmann::json::object({
     145             :         {"request_type", "generate-metrics"},
     146          11 :         {"payload", nlohmann::json::object({
     147             :                         {"namespace", "tracers"},
     148             :                         {"series", metrics},
     149             :                     })},
     150           4 :     });
     151           1 :     batch_payloads.emplace_back(std::move(generate_metrics));
     152           1 :   }
     153             : 
     154           4 :   auto telemetry_body = generate_telemetry_body("message-batch");
     155           2 :   telemetry_body["payload"] = batch_payloads;
     156           2 :   auto message_batch_payload = telemetry_body.dump();
     157           4 :   return message_batch_payload;
     158           2 : }
     159             : 
     160          19 : std::string TracerTelemetry::app_closing() {
     161          19 :   auto batch_payloads = nlohmann::json::array();
     162             : 
     163          76 :   auto app_closing = nlohmann::json::object({
     164             :       {"request_type", "app-closing"},
     165          38 :   });
     166          19 :   batch_payloads.emplace_back(std::move(app_closing));
     167             : 
     168          19 :   auto metrics = nlohmann::json::array();
     169         285 :   for (auto& m : metrics_snapshots_) {
     170         266 :     auto& metric = m.first.get();
     171         266 :     auto& points = m.second;
     172         266 :     if (!points.empty()) {
     173          35 :       auto type = metric.type();
     174          35 :       if (type == "count") {
     175         805 :         metrics.emplace_back(nlohmann::json::object({
     176          70 :             {"metric", metric.name()},
     177          70 :             {"tags", metric.tags()},
     178          70 :             {"type", metric.type()},
     179             :             {"points", points},
     180          70 :             {"common", metric.common()},
     181             :         }));
     182           0 :       } else if (type == "gauge") {
     183             :         // gauge metrics have a interval
     184           0 :         metrics.emplace_back(nlohmann::json::object({
     185           0 :             {"metric", metric.name()},
     186           0 :             {"tags", metric.tags()},
     187           0 :             {"type", metric.type()},
     188           0 :             {"interval", 10},
     189             :             {"points", points},
     190           0 :             {"common", metric.common()},
     191             :         }));
     192             :       }
     193          35 :     }
     194         266 :     points.clear();
     195             :   }
     196             : 
     197          19 :   if (!metrics.empty()) {
     198          49 :     auto generate_metrics = nlohmann::json::object({
     199             :         {"request_type", "generate-metrics"},
     200          77 :         {"payload", nlohmann::json::object({
     201             :                         {"namespace", "tracers"},
     202             :                         {"series", metrics},
     203             :                     })},
     204          28 :     });
     205           7 :     batch_payloads.emplace_back(std::move(generate_metrics));
     206           7 :   }
     207             : 
     208          38 :   auto telemetry_body = generate_telemetry_body("message-batch");
     209          19 :   telemetry_body["payload"] = batch_payloads;
     210          19 :   auto message_batch_payload = telemetry_body.dump();
     211          38 :   return message_batch_payload;
     212          19 : }
     213             : 
     214             : }  // namespace tracing
     215             : }  // namespace datadog

Generated by: LCOV version 1.16