231 lines
6.9 KiB
Go
231 lines
6.9 KiB
Go
/*
|
|
*
|
|
* 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()
|
|
}
|