1
#include "source/common/orca/orca_load_metrics.h"
2

            
3
#include <string>
4

            
5
#include "source/common/orca/orca_parser.h"
6

            
7
#include "absl/strings/match.h"
8
#include "absl/strings/str_cat.h"
9
#include "absl/strings/string_view.h"
10

            
11
namespace Envoy {
12
namespace Orca {
13
namespace {
14
// The following fields are the names of the metrics tracked in the ORCA load
15
// report proto.
16
static constexpr absl::string_view kApplicationUtilizationField = "application_utilization";
17
static constexpr absl::string_view kCpuUtilizationField = "cpu_utilization";
18
static constexpr absl::string_view kMemUtilizationField = "mem_utilization";
19
static constexpr absl::string_view kEpsField = "eps";
20
static constexpr absl::string_view kRpsFractionalField = "rps_fractional";
21
static constexpr absl::string_view kNamedMetricsFieldPrefix = "named_metrics.";
22
static constexpr absl::string_view kRequestCostFieldPrefix = "request_cost.";
23
static constexpr absl::string_view kUtilizationFieldPrefix = "utilization.";
24

            
25
using OnLoadReportMetricFn =
26
    std::function<void(absl::string_view metric_name, double metric_value)>;
27

            
28
void scanOrcaLoadReportMetricsMap(const Protobuf::Map<std::string, double>& metrics_map,
29
                                  absl::string_view metric_name,
30
                                  absl::string_view metric_name_prefix,
31
48
                                  OnLoadReportMetricFn on_load_report_metric) {
32
48
  absl::string_view metric_name_without_prefix = metric_name.substr(metric_name_prefix.size());
33
  // If the metric name is "*", report all metrics from the map.
34
48
  if (metric_name_without_prefix == "*") {
35
8
    for (const auto& [key, value] : metrics_map) {
36
8
      on_load_report_metric(absl::StrCat(metric_name_prefix, key), value);
37
8
    }
38
46
  } else {
39
    // Report the metric if it exists in the map.
40
44
    const auto metric_it = metrics_map.find(metric_name_without_prefix);
41
44
    if (metric_it != metrics_map.end()) {
42
39
      on_load_report_metric(metric_name, metric_it->second);
43
39
    }
44
44
  }
45
48
}
46

            
47
void scanOrcaLoadReport(const LrsReportMetricNames& metric_names,
48
                        const xds::data::orca::v3::OrcaLoadReport& report,
49
45
                        OnLoadReportMetricFn on_load_report_metric) {
50
  // TODO(efimki): Use InlineMap to speed up this loop.
51
91
  for (const std::string& metric_name : metric_names) {
52
91
    if (metric_name == kCpuUtilizationField) {
53
39
      on_load_report_metric(metric_name, report.cpu_utilization());
54
52
    } else if (metric_name == kMemUtilizationField) {
55
1
      on_load_report_metric(metric_name, report.mem_utilization());
56
51
    } else if (metric_name == kApplicationUtilizationField) {
57
1
      on_load_report_metric(metric_name, report.application_utilization());
58
50
    } else if (metric_name == kEpsField) {
59
1
      on_load_report_metric(metric_name, report.eps());
60
49
    } else if (metric_name == kRpsFractionalField) {
61
1
      on_load_report_metric(metric_name, report.rps_fractional());
62
48
    } else if (absl::StartsWith(metric_name, kNamedMetricsFieldPrefix)) {
63
45
      scanOrcaLoadReportMetricsMap(report.named_metrics(), metric_name, kNamedMetricsFieldPrefix,
64
45
                                   on_load_report_metric);
65
45
    } else if (absl::StartsWith(metric_name, kUtilizationFieldPrefix)) {
66
2
      scanOrcaLoadReportMetricsMap(report.utilization(), metric_name, kUtilizationFieldPrefix,
67
2
                                   on_load_report_metric);
68
2
    } else if (absl::StartsWith(metric_name, kRequestCostFieldPrefix)) {
69
1
      scanOrcaLoadReportMetricsMap(report.request_cost(), metric_name, kRequestCostFieldPrefix,
70
1
                                   on_load_report_metric);
71
1
    }
72
91
  }
73
45
}
74

            
75
} // namespace
76

            
77
void addOrcaLoadReportToLoadMetricStats(const LrsReportMetricNames& metric_names,
78
                                        const xds::data::orca::v3::OrcaLoadReport& report,
79
41
                                        Upstream::LoadMetricStats& stats) {
80
41
  scanOrcaLoadReport(metric_names, report,
81
89
                     [&stats](absl::string_view metric_name, double metric_value) {
82
89
                       stats.add(metric_name, metric_value);
83
89
                     });
84
41
}
85

            
86
double getMaxUtilization(const LrsReportMetricNames& metric_names,
87
4
                         const xds::data::orca::v3::OrcaLoadReport& report) {
88
4
  double max_utilization = 0;
89
4
  scanOrcaLoadReport(metric_names, report,
90
4
                     [&max_utilization](absl::string_view, double metric_value) {
91
1
                       max_utilization = std::max<double>(max_utilization, metric_value);
92
1
                     });
93
4
  return max_utilization;
94
4
}
95

            
96
} // namespace Orca
97
} // namespace Envoy