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_SRC_CORE_CHANNELZ_CHANNELZ_H 20 #define GRPC_SRC_CORE_CHANNELZ_CHANNELZ_H 21 22 #include <grpc/grpc.h> 23 #include <grpc/impl/connectivity_state.h> 24 #include <grpc/slice.h> 25 #include <grpc/support/port_platform.h> 26 #include <stddef.h> 27 28 #include <atomic> 29 #include <cstdint> 30 #include <map> 31 #include <set> 32 #include <string> 33 #include <utility> 34 35 #include "absl/base/thread_annotations.h" 36 #include "absl/strings/string_view.h" 37 #include "absl/types/optional.h" 38 #include "src/core/channelz/channel_trace.h" 39 #include "src/core/util/json/json.h" 40 #include "src/core/util/per_cpu.h" 41 #include "src/core/util/ref_counted.h" 42 #include "src/core/util/ref_counted_ptr.h" 43 #include "src/core/util/sync.h" 44 #include "src/core/util/time_precise.h" 45 #include "src/core/util/useful.h" 46 47 // Channel arg key for channelz node. 48 #define GRPC_ARG_CHANNELZ_CHANNEL_NODE "grpc.internal.channelz_channel_node" 49 50 // Channel arg key for indicating an internal channel. 51 #define GRPC_ARG_CHANNELZ_IS_INTERNAL_CHANNEL \ 52 "grpc.channelz_is_internal_channel" 53 54 /// This is the default value for whether or not to enable channelz. If 55 /// GRPC_ARG_ENABLE_CHANNELZ is set, it will override this default value. 56 #define GRPC_ENABLE_CHANNELZ_DEFAULT true 57 58 /// This is the default value for the maximum amount of memory used by trace 59 /// events per channel trace node. If 60 /// GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE is set, it will override 61 /// this default value. 62 #define GRPC_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE_DEFAULT (1024 * 4) 63 64 namespace grpc_core { 65 66 namespace channelz { 67 68 class SocketNode; 69 class ListenSocketNode; 70 71 namespace testing { 72 class CallCountingHelperPeer; 73 class SubchannelNodePeer; 74 } // namespace testing 75 76 // base class for all channelz entities 77 class BaseNode : public RefCounted<BaseNode> { 78 public: 79 // There are only four high level channelz entities. However, to support 80 // GetTopChannelsRequest, we split the Channel entity into two different 81 // types. All children of BaseNode must be one of these types. 82 enum class EntityType { 83 kTopLevelChannel, 84 kInternalChannel, 85 kSubchannel, 86 kServer, 87 kSocket, 88 }; 89 90 protected: 91 BaseNode(EntityType type, std::string name); 92 93 public: 94 ~BaseNode() override; 95 96 // All children must implement this function. 97 virtual Json RenderJson() = 0; 98 99 // Renders the json and returns allocated string that must be freed by the 100 // caller. 101 std::string RenderJsonString(); 102 type()103 EntityType type() const { return type_; } uuid()104 intptr_t uuid() const { return uuid_; } name()105 const std::string& name() const { return name_; } 106 107 private: 108 // to allow the ChannelzRegistry to set uuid_ under its lock. 109 friend class ChannelzRegistry; 110 const EntityType type_; 111 intptr_t uuid_; 112 std::string name_; 113 }; 114 115 // This class is a helper class for channelz entities that deal with Channels, 116 // Subchannels, and Servers, since those have similar proto definitions. 117 // This class has the ability to: 118 // - track calls_{started,succeeded,failed} 119 // - track last_call_started_timestamp 120 // - perform rendering of the above items 121 class CallCountingHelper final { 122 public: 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 std::atomic<int64_t> calls_started_{0}; 135 std::atomic<int64_t> calls_succeeded_{0}; 136 std::atomic<int64_t> calls_failed_{0}; 137 std::atomic<gpr_cycle_counter> last_call_started_cycle_{0}; 138 }; 139 140 class PerCpuCallCountingHelper final { 141 public: 142 void RecordCallStarted(); 143 void RecordCallFailed(); 144 void RecordCallSucceeded(); 145 146 // Common rendering of the call count data and last_call_started_timestamp. 147 void PopulateCallCounts(Json::Object* json); 148 149 private: 150 // testing peer friend. 151 friend class testing::CallCountingHelperPeer; 152 153 // We want to ensure that this per-cpu data structure lands on different 154 // cachelines per cpu. 155 // With C++17 we can do so explicitly with an `alignas` specifier. 156 // Prior versions we can at best approximate it by padding the structure. 157 // It'll probably work out ok, but it's not guaranteed across allocators. 158 // (in the bad case where this gets split across cachelines we'll just have 159 // two cpus fighting over the same cacheline with a slight performance 160 // degregation). 161 // TODO(ctiller): When we move to C++17 delete the duplicate definition. 162 #if __cplusplus >= 201703L 163 struct alignas(GPR_CACHELINE_SIZE) PerCpuData { 164 std::atomic<int64_t> calls_started{0}; 165 std::atomic<int64_t> calls_succeeded{0}; 166 std::atomic<int64_t> calls_failed{0}; 167 std::atomic<gpr_cycle_counter> last_call_started_cycle{0}; 168 }; 169 #else 170 struct PerCpuDataHeader { 171 std::atomic<int64_t> calls_started{0}; 172 std::atomic<int64_t> calls_succeeded{0}; 173 std::atomic<int64_t> calls_failed{0}; 174 std::atomic<gpr_cycle_counter> last_call_started_cycle{0}; 175 }; 176 struct PerCpuData : public PerCpuDataHeader { 177 uint8_t padding[GPR_CACHELINE_SIZE - sizeof(PerCpuDataHeader)]; 178 }; 179 #endif 180 PerCpu<PerCpuData> per_cpu_data_{PerCpuOptions().SetCpusPerShard(4)}; 181 }; 182 183 // Handles channelz bookkeeping for channels 184 class ChannelNode final : public BaseNode { 185 public: 186 ChannelNode(std::string target, size_t channel_tracer_max_nodes, 187 bool is_internal_channel); 188 ChannelArgName()189 static absl::string_view ChannelArgName() { 190 return GRPC_ARG_CHANNELZ_CHANNEL_NODE; 191 } ChannelArgsCompare(const ChannelNode * a,const ChannelNode * b)192 static int ChannelArgsCompare(const ChannelNode* a, const ChannelNode* b) { 193 return QsortCompare(a, b); 194 } 195 196 // Returns the string description of the given connectivity state. 197 static const char* GetChannelConnectivityStateChangeString( 198 grpc_connectivity_state state); 199 200 Json RenderJson() override; 201 202 // proxy methods to composed classes. AddTraceEvent(ChannelTrace::Severity severity,const grpc_slice & data)203 void AddTraceEvent(ChannelTrace::Severity severity, const grpc_slice& data) { 204 trace_.AddTraceEvent(severity, data); 205 } AddTraceEventWithReference(ChannelTrace::Severity severity,const grpc_slice & data,RefCountedPtr<BaseNode> referenced_channel)206 void AddTraceEventWithReference(ChannelTrace::Severity severity, 207 const grpc_slice& data, 208 RefCountedPtr<BaseNode> referenced_channel) { 209 trace_.AddTraceEventWithReference(severity, data, 210 std::move(referenced_channel)); 211 } RecordCallStarted()212 void RecordCallStarted() { call_counter_.RecordCallStarted(); } RecordCallFailed()213 void RecordCallFailed() { call_counter_.RecordCallFailed(); } RecordCallSucceeded()214 void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); } 215 216 void SetConnectivityState(grpc_connectivity_state state); 217 218 // TODO(roth): take in a RefCountedPtr to the child channel so we can retrieve 219 // the human-readable name. 220 void AddChildChannel(intptr_t child_uuid); 221 void RemoveChildChannel(intptr_t child_uuid); 222 223 // TODO(roth): take in a RefCountedPtr to the child subchannel so we can 224 // retrieve the human-readable name. 225 void AddChildSubchannel(intptr_t child_uuid); 226 void RemoveChildSubchannel(intptr_t child_uuid); 227 228 private: 229 void PopulateChildRefs(Json::Object* json); 230 231 std::string target_; 232 CallCountingHelper call_counter_; 233 ChannelTrace trace_; 234 235 // Least significant bit indicates whether the value is set. Remaining 236 // bits are a grpc_connectivity_state value. 237 std::atomic<int> connectivity_state_{0}; 238 239 Mutex child_mu_; // Guards sets below. 240 std::set<intptr_t> child_channels_; 241 std::set<intptr_t> child_subchannels_; 242 }; 243 244 // Handles channelz bookkeeping for subchannels 245 class SubchannelNode final : public BaseNode { 246 public: 247 SubchannelNode(std::string target_address, size_t channel_tracer_max_nodes); 248 ~SubchannelNode() override; 249 250 // Sets the subchannel's connectivity state without health checking. 251 void UpdateConnectivityState(grpc_connectivity_state state); 252 253 // Used when the subchannel's child socket changes. This should be set when 254 // the subchannel's transport is created and set to nullptr when the 255 // subchannel unrefs the transport. 256 void SetChildSocket(RefCountedPtr<SocketNode> socket); 257 258 Json RenderJson() override; 259 260 // proxy methods to composed classes. AddTraceEvent(ChannelTrace::Severity severity,const grpc_slice & data)261 void AddTraceEvent(ChannelTrace::Severity severity, const grpc_slice& data) { 262 trace_.AddTraceEvent(severity, data); 263 } AddTraceEventWithReference(ChannelTrace::Severity severity,const grpc_slice & data,RefCountedPtr<BaseNode> referenced_channel)264 void AddTraceEventWithReference(ChannelTrace::Severity severity, 265 const grpc_slice& data, 266 RefCountedPtr<BaseNode> referenced_channel) { 267 trace_.AddTraceEventWithReference(severity, data, 268 std::move(referenced_channel)); 269 } RecordCallStarted()270 void RecordCallStarted() { call_counter_.RecordCallStarted(); } RecordCallFailed()271 void RecordCallFailed() { call_counter_.RecordCallFailed(); } RecordCallSucceeded()272 void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); } 273 274 private: 275 // Allows the channel trace test to access trace_. 276 friend class testing::SubchannelNodePeer; 277 278 std::atomic<grpc_connectivity_state> connectivity_state_{GRPC_CHANNEL_IDLE}; 279 Mutex socket_mu_; 280 RefCountedPtr<SocketNode> child_socket_ ABSL_GUARDED_BY(socket_mu_); 281 std::string target_; 282 CallCountingHelper call_counter_; 283 ChannelTrace trace_; 284 }; 285 286 // Handles channelz bookkeeping for servers 287 class ServerNode final : public BaseNode { 288 public: 289 explicit ServerNode(size_t channel_tracer_max_nodes); 290 291 ~ServerNode() override; 292 293 Json RenderJson() override; 294 295 std::string RenderServerSockets(intptr_t start_socket_id, 296 intptr_t max_results); 297 298 void AddChildSocket(RefCountedPtr<SocketNode> node); 299 300 void RemoveChildSocket(intptr_t child_uuid); 301 302 void AddChildListenSocket(RefCountedPtr<ListenSocketNode> node); 303 304 void RemoveChildListenSocket(intptr_t child_uuid); 305 306 // proxy methods to composed classes. AddTraceEvent(ChannelTrace::Severity severity,const grpc_slice & data)307 void AddTraceEvent(ChannelTrace::Severity severity, const grpc_slice& data) { 308 trace_.AddTraceEvent(severity, data); 309 } AddTraceEventWithReference(ChannelTrace::Severity severity,const grpc_slice & data,RefCountedPtr<BaseNode> referenced_channel)310 void AddTraceEventWithReference(ChannelTrace::Severity severity, 311 const grpc_slice& data, 312 RefCountedPtr<BaseNode> referenced_channel) { 313 trace_.AddTraceEventWithReference(severity, data, 314 std::move(referenced_channel)); 315 } RecordCallStarted()316 void RecordCallStarted() { call_counter_.RecordCallStarted(); } RecordCallFailed()317 void RecordCallFailed() { call_counter_.RecordCallFailed(); } RecordCallSucceeded()318 void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); } 319 320 private: 321 PerCpuCallCountingHelper call_counter_; 322 ChannelTrace trace_; 323 Mutex child_mu_; // Guards child maps below. 324 std::map<intptr_t, RefCountedPtr<SocketNode>> child_sockets_; 325 std::map<intptr_t, RefCountedPtr<ListenSocketNode>> child_listen_sockets_; 326 }; 327 328 #define GRPC_ARG_CHANNELZ_SECURITY "grpc.internal.channelz_security" 329 330 // Handles channelz bookkeeping for sockets 331 class SocketNode final : public BaseNode { 332 public: 333 struct Security : public RefCounted<Security> { 334 struct Tls { 335 // This is a workaround for https://bugs.llvm.org/show_bug.cgi?id=50346 TlsSecurity::Tls336 Tls() {} 337 338 enum class NameType { kUnset = 0, kStandardName = 1, kOtherName = 2 }; 339 NameType type = NameType::kUnset; 340 // Holds the value of standard_name or other_names if type is not kUnset. 341 std::string name; 342 std::string local_certificate; 343 std::string remote_certificate; 344 345 Json RenderJson(); 346 }; 347 enum class ModelType { kUnset = 0, kTls = 1, kOther = 2 }; 348 ModelType type = ModelType::kUnset; 349 absl::optional<Tls> tls; 350 absl::optional<Json> other; 351 352 Json RenderJson(); 353 ChannelArgNameSecurity354 static absl::string_view ChannelArgName() { 355 return GRPC_ARG_CHANNELZ_SECURITY; 356 } 357 ChannelArgsCompareSecurity358 static int ChannelArgsCompare(const Security* a, const Security* b) { 359 return QsortCompare(a, b); 360 } 361 362 grpc_arg MakeChannelArg() const; 363 364 static RefCountedPtr<Security> GetFromChannelArgs( 365 const grpc_channel_args* args); 366 }; 367 368 SocketNode(std::string local, std::string remote, std::string name, 369 RefCountedPtr<Security> security); ~SocketNode()370 ~SocketNode() override {} 371 372 Json RenderJson() override; 373 374 void RecordStreamStartedFromLocal(); 375 void RecordStreamStartedFromRemote(); RecordStreamSucceeded()376 void RecordStreamSucceeded() { 377 streams_succeeded_.fetch_add(1, std::memory_order_relaxed); 378 } RecordStreamFailed()379 void RecordStreamFailed() { 380 streams_failed_.fetch_add(1, std::memory_order_relaxed); 381 } 382 void RecordMessagesSent(uint32_t num_sent); 383 void RecordMessageReceived(); RecordKeepaliveSent()384 void RecordKeepaliveSent() { 385 keepalives_sent_.fetch_add(1, std::memory_order_relaxed); 386 } 387 remote()388 const std::string& remote() { return remote_; } 389 390 private: 391 std::atomic<int64_t> streams_started_{0}; 392 std::atomic<int64_t> streams_succeeded_{0}; 393 std::atomic<int64_t> streams_failed_{0}; 394 std::atomic<int64_t> messages_sent_{0}; 395 std::atomic<int64_t> messages_received_{0}; 396 std::atomic<int64_t> keepalives_sent_{0}; 397 std::atomic<gpr_cycle_counter> last_local_stream_created_cycle_{0}; 398 std::atomic<gpr_cycle_counter> last_remote_stream_created_cycle_{0}; 399 std::atomic<gpr_cycle_counter> last_message_sent_cycle_{0}; 400 std::atomic<gpr_cycle_counter> last_message_received_cycle_{0}; 401 std::string local_; 402 std::string remote_; 403 RefCountedPtr<Security> const security_; 404 }; 405 406 // Handles channelz bookkeeping for listen sockets 407 class ListenSocketNode final : public BaseNode { 408 public: 409 ListenSocketNode(std::string local_addr, std::string name); ~ListenSocketNode()410 ~ListenSocketNode() override {} 411 412 Json RenderJson() override; 413 414 private: 415 std::string local_addr_; 416 }; 417 418 } // namespace channelz 419 } // namespace grpc_core 420 421 #endif // GRPC_SRC_CORE_CHANNELZ_CHANNELZ_H 422