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 19package channelz 20 21import ( 22 "net" 23 "time" 24 25 "google.golang.org/grpc/connectivity" 26 "google.golang.org/grpc/credentials" 27 "google.golang.org/grpc/grpclog" 28) 29 30// entry represents a node in the channelz database. 31type entry interface { 32 // addChild adds a child e, whose channelz id is id to child list 33 addChild(id int64, e entry) 34 // deleteChild deletes a child with channelz id to be id from child list 35 deleteChild(id int64) 36 // triggerDelete tries to delete self from channelz database. However, if child 37 // list is not empty, then deletion from the database is on hold until the last 38 // child is deleted from database. 39 triggerDelete() 40 // deleteSelfIfReady check whether triggerDelete() has been called before, and whether child 41 // list is now empty. If both conditions are met, then delete self from database. 42 deleteSelfIfReady() 43} 44 45// dummyEntry is a fake entry to handle entry not found case. 46type dummyEntry struct { 47 idNotFound int64 48} 49 50func (d *dummyEntry) addChild(id int64, e entry) { 51 // Note: It is possible for a normal program to reach here under race condition. 52 // For example, there could be a race between ClientConn.Close() info being propagated 53 // to addrConn and http2Client. ClientConn.Close() cancel the context and result 54 // in http2Client to error. The error info is then caught by transport monitor 55 // and before addrConn.tearDown() is called in side ClientConn.Close(). Therefore, 56 // the addrConn will create a new transport. And when registering the new transport in 57 // channelz, its parent addrConn could have already been torn down and deleted 58 // from channelz tracking, and thus reach the code here. 59 grpclog.Infof("attempt to add child of type %T with id %d to a parent (id=%d) that doesn't currently exist", e, id, d.idNotFound) 60} 61 62func (d *dummyEntry) deleteChild(id int64) { 63 // It is possible for a normal program to reach here under race condition. 64 // Refer to the example described in addChild(). 65 grpclog.Infof("attempt to delete child with id %d from a parent (id=%d) that doesn't currently exist", id, d.idNotFound) 66} 67 68func (d *dummyEntry) triggerDelete() { 69 grpclog.Warningf("attempt to delete an entry (id=%d) that doesn't currently exist", d.idNotFound) 70} 71 72func (*dummyEntry) deleteSelfIfReady() { 73 // code should not reach here. deleteSelfIfReady is always called on an existing entry. 74} 75 76// ChannelMetric defines the info channelz provides for a specific Channel, which 77// includes ChannelInternalMetric and channelz-specific data, such as channelz id, 78// child list, etc. 79type ChannelMetric struct { 80 // ID is the channelz id of this channel. 81 ID int64 82 // RefName is the human readable reference string of this channel. 83 RefName string 84 // ChannelData contains channel internal metric reported by the channel through 85 // ChannelzMetric(). 86 ChannelData *ChannelInternalMetric 87 // NestedChans tracks the nested channel type children of this channel in the format of 88 // a map from nested channel channelz id to corresponding reference string. 89 NestedChans map[int64]string 90 // SubChans tracks the subchannel type children of this channel in the format of a 91 // map from subchannel channelz id to corresponding reference string. 92 SubChans map[int64]string 93 // Sockets tracks the socket type children of this channel in the format of a map 94 // from socket channelz id to corresponding reference string. 95 // Note current grpc implementation doesn't allow channel having sockets directly, 96 // therefore, this is field is unused. 97 Sockets map[int64]string 98} 99 100// SubChannelMetric defines the info channelz provides for a specific SubChannel, 101// which includes ChannelInternalMetric and channelz-specific data, such as 102// channelz id, child list, etc. 103type SubChannelMetric struct { 104 // ID is the channelz id of this subchannel. 105 ID int64 106 // RefName is the human readable reference string of this subchannel. 107 RefName string 108 // ChannelData contains subchannel internal metric reported by the subchannel 109 // through ChannelzMetric(). 110 ChannelData *ChannelInternalMetric 111 // NestedChans tracks the nested channel type children of this subchannel in the format of 112 // a map from nested channel channelz id to corresponding reference string. 113 // Note current grpc implementation doesn't allow subchannel to have nested channels 114 // as children, therefore, this field is unused. 115 NestedChans map[int64]string 116 // SubChans tracks the subchannel type children of this subchannel in the format of a 117 // map from subchannel channelz id to corresponding reference string. 118 // Note current grpc implementation doesn't allow subchannel to have subchannels 119 // as children, therefore, this field is unused. 120 SubChans map[int64]string 121 // Sockets tracks the socket type children of this subchannel in the format of a map 122 // from socket channelz id to corresponding reference string. 123 Sockets map[int64]string 124} 125 126// ChannelInternalMetric defines the struct that the implementor of Channel interface 127// should return from ChannelzMetric(). 128type ChannelInternalMetric struct { 129 // current connectivity state of the channel. 130 State connectivity.State 131 // The target this channel originally tried to connect to. May be absent 132 Target string 133 // The number of calls started on the channel. 134 CallsStarted int64 135 // The number of calls that have completed with an OK status. 136 CallsSucceeded int64 137 // The number of calls that have a completed with a non-OK status. 138 CallsFailed int64 139 // The last time a call was started on the channel. 140 LastCallStartedTimestamp time.Time 141 //TODO: trace 142} 143 144// Channel is the interface that should be satisfied in order to be tracked by 145// channelz as Channel or SubChannel. 146type Channel interface { 147 ChannelzMetric() *ChannelInternalMetric 148} 149 150type channel struct { 151 refName string 152 c Channel 153 closeCalled bool 154 nestedChans map[int64]string 155 subChans map[int64]string 156 id int64 157 pid int64 158 cm *channelMap 159} 160 161func (c *channel) addChild(id int64, e entry) { 162 switch v := e.(type) { 163 case *subChannel: 164 c.subChans[id] = v.refName 165 case *channel: 166 c.nestedChans[id] = v.refName 167 default: 168 grpclog.Errorf("cannot add a child (id = %d) of type %T to a channel", id, e) 169 } 170} 171 172func (c *channel) deleteChild(id int64) { 173 delete(c.subChans, id) 174 delete(c.nestedChans, id) 175 c.deleteSelfIfReady() 176} 177 178func (c *channel) triggerDelete() { 179 c.closeCalled = true 180 c.deleteSelfIfReady() 181} 182 183func (c *channel) deleteSelfIfReady() { 184 if !c.closeCalled || len(c.subChans)+len(c.nestedChans) != 0 { 185 return 186 } 187 c.cm.deleteEntry(c.id) 188 // not top channel 189 if c.pid != 0 { 190 c.cm.findEntry(c.pid).deleteChild(c.id) 191 } 192} 193 194type subChannel struct { 195 refName string 196 c Channel 197 closeCalled bool 198 sockets map[int64]string 199 id int64 200 pid int64 201 cm *channelMap 202} 203 204func (sc *subChannel) addChild(id int64, e entry) { 205 if v, ok := e.(*normalSocket); ok { 206 sc.sockets[id] = v.refName 207 } else { 208 grpclog.Errorf("cannot add a child (id = %d) of type %T to a subChannel", id, e) 209 } 210} 211 212func (sc *subChannel) deleteChild(id int64) { 213 delete(sc.sockets, id) 214 sc.deleteSelfIfReady() 215} 216 217func (sc *subChannel) triggerDelete() { 218 sc.closeCalled = true 219 sc.deleteSelfIfReady() 220} 221 222func (sc *subChannel) deleteSelfIfReady() { 223 if !sc.closeCalled || len(sc.sockets) != 0 { 224 return 225 } 226 sc.cm.deleteEntry(sc.id) 227 sc.cm.findEntry(sc.pid).deleteChild(sc.id) 228} 229 230// SocketMetric defines the info channelz provides for a specific Socket, which 231// includes SocketInternalMetric and channelz-specific data, such as channelz id, etc. 232type SocketMetric struct { 233 // ID is the channelz id of this socket. 234 ID int64 235 // RefName is the human readable reference string of this socket. 236 RefName string 237 // SocketData contains socket internal metric reported by the socket through 238 // ChannelzMetric(). 239 SocketData *SocketInternalMetric 240} 241 242// SocketInternalMetric defines the struct that the implementor of Socket interface 243// should return from ChannelzMetric(). 244type SocketInternalMetric struct { 245 // The number of streams that have been started. 246 StreamsStarted int64 247 // The number of streams that have ended successfully: 248 // On client side, receiving frame with eos bit set. 249 // On server side, sending frame with eos bit set. 250 StreamsSucceeded int64 251 // The number of streams that have ended unsuccessfully: 252 // On client side, termination without receiving frame with eos bit set. 253 // On server side, termination without sending frame with eos bit set. 254 StreamsFailed int64 255 // The number of messages successfully sent on this socket. 256 MessagesSent int64 257 MessagesReceived int64 258 // The number of keep alives sent. This is typically implemented with HTTP/2 259 // ping messages. 260 KeepAlivesSent int64 261 // The last time a stream was created by this endpoint. Usually unset for 262 // servers. 263 LastLocalStreamCreatedTimestamp time.Time 264 // The last time a stream was created by the remote endpoint. Usually unset 265 // for clients. 266 LastRemoteStreamCreatedTimestamp time.Time 267 // The last time a message was sent by this endpoint. 268 LastMessageSentTimestamp time.Time 269 // The last time a message was received by this endpoint. 270 LastMessageReceivedTimestamp time.Time 271 // The amount of window, granted to the local endpoint by the remote endpoint. 272 // This may be slightly out of date due to network latency. This does NOT 273 // include stream level or TCP level flow control info. 274 LocalFlowControlWindow int64 275 // The amount of window, granted to the remote endpoint by the local endpoint. 276 // This may be slightly out of date due to network latency. This does NOT 277 // include stream level or TCP level flow control info. 278 RemoteFlowControlWindow int64 279 // The locally bound address. 280 LocalAddr net.Addr 281 // The remote bound address. May be absent. 282 RemoteAddr net.Addr 283 // Optional, represents the name of the remote endpoint, if different than 284 // the original target name. 285 RemoteName string 286 SocketOptions *SocketOptionData 287 Security credentials.ChannelzSecurityValue 288} 289 290// Socket is the interface that should be satisfied in order to be tracked by 291// channelz as Socket. 292type Socket interface { 293 ChannelzMetric() *SocketInternalMetric 294} 295 296type listenSocket struct { 297 refName string 298 s Socket 299 id int64 300 pid int64 301 cm *channelMap 302} 303 304func (ls *listenSocket) addChild(id int64, e entry) { 305 grpclog.Errorf("cannot add a child (id = %d) of type %T to a listen socket", id, e) 306} 307 308func (ls *listenSocket) deleteChild(id int64) { 309 grpclog.Errorf("cannot delete a child (id = %d) from a listen socket", id) 310} 311 312func (ls *listenSocket) triggerDelete() { 313 ls.cm.deleteEntry(ls.id) 314 ls.cm.findEntry(ls.pid).deleteChild(ls.id) 315} 316 317func (ls *listenSocket) deleteSelfIfReady() { 318 grpclog.Errorf("cannot call deleteSelfIfReady on a listen socket") 319} 320 321type normalSocket struct { 322 refName string 323 s Socket 324 id int64 325 pid int64 326 cm *channelMap 327} 328 329func (ns *normalSocket) addChild(id int64, e entry) { 330 grpclog.Errorf("cannot add a child (id = %d) of type %T to a normal socket", id, e) 331} 332 333func (ns *normalSocket) deleteChild(id int64) { 334 grpclog.Errorf("cannot delete a child (id = %d) from a normal socket", id) 335} 336 337func (ns *normalSocket) triggerDelete() { 338 ns.cm.deleteEntry(ns.id) 339 ns.cm.findEntry(ns.pid).deleteChild(ns.id) 340} 341 342func (ns *normalSocket) deleteSelfIfReady() { 343 grpclog.Errorf("cannot call deleteSelfIfReady on a normal socket") 344} 345 346// ServerMetric defines the info channelz provides for a specific Server, which 347// includes ServerInternalMetric and channelz-specific data, such as channelz id, 348// child list, etc. 349type ServerMetric struct { 350 // ID is the channelz id of this server. 351 ID int64 352 // RefName is the human readable reference string of this server. 353 RefName string 354 // ServerData contains server internal metric reported by the server through 355 // ChannelzMetric(). 356 ServerData *ServerInternalMetric 357 // ListenSockets tracks the listener socket type children of this server in the 358 // format of a map from socket channelz id to corresponding reference string. 359 ListenSockets map[int64]string 360} 361 362// ServerInternalMetric defines the struct that the implementor of Server interface 363// should return from ChannelzMetric(). 364type ServerInternalMetric struct { 365 // The number of incoming calls started on the server. 366 CallsStarted int64 367 // The number of incoming calls that have completed with an OK status. 368 CallsSucceeded int64 369 // The number of incoming calls that have a completed with a non-OK status. 370 CallsFailed int64 371 // The last time a call was started on the server. 372 LastCallStartedTimestamp time.Time 373 //TODO: trace 374} 375 376// Server is the interface to be satisfied in order to be tracked by channelz as 377// Server. 378type Server interface { 379 ChannelzMetric() *ServerInternalMetric 380} 381 382type server struct { 383 refName string 384 s Server 385 closeCalled bool 386 sockets map[int64]string 387 listenSockets map[int64]string 388 id int64 389 cm *channelMap 390} 391 392func (s *server) addChild(id int64, e entry) { 393 switch v := e.(type) { 394 case *normalSocket: 395 s.sockets[id] = v.refName 396 case *listenSocket: 397 s.listenSockets[id] = v.refName 398 default: 399 grpclog.Errorf("cannot add a child (id = %d) of type %T to a server", id, e) 400 } 401} 402 403func (s *server) deleteChild(id int64) { 404 delete(s.sockets, id) 405 delete(s.listenSockets, id) 406 s.deleteSelfIfReady() 407} 408 409func (s *server) triggerDelete() { 410 s.closeCalled = true 411 s.deleteSelfIfReady() 412} 413 414func (s *server) deleteSelfIfReady() { 415 if !s.closeCalled || len(s.sockets)+len(s.listenSockets) != 0 { 416 return 417 } 418 s.cm.deleteEntry(s.id) 419} 420