1 /*
2  *
3  * Copyright 2018 gRPC authors.
4  *
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
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  *
17  */
18 
19 #ifndef GRPC_CORE_LIB_CHANNEL_CHANNELZ_H
20 #define GRPC_CORE_LIB_CHANNEL_CHANNELZ_H
21 
22 #include <grpc/impl/codegen/port_platform.h>
23 
24 #include <grpc/grpc.h>
25 
26 #include "src/core/lib/channel/channel_trace.h"
27 #include "src/core/lib/gprpp/manual_constructor.h"
28 #include "src/core/lib/gprpp/ref_counted.h"
29 #include "src/core/lib/gprpp/ref_counted_ptr.h"
30 #include "src/core/lib/iomgr/error.h"
31 #include "src/core/lib/iomgr/exec_ctx.h"
32 #include "src/core/lib/json/json.h"
33 
34 // Channel arg key for client channel factory.
35 #define GRPC_ARG_CHANNELZ_CHANNEL_NODE_CREATION_FUNC \
36   "grpc.channelz_channel_node_creation_func"
37 
38 // Channel arg key to signal that the channel is an internal channel.
39 #define GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL \
40   "grpc.channelz_channel_is_internal_channel"
41 
42 namespace grpc_core {
43 namespace channelz {
44 
45 namespace testing {
46 class CallCountingHelperPeer;
47 class ChannelNodePeer;
48 }  // namespace testing
49 
50 // base class for all channelz entities
51 class BaseNode : public RefCounted<BaseNode> {
52  public:
53   // There are only four high level channelz entities. However, to support
54   // GetTopChannelsRequest, we split the Channel entity into two different
55   // types. All children of BaseNode must be one of these types.
56   enum class EntityType {
57     kTopLevelChannel,
58     kInternalChannel,
59     kSubchannel,
60     kServer,
61     kSocket,
62   };
63 
64   explicit BaseNode(EntityType type);
65   virtual ~BaseNode();
66 
67   // All children must implement this function.
68   virtual grpc_json* RenderJson() GRPC_ABSTRACT;
69 
70   // Renders the json and returns allocated string that must be freed by the
71   // caller.
72   char* RenderJsonString();
73 
type()74   EntityType type() const { return type_; }
uuid()75   intptr_t uuid() const { return uuid_; }
76 
77  private:
78   const EntityType type_;
79   const intptr_t uuid_;
80 };
81 
82 // This class is a helper class for channelz entities that deal with Channels,
83 // Subchannels, and Servers, since those have similar proto definitions.
84 // This class has the ability to:
85 //   - track calls_{started,succeeded,failed}
86 //   - track last_call_started_timestamp
87 //   - perform rendering of the above items
88 class CallCountingHelper {
89  public:
90   CallCountingHelper();
91   ~CallCountingHelper();
92 
93   void RecordCallStarted();
RecordCallFailed()94   void RecordCallFailed() {
95     gpr_atm_no_barrier_fetch_add(&calls_failed_, (gpr_atm(1)));
96   }
RecordCallSucceeded()97   void RecordCallSucceeded() {
98     gpr_atm_no_barrier_fetch_add(&calls_succeeded_, (gpr_atm(1)));
99   }
100 
101   // Common rendering of the call count data and last_call_started_timestamp.
102   void PopulateCallCounts(grpc_json* json);
103 
104  private:
105   // testing peer friend.
106   friend class testing::CallCountingHelperPeer;
107 
108   gpr_atm calls_started_ = 0;
109   gpr_atm calls_succeeded_ = 0;
110   gpr_atm calls_failed_ = 0;
111   gpr_atm last_call_started_millis_ = 0;
112 };
113 
114 // Handles channelz bookkeeping for channels
115 class ChannelNode : public BaseNode {
116  public:
117   static RefCountedPtr<ChannelNode> MakeChannelNode(
118       grpc_channel* channel, size_t channel_tracer_max_nodes,
119       bool is_top_level_channel);
120 
121   ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes,
122               bool is_top_level_channel);
123   ~ChannelNode() override;
124 
125   grpc_json* RenderJson() override;
126 
127   // template methods. RenderJSON uses these methods to render its JSON
128   // representation. These are virtual so that children classes may provide
129   // their specific mechanism for populating these parts of the channelz
130   // object.
131   //
132   // ChannelNode does not have a notion of connectivity state or child refs,
133   // so it leaves these implementations blank.
134   //
135   // This is utilizing the template method design pattern.
136   //
137   // TODO(ncteisen): remove these template methods in favor of manual traversal
138   // and mutation of the grpc_json object.
PopulateConnectivityState(grpc_json * json)139   virtual void PopulateConnectivityState(grpc_json* json) {}
PopulateChildRefs(grpc_json * json)140   virtual void PopulateChildRefs(grpc_json* json) {}
141 
MarkChannelDestroyed()142   void MarkChannelDestroyed() {
143     GPR_ASSERT(channel_ != nullptr);
144     channel_ = nullptr;
145   }
146 
ChannelIsDestroyed()147   bool ChannelIsDestroyed() { return channel_ == nullptr; }
148 
149   // proxy methods to composed classes.
AddTraceEvent(ChannelTrace::Severity severity,grpc_slice data)150   void AddTraceEvent(ChannelTrace::Severity severity, grpc_slice data) {
151     trace_.AddTraceEvent(severity, data);
152   }
AddTraceEventWithReference(ChannelTrace::Severity severity,grpc_slice data,RefCountedPtr<BaseNode> referenced_channel)153   void AddTraceEventWithReference(ChannelTrace::Severity severity,
154                                   grpc_slice data,
155                                   RefCountedPtr<BaseNode> referenced_channel) {
156     trace_.AddTraceEventWithReference(severity, data,
157                                       std::move(referenced_channel));
158   }
RecordCallStarted()159   void RecordCallStarted() { call_counter_.RecordCallStarted(); }
RecordCallFailed()160   void RecordCallFailed() { call_counter_.RecordCallFailed(); }
RecordCallSucceeded()161   void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); }
162 
163  private:
164   // to allow the channel trace test to access trace_.
165   friend class testing::ChannelNodePeer;
166   grpc_channel* channel_ = nullptr;
167   UniquePtr<char> target_;
168   CallCountingHelper call_counter_;
169   ChannelTrace trace_;
170 };
171 
172 // Handles channelz bookkeeping for servers
173 class ServerNode : public BaseNode {
174  public:
175   explicit ServerNode(size_t channel_tracer_max_nodes);
176   ~ServerNode() override;
177 
178   grpc_json* RenderJson() override;
179 
180   // proxy methods to composed classes.
AddTraceEvent(ChannelTrace::Severity severity,grpc_slice data)181   void AddTraceEvent(ChannelTrace::Severity severity, grpc_slice data) {
182     trace_.AddTraceEvent(severity, data);
183   }
AddTraceEventWithReference(ChannelTrace::Severity severity,grpc_slice data,RefCountedPtr<BaseNode> referenced_channel)184   void AddTraceEventWithReference(ChannelTrace::Severity severity,
185                                   grpc_slice data,
186                                   RefCountedPtr<BaseNode> referenced_channel) {
187     trace_.AddTraceEventWithReference(severity, data,
188                                       std::move(referenced_channel));
189   }
RecordCallStarted()190   void RecordCallStarted() { call_counter_.RecordCallStarted(); }
RecordCallFailed()191   void RecordCallFailed() { call_counter_.RecordCallFailed(); }
RecordCallSucceeded()192   void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); }
193 
194  private:
195   CallCountingHelper call_counter_;
196   ChannelTrace trace_;
197 };
198 
199 // Handles channelz bookkeeping for sockets
200 // TODO(ncteisen): implement in subsequent PR.
201 class SocketNode : public BaseNode {
202  public:
SocketNode()203   SocketNode() : BaseNode(EntityType::kSocket) {}
~SocketNode()204   ~SocketNode() override {}
205 };
206 
207 // Creation functions
208 
209 typedef RefCountedPtr<ChannelNode> (*ChannelNodeCreationFunc)(grpc_channel*,
210                                                               size_t, bool);
211 
212 }  // namespace channelz
213 }  // namespace grpc_core
214 
215 #endif /* GRPC_CORE_LIB_CHANNEL_CHANNELZ_H */
216