LCOV - code coverage report
Current view: top level - datadog - tag_propagation.cpp (source / functions) Hit Total Coverage
Test: filtered.info Lines: 46 47 97.9 %
Date: 2024-01-03 20:30:12 Functions: 4 4 100.0 %

          Line data    Source code
       1             : #include "tag_propagation.h"
       2             : 
       3             : #include <algorithm>
       4             : #include <cstddef>
       5             : #include <sstream>
       6             : 
       7             : #include "error.h"
       8             : #include "parse_util.h"
       9             : 
      10             : namespace datadog {
      11             : namespace tracing {
      12             : 
      13             : // The following [eBNF][1] grammar describes the tag propagation encoding.
      14             : // The grammar was copied from [an internal design document][2].
      15             : //
      16             : //     tagset = ( tag, { ",", tag } ) | "";
      17             : //     tag = ( identifier - space or equal ), "=", identifier;
      18             : //     identifier = allowed characters, { allowed characters };
      19             : //     allowed characters = ( ? ASCII characters 32-126 ? - "," );
      20             : //     space or equal = " " | "=";
      21             : //
      22             : // That is, comma-separated "<key>=<value>" pairs.
      23             : //
      24             : // See `tag_propagation_test.cpp` for examples.
      25             : //
      26             : // [1]: https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form
      27             : // [2]:
      28             : // https://docs.google.com/document/d/1zeO6LGnvxk5XweObHAwJbK3SfK23z7jQzp7ozWJTa2A/edit#heading=h.yp07yuixga36
      29             : 
      30             : namespace {
      31             : 
      32             : // Insert into the specified `destination` a tag decoded from the specified
      33             : // `entry`.  Return an `Error` if an error occurs.
      34       10042 : Expected<void> decode_tag(
      35             :     std::vector<std::pair<std::string, std::string>>& destination,
      36             :     StringView entry) {
      37       10042 :   const auto separator = std::find(entry.begin(), entry.end(), '=');
      38       10042 :   if (separator == entry.end()) {
      39           2 :     std::string message;
      40           2 :     message += "invalid key=value pair for encoded tag: missing \"=\" in: ";
      41           2 :     append(message, entry);
      42           2 :     return Error{Error::MALFORMED_TRACE_TAGS, std::move(message)};
      43           2 :   }
      44             : 
      45       10040 :   const StringView key = range(entry.begin(), separator);
      46       10040 :   const StringView value = range(separator + 1, entry.end());
      47       10040 :   destination.emplace_back(std::string(key), std::string(value));
      48             : 
      49       10040 :   return nullopt;
      50             : }
      51             : 
      52       10015 : void append_tag(std::string& serialized_tags, StringView tag_key,
      53             :                 StringView tag_value) {
      54       10015 :   serialized_tags.append(tag_key.begin(), tag_key.end());
      55       10015 :   serialized_tags += '=';
      56       10015 :   serialized_tags.append(tag_value.begin(), tag_value.end());
      57       10015 : }
      58             : 
      59             : }  // namespace
      60             : 
      61          24 : Expected<std::vector<std::pair<std::string, std::string>>> decode_tags(
      62             :     StringView header_value) {
      63          24 :   std::vector<std::pair<std::string, std::string>> tags;
      64             : 
      65          24 :   auto iter = header_value.begin();
      66          24 :   const auto end = header_value.end();
      67          24 :   if (iter == end) {
      68             :     // An empty string means no tags.
      69           3 :     return tags;
      70             :   }
      71             : 
      72             :   decltype(iter) next;
      73             :   do {
      74       10042 :     next = std::find(iter, end, ',');
      75       10042 :     auto result = decode_tag(tags, range(iter, next));
      76       10042 :     if (auto* error = result.if_error()) {
      77           2 :       std::string prefix;
      78           2 :       prefix += "Error decoding trace tags \"";
      79           2 :       append(prefix, header_value);
      80           2 :       prefix += "\": ";
      81           2 :       return error->with_prefix(prefix);
      82           2 :     }
      83       10040 :     iter = next + 1;
      84       20082 :   } while (next != end);
      85             : 
      86          19 :   return tags;
      87          24 : }
      88             : 
      89          12 : std::string encode_tags(
      90             :     const std::vector<std::pair<std::string, std::string>>& trace_tags) {
      91          12 :   std::string result;
      92          12 :   auto iter = trace_tags.begin();
      93          12 :   if (iter == trace_tags.end()) {
      94           2 :     return result;
      95             :   }
      96             : 
      97          10 :   append_tag(result, iter->first, iter->second);
      98       10015 :   for (++iter; iter != trace_tags.end(); ++iter) {
      99       10005 :     result += ',';
     100       10005 :     append_tag(result, iter->first, iter->second);
     101             :   }
     102             : 
     103          10 :   return result;
     104           0 : }
     105             : 
     106             : }  // namespace tracing
     107             : }  // namespace datadog

Generated by: LCOV version 1.16