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