Line data Source code
1 : #include "source/common/grpc/context_impl.h"
2 :
3 : #include <cstdint>
4 : #include <memory>
5 : #include <string>
6 : #include <tuple>
7 : #include <utility>
8 :
9 : #include "source/common/grpc/common.h"
10 : #include "source/common/stats/utility.h"
11 :
12 : #include "absl/strings/str_replace.h"
13 :
14 : namespace Envoy {
15 : namespace Grpc {
16 :
17 : ContextImpl::ContextImpl(Stats::SymbolTable& symbol_table)
18 : : stat_name_pool_(symbol_table), grpc_(stat_name_pool_.add("grpc")),
19 : grpc_web_(stat_name_pool_.add("grpc-web")), success_(stat_name_pool_.add("success")),
20 : failure_(stat_name_pool_.add("failure")), total_(stat_name_pool_.add("total")),
21 : zero_(stat_name_pool_.add("0")),
22 : request_message_count_(stat_name_pool_.add("request_message_count")),
23 : response_message_count_(stat_name_pool_.add("response_message_count")),
24 481 : upstream_rq_time_(stat_name_pool_.add("upstream_rq_time")), stat_names_(symbol_table) {}
25 :
26 : // Gets the stat prefix and underlying storage, depending on whether request_names is empty
27 : Stats::ElementVec ContextImpl::statElements(Protocol protocol,
28 : const absl::optional<RequestStatNames>& request_names,
29 3 : Stats::Element suffix) {
30 3 : const Stats::StatName protocolName = protocolStatName(protocol);
31 3 : if (request_names) {
32 0 : return Stats::ElementVec{protocolName, request_names->service_, request_names->method_, suffix};
33 0 : }
34 3 : return Stats::ElementVec{protocolName, suffix};
35 3 : }
36 :
37 : void ContextImpl::chargeStat(const Upstream::ClusterInfo& cluster, Protocol protocol,
38 : const absl::optional<RequestStatNames>& request_names,
39 2 : const Http::HeaderEntry* grpc_status) {
40 2 : if (!grpc_status) {
41 1 : return;
42 1 : }
43 :
44 1 : absl::string_view status_str = grpc_status->value().getStringView();
45 1 : auto iter = stat_names_.status_names_.find(status_str);
46 1 : Stats::ElementVec elements =
47 1 : statElements(protocol, request_names,
48 1 : (iter != stat_names_.status_names_.end()) ? Stats::Element(iter->second)
49 1 : : Stats::DynamicName(status_str));
50 1 : Stats::Utility::counterFromElements(cluster.statsScope(), elements).inc();
51 1 : chargeStat(cluster, protocol, request_names, (status_str == "0"));
52 1 : }
53 :
54 : void ContextImpl::chargeStat(const Upstream::ClusterInfo& cluster, Protocol protocol,
55 1 : const absl::optional<RequestStatNames>& request_names, bool success) {
56 1 : Stats::ElementVec elements = statElements(protocol, request_names, successStatName(success));
57 1 : Stats::Utility::counterFromElements(cluster.statsScope(), elements).inc();
58 1 : elements.back() = total_;
59 1 : Stats::Utility::counterFromElements(cluster.statsScope(), elements).inc();
60 1 : }
61 :
62 : void ContextImpl::chargeStat(const Upstream::ClusterInfo& cluster,
63 0 : const absl::optional<RequestStatNames>& request_names, bool success) {
64 0 : chargeStat(cluster, Protocol::Grpc, request_names, success);
65 0 : }
66 :
67 : void ContextImpl::chargeRequestMessageStat(const Upstream::ClusterInfo& cluster,
68 : const absl::optional<RequestStatNames>& request_names,
69 0 : uint64_t amount) {
70 0 : Stats::ElementVec elements = statElements(Protocol::Grpc, request_names, request_message_count_);
71 0 : Stats::Utility::counterFromElements(cluster.statsScope(), elements).add(amount);
72 0 : }
73 :
74 : void ContextImpl::chargeResponseMessageStat(const Upstream::ClusterInfo& cluster,
75 : const absl::optional<RequestStatNames>& request_names,
76 1 : uint64_t amount) {
77 1 : Stats::ElementVec elements = statElements(Protocol::Grpc, request_names, response_message_count_);
78 1 : Stats::Utility::counterFromElements(cluster.statsScope(), elements).add(amount);
79 1 : }
80 :
81 : void ContextImpl::chargeUpstreamStat(const Upstream::ClusterInfo& cluster,
82 : const absl::optional<RequestStatNames>& request_names,
83 0 : std::chrono::milliseconds duration) {
84 0 : Stats::ElementVec elements = statElements(Protocol::Grpc, request_names, upstream_rq_time_);
85 0 : Stats::Utility::histogramFromElements(cluster.statsScope(), elements,
86 0 : Stats::Histogram::Unit::Milliseconds)
87 0 : .recordValue(duration.count());
88 0 : }
89 :
90 : absl::optional<ContextImpl::RequestStatNames>
91 0 : ContextImpl::resolveDynamicServiceAndMethod(const Http::HeaderEntry* path) {
92 0 : absl::optional<Common::RequestNames> request_names = Common::resolveServiceAndMethod(path);
93 :
94 0 : if (!request_names) {
95 0 : return {};
96 0 : }
97 :
98 : // service/method will live until the request is finished to emit resulting stats (e.g. request
99 : // status) values in request_names_ might get changed, for example by routing rules (i.e.
100 : // "prefix_rewrite"), so we copy them here to preserve the initial value and get a proper stat
101 0 : Stats::Element service = Stats::DynamicSavedName(request_names->service_);
102 0 : Stats::Element method = Stats::DynamicSavedName(request_names->method_);
103 0 : return RequestStatNames{service, method};
104 0 : }
105 :
106 : absl::optional<ContextImpl::RequestStatNames>
107 0 : ContextImpl::resolveDynamicServiceAndMethodWithDotReplaced(const Http::HeaderEntry* path) {
108 0 : absl::optional<Common::RequestNames> request_names = Common::resolveServiceAndMethod(path);
109 0 : if (!request_names) {
110 0 : return {};
111 0 : }
112 0 : Stats::Element service =
113 0 : Stats::DynamicSavedName(absl::StrReplaceAll(request_names->service_, {{".", "_"}}));
114 0 : Stats::Element method = Stats::DynamicSavedName(request_names->method_);
115 0 : return RequestStatNames{service, method};
116 0 : }
117 :
118 : } // namespace Grpc
119 : } // namespace Envoy
|