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 // Package channelz defines internal APIs for enabling channelz service, entry 20 // registration/deletion, and accessing channelz data. It also defines channelz 21 // metric struct formats. 22 package channelz 23 24 import ( 25 "sync/atomic" 26 "time" 27 28 "google.golang.org/grpc/internal" 29 ) 30 31 var ( 32 // IDGen is the global channelz entity ID generator. It should not be used 33 // outside this package except by tests. 34 IDGen IDGenerator 35 36 db *channelMap = newChannelMap() 37 // EntriesPerPage defines the number of channelz entries to be shown on a web page. 38 EntriesPerPage = 50 39 curState int32 40 ) 41 42 // TurnOn turns on channelz data collection. 43 func TurnOn() { 44 atomic.StoreInt32(&curState, 1) 45 } 46 47 func init() { 48 internal.ChannelzTurnOffForTesting = func() { 49 atomic.StoreInt32(&curState, 0) 50 } 51 } 52 53 // IsOn returns whether channelz data collection is on. 54 func IsOn() bool { 55 return atomic.LoadInt32(&curState) == 1 56 } 57 58 // GetTopChannels returns a slice of top channel's ChannelMetric, along with a 59 // boolean indicating whether there's more top channels to be queried for. 60 // 61 // The arg id specifies that only top channel with id at or above it will be 62 // included in the result. The returned slice is up to a length of the arg 63 // maxResults or EntriesPerPage if maxResults is zero, and is sorted in ascending 64 // id order. 65 func GetTopChannels(id int64, maxResults int) ([]*Channel, bool) { 66 return db.getTopChannels(id, maxResults) 67 } 68 69 // GetServers returns a slice of server's ServerMetric, along with a 70 // boolean indicating whether there's more servers to be queried for. 71 // 72 // The arg id specifies that only server with id at or above it will be included 73 // in the result. The returned slice is up to a length of the arg maxResults or 74 // EntriesPerPage if maxResults is zero, and is sorted in ascending id order. 75 func GetServers(id int64, maxResults int) ([]*Server, bool) { 76 return db.getServers(id, maxResults) 77 } 78 79 // GetServerSockets returns a slice of server's (identified by id) normal socket's 80 // SocketMetrics, along with a boolean indicating whether there's more sockets to 81 // be queried for. 82 // 83 // The arg startID specifies that only sockets with id at or above it will be 84 // included in the result. The returned slice is up to a length of the arg maxResults 85 // or EntriesPerPage if maxResults is zero, and is sorted in ascending id order. 86 func GetServerSockets(id int64, startID int64, maxResults int) ([]*Socket, bool) { 87 return db.getServerSockets(id, startID, maxResults) 88 } 89 90 // GetChannel returns the Channel for the channel (identified by id). 91 func GetChannel(id int64) *Channel { 92 return db.getChannel(id) 93 } 94 95 // GetSubChannel returns the SubChannel for the subchannel (identified by id). 96 func GetSubChannel(id int64) *SubChannel { 97 return db.getSubChannel(id) 98 } 99 100 // GetSocket returns the Socket for the socket (identified by id). 101 func GetSocket(id int64) *Socket { 102 return db.getSocket(id) 103 } 104 105 // GetServer returns the ServerMetric for the server (identified by id). 106 func GetServer(id int64) *Server { 107 return db.getServer(id) 108 } 109 110 // RegisterChannel registers the given channel c in the channelz database with 111 // target as its target and reference name, and adds it to the child list of its 112 // parent. parent == nil means no parent. 113 // 114 // Returns a unique channelz identifier assigned to this channel. 115 // 116 // If channelz is not turned ON, the channelz database is not mutated. 117 func RegisterChannel(parent *Channel, target string) *Channel { 118 id := IDGen.genID() 119 120 if !IsOn() { 121 return &Channel{ID: id} 122 } 123 124 isTopChannel := parent == nil 125 126 cn := &Channel{ 127 ID: id, 128 RefName: target, 129 nestedChans: make(map[int64]string), 130 subChans: make(map[int64]string), 131 Parent: parent, 132 trace: &ChannelTrace{CreationTime: time.Now(), Events: make([]*traceEvent, 0, getMaxTraceEntry())}, 133 } 134 cn.ChannelMetrics.Target.Store(&target) 135 db.addChannel(id, cn, isTopChannel, cn.getParentID()) 136 return cn 137 } 138 139 // RegisterSubChannel registers the given subChannel c in the channelz database 140 // with ref as its reference name, and adds it to the child list of its parent 141 // (identified by pid). 142 // 143 // Returns a unique channelz identifier assigned to this subChannel. 144 // 145 // If channelz is not turned ON, the channelz database is not mutated. 146 func RegisterSubChannel(parent *Channel, ref string) *SubChannel { 147 id := IDGen.genID() 148 sc := &SubChannel{ 149 ID: id, 150 RefName: ref, 151 parent: parent, 152 } 153 154 if !IsOn() { 155 return sc 156 } 157 158 sc.sockets = make(map[int64]string) 159 sc.trace = &ChannelTrace{CreationTime: time.Now(), Events: make([]*traceEvent, 0, getMaxTraceEntry())} 160 db.addSubChannel(id, sc, parent.ID) 161 return sc 162 } 163 164 // RegisterServer registers the given server s in channelz database. It returns 165 // the unique channelz tracking id assigned to this server. 166 // 167 // If channelz is not turned ON, the channelz database is not mutated. 168 func RegisterServer(ref string) *Server { 169 id := IDGen.genID() 170 if !IsOn() { 171 return &Server{ID: id} 172 } 173 174 svr := &Server{ 175 RefName: ref, 176 sockets: make(map[int64]string), 177 listenSockets: make(map[int64]string), 178 ID: id, 179 } 180 db.addServer(id, svr) 181 return svr 182 } 183 184 // RegisterSocket registers the given normal socket s in channelz database 185 // with ref as its reference name, and adds it to the child list of its parent 186 // (identified by skt.Parent, which must be set). It returns the unique channelz 187 // tracking id assigned to this normal socket. 188 // 189 // If channelz is not turned ON, the channelz database is not mutated. 190 func RegisterSocket(skt *Socket) *Socket { 191 skt.ID = IDGen.genID() 192 if IsOn() { 193 db.addSocket(skt) 194 } 195 return skt 196 } 197 198 // RemoveEntry removes an entry with unique channelz tracking id to be id from 199 // channelz database. 200 // 201 // If channelz is not turned ON, this function is a no-op. 202 func RemoveEntry(id int64) { 203 if !IsOn() { 204 return 205 } 206 db.removeEntry(id) 207 } 208 209 // IDGenerator is an incrementing atomic that tracks IDs for channelz entities. 210 type IDGenerator struct { 211 id int64 212 } 213 214 // Reset resets the generated ID back to zero. Should only be used at 215 // initialization or by tests sensitive to the ID number. 216 func (i *IDGenerator) Reset() { 217 atomic.StoreInt64(&i.id, 0) 218 } 219 220 func (i *IDGenerator) genID() int64 { 221 return atomic.AddInt64(&i.id, 1) 222 } 223 224 // Identifier is an opaque channelz identifier used to expose channelz symbols 225 // outside of grpc. Currently only implemented by Channel since no other 226 // types require exposure outside grpc. 227 type Identifier interface { 228 Entity 229 channelzIdentifier() 230 } 231