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 <set> 27 #include <string> 28 29 #include "absl/container/inlined_vector.h" 30 31 #include "src/core/lib/channel/channel_trace.h" 32 #include "src/core/lib/gpr/time_precise.h" 33 #include "src/core/lib/gprpp/atomic.h" 34 #include "src/core/lib/gprpp/manual_constructor.h" 35 #include "src/core/lib/gprpp/ref_counted.h" 36 #include "src/core/lib/gprpp/ref_counted_ptr.h" 37 #include "src/core/lib/gprpp/sync.h" 38 #include "src/core/lib/iomgr/error.h" 39 #include "src/core/lib/iomgr/exec_ctx.h" 40 #include "src/core/lib/json/json.h" 41 42 // Channel arg key for channelz node. 43 #define GRPC_ARG_CHANNELZ_CHANNEL_NODE "grpc.channelz_channel_node" 44 45 // Channel arg key for indicating an internal channel. 46 #define GRPC_ARG_CHANNELZ_IS_INTERNAL_CHANNEL \ 47 "grpc.channelz_is_internal_channel" 48 49 /** This is the default value for whether or not to enable channelz. If 50 * GRPC_ARG_ENABLE_CHANNELZ is set, it will override this default value. */ 51 #define GRPC_ENABLE_CHANNELZ_DEFAULT true 52 53 /** This is the default value for the maximum amount of memory used by trace 54 * events per channel trace node. If 55 * GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE is set, it will override 56 * this default value. */ 57 #define GRPC_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE_DEFAULT (1024 * 4) 58 59 namespace grpc_core { 60 61 namespace channelz { 62 63 class SocketNode; 64 class ListenSocketNode; 65 66 namespace testing { 67 class CallCountingHelperPeer; 68 class ChannelNodePeer; 69 } // namespace testing 70 71 // base class for all channelz entities 72 class BaseNode : public RefCounted<BaseNode> { 73 public: 74 // There are only four high level channelz entities. However, to support 75 // GetTopChannelsRequest, we split the Channel entity into two different 76 // types. All children of BaseNode must be one of these types. 77 enum class EntityType { 78 kTopLevelChannel, 79 kInternalChannel, 80 kSubchannel, 81 kServer, 82 kSocket, 83 }; 84 85 protected: 86 BaseNode(EntityType type, std::string name); 87 88 public: 89 ~BaseNode() override; 90 91 // All children must implement this function. 92 virtual Json RenderJson() = 0; 93 94 // Renders the json and returns allocated string that must be freed by the 95 // caller. 96 std::string RenderJsonString(); 97 type()98 EntityType type() const { return type_; } uuid()99 intptr_t uuid() const { return uuid_; } name()100 const std::string& name() const { return name_; } 101 102 private: 103 // to allow the ChannelzRegistry to set uuid_ under its lock. 104 friend class ChannelzRegistry; 105 const EntityType type_; 106 intptr_t uuid_; 107 std::string name_; 108 }; 109 110 // This class is a helper class for channelz entities that deal with Channels, 111 // Subchannels, and Servers, since those have similar proto definitions. 112 // This class has the ability to: 113 // - track calls_{started,succeeded,failed} 114 // - track last_call_started_timestamp 115 // - perform rendering of the above items 116 class CallCountingHelper { 117 public: 118 CallCountingHelper(); 119 120 void RecordCallStarted(); 121 void RecordCallFailed(); 122 void RecordCallSucceeded(); 123 124 // Common rendering of the call count data and last_call_started_timestamp. 125 void PopulateCallCounts(Json::Object* json); 126 127 private: 128 // testing peer friend. 129 friend class testing::CallCountingHelperPeer; 130 131 // TODO(soheil): add a proper PerCPU helper and use it here. 132 struct AtomicCounterData { 133 // Define the ctors so that we can use this structure in InlinedVector. 134 AtomicCounterData() = default; AtomicCounterDataAtomicCounterData135 AtomicCounterData(const AtomicCounterData& that) 136 : calls_started(that.calls_started.Load(MemoryOrder::RELAXED)), 137 calls_succeeded(that.calls_succeeded.Load(MemoryOrder::RELAXED)), 138 calls_failed(that.calls_failed.Load(MemoryOrder::RELAXED)), 139 last_call_started_cycle( 140 that.last_call_started_cycle.Load(MemoryOrder::RELAXED)) {} 141 142 Atomic<int64_t> calls_started{0}; 143 Atomic<int64_t> calls_succeeded{0}; 144 Atomic<int64_t> calls_failed{0}; 145 Atomic<gpr_cycle_counter> last_call_started_cycle{0}; 146 // Make sure the size is exactly one cache line. 147 uint8_t padding[GPR_CACHELINE_SIZE - 3 * sizeof(Atomic<intptr_t>) - 148 sizeof(Atomic<gpr_cycle_counter>)]; 149 }; 150 // TODO(soheilhy,veblush): Revist this after abseil integration. 151 // This has a problem when using abseil inlined_vector because it 152 // carries an alignment attribute properly but our allocator doesn't 153 // respect this. To avoid UBSAN errors, this should be removed with 154 // abseil inlined_vector. 155 // GPR_ALIGN_STRUCT(GPR_CACHELINE_SIZE); 156 157 struct CounterData { 158 int64_t calls_started = 0; 159 int64_t calls_succeeded = 0; 160 int64_t calls_failed = 0; 161 gpr_cycle_counter last_call_started_cycle = 0; 162 }; 163 164 // collects the sharded data into one CounterData struct. 165 void CollectData(CounterData* out); 166 167 // Really zero-sized, but 0-sized arrays are illegal on MSVC. 168 absl::InlinedVector<AtomicCounterData, 1> per_cpu_counter_data_storage_; 169 size_t num_cores_ = 0; 170 }; 171 172 // Handles channelz bookkeeping for channels 173 class ChannelNode : public BaseNode { 174 public: 175 ChannelNode(std::string target, size_t channel_tracer_max_nodes, 176 bool is_internal_channel); 177 178 // Returns the string description of the given connectivity state. 179 static const char* GetChannelConnectivityStateChangeString( 180 grpc_connectivity_state state); 181 182 Json RenderJson() override; 183 184 // proxy methods to composed classes. AddTraceEvent(ChannelTrace::Severity severity,const grpc_slice & data)185 void AddTraceEvent(ChannelTrace::Severity severity, const grpc_slice& data) { 186 trace_.AddTraceEvent(severity, data); 187 } AddTraceEventWithReference(ChannelTrace::Severity severity,const grpc_slice & data,RefCountedPtr<BaseNode> referenced_channel)188 void AddTraceEventWithReference(ChannelTrace::Severity severity, 189 const grpc_slice& data, 190 RefCountedPtr<BaseNode> referenced_channel) { 191 trace_.AddTraceEventWithReference(severity, data, 192 std::move(referenced_channel)); 193 } RecordCallStarted()194 void RecordCallStarted() { call_counter_.RecordCallStarted(); } RecordCallFailed()195 void RecordCallFailed() { call_counter_.RecordCallFailed(); } RecordCallSucceeded()196 void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); } 197 198 void SetConnectivityState(grpc_connectivity_state state); 199 200 // TODO(roth): take in a RefCountedPtr to the child channel so we can retrieve 201 // the human-readable name. 202 void AddChildChannel(intptr_t child_uuid); 203 void RemoveChildChannel(intptr_t child_uuid); 204 205 // TODO(roth): take in a RefCountedPtr to the child subchannel so we can 206 // retrieve the human-readable name. 207 void AddChildSubchannel(intptr_t child_uuid); 208 void RemoveChildSubchannel(intptr_t child_uuid); 209 210 private: 211 // Allows the channel trace test to access trace_. 212 friend class testing::ChannelNodePeer; 213 214 void PopulateChildRefs(Json::Object* json); 215 216 std::string target_; 217 CallCountingHelper call_counter_; 218 ChannelTrace trace_; 219 220 // Least significant bit indicates whether the value is set. Remaining 221 // bits are a grpc_connectivity_state value. 222 Atomic<int> connectivity_state_{0}; 223 224 Mutex child_mu_; // Guards sets below. 225 std::set<intptr_t> child_channels_; 226 std::set<intptr_t> child_subchannels_; 227 }; 228 229 // Handles channelz bookkeeping for servers 230 class ServerNode : public BaseNode { 231 public: 232 explicit ServerNode(size_t channel_tracer_max_nodes); 233 234 ~ServerNode() override; 235 236 Json RenderJson() override; 237 238 std::string RenderServerSockets(intptr_t start_socket_id, 239 intptr_t max_results); 240 241 void AddChildSocket(RefCountedPtr<SocketNode> node); 242 243 void RemoveChildSocket(intptr_t child_uuid); 244 245 void AddChildListenSocket(RefCountedPtr<ListenSocketNode> node); 246 247 void RemoveChildListenSocket(intptr_t child_uuid); 248 249 // proxy methods to composed classes. AddTraceEvent(ChannelTrace::Severity severity,const grpc_slice & data)250 void AddTraceEvent(ChannelTrace::Severity severity, const grpc_slice& data) { 251 trace_.AddTraceEvent(severity, data); 252 } AddTraceEventWithReference(ChannelTrace::Severity severity,const grpc_slice & data,RefCountedPtr<BaseNode> referenced_channel)253 void AddTraceEventWithReference(ChannelTrace::Severity severity, 254 const grpc_slice& data, 255 RefCountedPtr<BaseNode> referenced_channel) { 256 trace_.AddTraceEventWithReference(severity, data, 257 std::move(referenced_channel)); 258 } RecordCallStarted()259 void RecordCallStarted() { call_counter_.RecordCallStarted(); } RecordCallFailed()260 void RecordCallFailed() { call_counter_.RecordCallFailed(); } RecordCallSucceeded()261 void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); } 262 263 private: 264 CallCountingHelper call_counter_; 265 ChannelTrace trace_; 266 Mutex child_mu_; // Guards child maps below. 267 std::map<intptr_t, RefCountedPtr<SocketNode>> child_sockets_; 268 std::map<intptr_t, RefCountedPtr<ListenSocketNode>> child_listen_sockets_; 269 }; 270 271 // Handles channelz bookkeeping for sockets 272 class SocketNode : public BaseNode { 273 public: 274 SocketNode(std::string local, std::string remote, std::string name); ~SocketNode()275 ~SocketNode() override {} 276 277 Json RenderJson() override; 278 279 void RecordStreamStartedFromLocal(); 280 void RecordStreamStartedFromRemote(); RecordStreamSucceeded()281 void RecordStreamSucceeded() { 282 streams_succeeded_.FetchAdd(1, MemoryOrder::RELAXED); 283 } RecordStreamFailed()284 void RecordStreamFailed() { 285 streams_failed_.FetchAdd(1, MemoryOrder::RELAXED); 286 } 287 void RecordMessagesSent(uint32_t num_sent); 288 void RecordMessageReceived(); RecordKeepaliveSent()289 void RecordKeepaliveSent() { 290 keepalives_sent_.FetchAdd(1, MemoryOrder::RELAXED); 291 } 292 remote()293 const std::string& remote() { return remote_; } 294 295 private: 296 Atomic<int64_t> streams_started_{0}; 297 Atomic<int64_t> streams_succeeded_{0}; 298 Atomic<int64_t> streams_failed_{0}; 299 Atomic<int64_t> messages_sent_{0}; 300 Atomic<int64_t> messages_received_{0}; 301 Atomic<int64_t> keepalives_sent_{0}; 302 Atomic<gpr_cycle_counter> last_local_stream_created_cycle_{0}; 303 Atomic<gpr_cycle_counter> last_remote_stream_created_cycle_{0}; 304 Atomic<gpr_cycle_counter> last_message_sent_cycle_{0}; 305 Atomic<gpr_cycle_counter> last_message_received_cycle_{0}; 306 std::string local_; 307 std::string remote_; 308 }; 309 310 // Handles channelz bookkeeping for listen sockets 311 class ListenSocketNode : public BaseNode { 312 public: 313 ListenSocketNode(std::string local_addr, std::string name); ~ListenSocketNode()314 ~ListenSocketNode() override {} 315 316 Json RenderJson() override; 317 318 private: 319 std::string local_addr_; 320 }; 321 322 } // namespace channelz 323 } // namespace grpc_core 324 325 #endif /* GRPC_CORE_LIB_CHANNEL_CHANNELZ_H */ 326