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