/* * * Copyright 2018 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ // Package channelz defines internal APIs for enabling channelz service, entry // registration/deletion, and accessing channelz data. It also defines channelz // metric struct formats. package channelz import ( "sync/atomic" "time" "google.golang.org/grpc/internal" ) var ( // IDGen is the global channelz entity ID generator. It should not be used // outside this package except by tests. IDGen IDGenerator db *channelMap = newChannelMap() // EntriesPerPage defines the number of channelz entries to be shown on a web page. EntriesPerPage = 50 curState int32 ) // TurnOn turns on channelz data collection. func TurnOn() { atomic.StoreInt32(&curState, 1) } func init() { internal.ChannelzTurnOffForTesting = func() { atomic.StoreInt32(&curState, 0) } } // IsOn returns whether channelz data collection is on. func IsOn() bool { return atomic.LoadInt32(&curState) == 1 } // GetTopChannels returns a slice of top channel's ChannelMetric, along with a // boolean indicating whether there's more top channels to be queried for. // // The arg id specifies that only top channel with id at or above it will be // included in the result. The returned slice is up to a length of the arg // maxResults or EntriesPerPage if maxResults is zero, and is sorted in ascending // id order. func GetTopChannels(id int64, maxResults int) ([]*Channel, bool) { return db.getTopChannels(id, maxResults) } // GetServers returns a slice of server's ServerMetric, along with a // boolean indicating whether there's more servers to be queried for. // // The arg id specifies that only server with id at or above it will be included // in the result. The returned slice is up to a length of the arg maxResults or // EntriesPerPage if maxResults is zero, and is sorted in ascending id order. func GetServers(id int64, maxResults int) ([]*Server, bool) { return db.getServers(id, maxResults) } // GetServerSockets returns a slice of server's (identified by id) normal socket's // SocketMetrics, along with a boolean indicating whether there's more sockets to // be queried for. // // The arg startID specifies that only sockets with id at or above it will be // included in the result. The returned slice is up to a length of the arg maxResults // or EntriesPerPage if maxResults is zero, and is sorted in ascending id order. func GetServerSockets(id int64, startID int64, maxResults int) ([]*Socket, bool) { return db.getServerSockets(id, startID, maxResults) } // GetChannel returns the Channel for the channel (identified by id). func GetChannel(id int64) *Channel { return db.getChannel(id) } // GetSubChannel returns the SubChannel for the subchannel (identified by id). func GetSubChannel(id int64) *SubChannel { return db.getSubChannel(id) } // GetSocket returns the Socket for the socket (identified by id). func GetSocket(id int64) *Socket { return db.getSocket(id) } // GetServer returns the ServerMetric for the server (identified by id). func GetServer(id int64) *Server { return db.getServer(id) } // RegisterChannel registers the given channel c in the channelz database with // target as its target and reference name, and adds it to the child list of its // parent. parent == nil means no parent. // // Returns a unique channelz identifier assigned to this channel. // // If channelz is not turned ON, the channelz database is not mutated. func RegisterChannel(parent *Channel, target string) *Channel { id := IDGen.genID() if !IsOn() { return &Channel{ID: id} } isTopChannel := parent == nil cn := &Channel{ ID: id, RefName: target, nestedChans: make(map[int64]string), subChans: make(map[int64]string), Parent: parent, trace: &ChannelTrace{CreationTime: time.Now(), Events: make([]*traceEvent, 0, getMaxTraceEntry())}, } cn.ChannelMetrics.Target.Store(&target) db.addChannel(id, cn, isTopChannel, cn.getParentID()) return cn } // RegisterSubChannel registers the given subChannel c in the channelz database // with ref as its reference name, and adds it to the child list of its parent // (identified by pid). // // Returns a unique channelz identifier assigned to this subChannel. // // If channelz is not turned ON, the channelz database is not mutated. func RegisterSubChannel(parent *Channel, ref string) *SubChannel { id := IDGen.genID() sc := &SubChannel{ ID: id, RefName: ref, parent: parent, } if !IsOn() { return sc } sc.sockets = make(map[int64]string) sc.trace = &ChannelTrace{CreationTime: time.Now(), Events: make([]*traceEvent, 0, getMaxTraceEntry())} db.addSubChannel(id, sc, parent.ID) return sc } // RegisterServer registers the given server s in channelz database. It returns // the unique channelz tracking id assigned to this server. // // If channelz is not turned ON, the channelz database is not mutated. func RegisterServer(ref string) *Server { id := IDGen.genID() if !IsOn() { return &Server{ID: id} } svr := &Server{ RefName: ref, sockets: make(map[int64]string), listenSockets: make(map[int64]string), ID: id, } db.addServer(id, svr) return svr } // RegisterSocket registers the given normal socket s in channelz database // with ref as its reference name, and adds it to the child list of its parent // (identified by skt.Parent, which must be set). It returns the unique channelz // tracking id assigned to this normal socket. // // If channelz is not turned ON, the channelz database is not mutated. func RegisterSocket(skt *Socket) *Socket { skt.ID = IDGen.genID() if IsOn() { db.addSocket(skt) } return skt } // RemoveEntry removes an entry with unique channelz tracking id to be id from // channelz database. // // If channelz is not turned ON, this function is a no-op. func RemoveEntry(id int64) { if !IsOn() { return } db.removeEntry(id) } // IDGenerator is an incrementing atomic that tracks IDs for channelz entities. type IDGenerator struct { id int64 } // Reset resets the generated ID back to zero. Should only be used at // initialization or by tests sensitive to the ID number. func (i *IDGenerator) Reset() { atomic.StoreInt64(&i.id, 0) } func (i *IDGenerator) genID() int64 { return atomic.AddInt64(&i.id, 1) } // Identifier is an opaque channelz identifier used to expose channelz symbols // outside of grpc. Currently only implemented by Channel since no other // types require exposure outside grpc. type Identifier interface { Entity channelzIdentifier() }