3 * Copyright 2018 gRPC authors.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
19 #ifndef GRPC_CORE_EXT_XDS_XDS_CLIENT_STATS_H
20 #define GRPC_CORE_EXT_XDS_XDS_CLIENT_STATS_H
22 #include <grpc/support/port_platform.h>
27 #include "absl/strings/str_cat.h"
28 #include "absl/strings/str_format.h"
29 #include "absl/strings/string_view.h"
31 #include "src/core/lib/gprpp/atomic.h"
32 #include "src/core/lib/gprpp/memory.h"
33 #include "src/core/lib/gprpp/ref_counted.h"
34 #include "src/core/lib/gprpp/sync.h"
35 #include "src/core/lib/iomgr/exec_ctx.h"
39 // Forward declaration to avoid circular dependency.
43 class XdsLocalityName : public RefCounted<XdsLocalityName> {
46 bool operator()(const XdsLocalityName* lhs,
47 const XdsLocalityName* rhs) const {
48 return lhs->Compare(*rhs) < 0;
51 bool operator()(const RefCountedPtr<XdsLocalityName>& lhs,
52 const RefCountedPtr<XdsLocalityName>& rhs) const {
53 return (*this)(lhs.get(), rhs.get());
57 XdsLocalityName(std::string region, std::string zone, std::string subzone)
58 : region_(std::move(region)),
59 zone_(std::move(zone)),
60 sub_zone_(std::move(subzone)) {}
62 bool operator==(const XdsLocalityName& other) const {
63 return region_ == other.region_ && zone_ == other.zone_ &&
64 sub_zone_ == other.sub_zone_;
67 bool operator!=(const XdsLocalityName& other) const {
68 return !(*this == other);
71 int Compare(const XdsLocalityName& other) const {
72 int cmp_result = region_.compare(other.region_);
73 if (cmp_result != 0) return cmp_result;
74 cmp_result = zone_.compare(other.zone_);
75 if (cmp_result != 0) return cmp_result;
76 return sub_zone_.compare(other.sub_zone_);
79 const std::string& region() const { return region_; }
80 const std::string& zone() const { return zone_; }
81 const std::string& sub_zone() const { return sub_zone_; }
83 const std::string& AsHumanReadableString() {
84 if (human_readable_string_.empty()) {
85 human_readable_string_ =
86 absl::StrFormat("{region=\"%s\", zone=\"%s\", sub_zone=\"%s\"}",
87 region_, zone_, sub_zone_);
89 return human_readable_string_;
95 std::string sub_zone_;
96 std::string human_readable_string_;
99 // Drop stats for an xds cluster.
100 class XdsClusterDropStats : public RefCounted<XdsClusterDropStats> {
102 using DroppedRequestsMap = std::map<std::string /* category */, uint64_t>;
104 XdsClusterDropStats(RefCountedPtr<XdsClient> xds_client,
105 absl::string_view lrs_server_name,
106 absl::string_view cluster_name,
107 absl::string_view eds_service_name);
108 ~XdsClusterDropStats();
110 // Returns a snapshot of this instance and resets all the counters.
111 DroppedRequestsMap GetSnapshotAndReset();
113 void AddCallDropped(const std::string& category);
116 RefCountedPtr<XdsClient> xds_client_;
117 absl::string_view lrs_server_name_;
118 absl::string_view cluster_name_;
119 absl::string_view eds_service_name_;
120 // Protects dropped_requests_. A mutex is necessary because the length of
121 // dropped_requests_ can be accessed by both the picker (from data plane
122 // mutex) and the load reporting thread (from the control plane combiner).
124 DroppedRequestsMap dropped_requests_;
127 // Locality stats for an xds cluster.
128 class XdsClusterLocalityStats : public RefCounted<XdsClusterLocalityStats> {
130 struct BackendMetric {
131 uint64_t num_requests_finished_with_metric;
132 double total_metric_value;
134 BackendMetric& operator+=(const BackendMetric& other) {
135 num_requests_finished_with_metric +=
136 other.num_requests_finished_with_metric;
137 total_metric_value += other.total_metric_value;
141 bool IsZero() const {
142 return num_requests_finished_with_metric == 0 && total_metric_value == 0;
147 uint64_t total_successful_requests;
148 uint64_t total_requests_in_progress;
149 uint64_t total_error_requests;
150 uint64_t total_issued_requests;
151 std::map<std::string, BackendMetric> backend_metrics;
153 Snapshot& operator+=(const Snapshot& other) {
154 total_successful_requests += other.total_successful_requests;
155 total_requests_in_progress += other.total_requests_in_progress;
156 total_error_requests += other.total_error_requests;
157 total_issued_requests += other.total_issued_requests;
158 for (const auto& p : other.backend_metrics) {
159 backend_metrics[p.first] += p.second;
164 bool IsZero() const {
165 if (total_successful_requests != 0 || total_requests_in_progress != 0 ||
166 total_error_requests != 0 || total_issued_requests != 0) {
169 for (const auto& p : backend_metrics) {
170 if (!p.second.IsZero()) return false;
176 XdsClusterLocalityStats(RefCountedPtr<XdsClient> xds_client,
177 absl::string_view lrs_server_name,
178 absl::string_view cluster_name,
179 absl::string_view eds_service_name,
180 RefCountedPtr<XdsLocalityName> name);
181 ~XdsClusterLocalityStats();
183 // Returns a snapshot of this instance and resets all the counters.
184 Snapshot GetSnapshotAndReset();
186 void AddCallStarted();
187 void AddCallFinished(bool fail = false);
190 RefCountedPtr<XdsClient> xds_client_;
191 absl::string_view lrs_server_name_;
192 absl::string_view cluster_name_;
193 absl::string_view eds_service_name_;
194 RefCountedPtr<XdsLocalityName> name_;
196 Atomic<uint64_t> total_successful_requests_{0};
197 Atomic<uint64_t> total_requests_in_progress_{0};
198 Atomic<uint64_t> total_error_requests_{0};
199 Atomic<uint64_t> total_issued_requests_{0};
201 // Protects backend_metrics_. A mutex is necessary because the length of
202 // backend_metrics_ can be accessed by both the callback intercepting the
203 // call's recv_trailing_metadata (not from the control plane work serializer)
204 // and the load reporting thread (from the control plane work serializer).
205 Mutex backend_metrics_mu_;
206 std::map<std::string, BackendMetric> backend_metrics_;
209 } // namespace grpc_core
211 #endif /* GRPC_CORE_EXT_XDS_XDS_CLIENT_STATS_H */