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

          Line data    Source code
       1             : #include "span_matcher.h"
       2             : 
       3             : #include <algorithm>
       4             : 
       5             : #include "error.h"
       6             : #include "glob.h"
       7             : #include "json.hpp"
       8             : #include "optional.h"
       9             : #include "span_data.h"
      10             : 
      11             : namespace datadog {
      12             : namespace tracing {
      13             : namespace {
      14             : 
      15      163051 : bool is_match(StringView pattern, StringView subject) {
      16             :   // Since "*" is the default pattern, optimize for that case.
      17      163051 :   return pattern == "*" || glob_match(pattern, subject);
      18             : }
      19             : 
      20             : }  // namespace
      21             : 
      22          34 : nlohmann::json SpanMatcher::to_json() const {
      23         442 :   return nlohmann::json::object({
      24          34 :       {"service", service},
      25          34 :       {"name", name},
      26          34 :       {"resource", resource},
      27          34 :       {"tags", tags},
      28         476 :   });
      29             : }
      30             : 
      31       54352 : bool SpanMatcher::match(const SpanData& span) const {
      32      108702 :   return is_match(service, span.service) && is_match(name, span.name) &&
      33      163043 :          is_match(resource, span.resource) &&
      34       54341 :          std::all_of(tags.begin(), tags.end(), [&](const auto& entry) {
      35           5 :            const auto& [name, pattern] = entry;
      36           5 :            auto found = span.tags.find(name);
      37           5 :            return found != span.tags.end() && is_match(pattern, found->second);
      38       54352 :          });
      39             : }
      40             : 
      41          26 : Expected<SpanMatcher> SpanMatcher::from_json(const nlohmann::json& json) {
      42          26 :   SpanMatcher result;
      43             : 
      44          26 :   std::string type = json.type_name();
      45          26 :   if (type != "object") {
      46           2 :     std::string message;
      47           2 :     message += "A rule must be a JSON object, but this is of type \"";
      48           2 :     message += type;
      49           2 :     message += "\": ";
      50           2 :     message += json.dump();
      51           2 :     return Error{Error::RULE_WRONG_TYPE, std::move(message)};
      52           2 :   }
      53             : 
      54             :   const auto check_property_type =
      55          18 :       [&](StringView property, const nlohmann::json& value,
      56             :           StringView expected_type) -> Optional<Error> {
      57          18 :     type = value.type_name();
      58          18 :     if (type == expected_type) {
      59          10 :       return nullopt;
      60             :     }
      61             : 
      62           8 :     std::string message;
      63           8 :     message += "Rule property \"";
      64           8 :     append(message, property);
      65           8 :     message += "\" should have type \"";
      66           8 :     append(message, expected_type);
      67           8 :     message += "\", but has type \"";
      68           8 :     message += type;
      69           8 :     message += "\": ";
      70           8 :     message += value.dump();
      71           8 :     message += " in rule ";
      72           8 :     message += json.dump();
      73           8 :     return Error{Error::RULE_PROPERTY_WRONG_TYPE, std::move(message)};
      74           8 :   };
      75             : 
      76          46 :   for (const auto& [key, value] : json.items()) {
      77          32 :     if (key == "service") {
      78           3 :       if (auto error = check_property_type(key, value, "string")) {
      79           2 :         return *error;
      80           3 :       }
      81           1 :       result.service = value;
      82          29 :     } else if (key == "name") {
      83           6 :       if (auto error = check_property_type(key, value, "string")) {
      84           2 :         return *error;
      85           6 :       }
      86           4 :       result.name = value;
      87          23 :     } else if (key == "resource") {
      88           4 :       if (auto error = check_property_type(key, value, "string")) {
      89           2 :         return *error;
      90           4 :       }
      91           2 :       result.resource = value;
      92          19 :     } else if (key == "tags") {
      93           5 :       if (auto error = check_property_type(key, value, "object")) {
      94           2 :         return *error;
      95           5 :       }
      96           4 :       for (const auto& [tag_name, tag_value] : value.items()) {
      97           3 :         type = tag_value.type_name();
      98           3 :         if (type != "string") {
      99           2 :           std::string message;
     100           2 :           message += "Rule tag pattern must be a string, but ";
     101           2 :           message += tag_value.dump();
     102           2 :           message += " has type \"";
     103           2 :           message += type;
     104           2 :           message += "\" for tag named \"";
     105           2 :           message += tag_name;
     106           2 :           message += "\" in rule: ";
     107           2 :           message += json.dump();
     108           2 :           return Error{Error::RULE_TAG_WRONG_TYPE, std::move(message)};
     109           2 :         }
     110           1 :         result.tags.emplace(std::string(tag_name), std::string(tag_value));
     111           5 :       }
     112             :     } else {
     113             :       // Unknown properties are OK.  `SpanMatcher` is used as a base class for
     114             :       // trace sampling rules and span sampling rules.  Those derived types
     115             :       // will have additional properties in their JSON representations.
     116             :     }
     117          34 :   }
     118             : 
     119          14 :   return result;
     120          26 : }
     121             : 
     122             : }  // namespace tracing
     123             : }  // namespace datadog

Generated by: LCOV version 1.16