trace.go raw

   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
  20  
  21  import (
  22  	"fmt"
  23  	"sync"
  24  	"sync/atomic"
  25  	"time"
  26  
  27  	"google.golang.org/grpc/grpclog"
  28  )
  29  
  30  const (
  31  	defaultMaxTraceEntry int32 = 30
  32  )
  33  
  34  var maxTraceEntry = defaultMaxTraceEntry
  35  
  36  // SetMaxTraceEntry sets maximum number of trace entries per entity (i.e.
  37  // channel/subchannel).  Setting it to 0 will disable channel tracing.
  38  func SetMaxTraceEntry(i int32) {
  39  	atomic.StoreInt32(&maxTraceEntry, i)
  40  }
  41  
  42  // ResetMaxTraceEntryToDefault resets the maximum number of trace entries per
  43  // entity to default.
  44  func ResetMaxTraceEntryToDefault() {
  45  	atomic.StoreInt32(&maxTraceEntry, defaultMaxTraceEntry)
  46  }
  47  
  48  func getMaxTraceEntry() int {
  49  	i := atomic.LoadInt32(&maxTraceEntry)
  50  	return int(i)
  51  }
  52  
  53  // traceEvent is an internal representation of a single trace event
  54  type traceEvent struct {
  55  	// Desc is a simple description of the trace event.
  56  	Desc string
  57  	// Severity states the severity of this trace event.
  58  	Severity Severity
  59  	// Timestamp is the event time.
  60  	Timestamp time.Time
  61  	// RefID is the id of the entity that gets referenced in the event. RefID is 0 if no other entity is
  62  	// involved in this event.
  63  	// e.g. SubChannel (id: 4[]) Created. --> RefID = 4, RefName = "" (inside [])
  64  	RefID int64
  65  	// RefName is the reference name for the entity that gets referenced in the event.
  66  	RefName string
  67  	// RefType indicates the referenced entity type, i.e Channel or SubChannel.
  68  	RefType RefChannelType
  69  }
  70  
  71  // TraceEvent is what the caller of AddTraceEvent should provide to describe the
  72  // event to be added to the channel trace.
  73  //
  74  // The Parent field is optional. It is used for an event that will be recorded
  75  // in the entity's parent trace.
  76  type TraceEvent struct {
  77  	Desc     string
  78  	Severity Severity
  79  	Parent   *TraceEvent
  80  }
  81  
  82  // ChannelTrace provides tracing information for a channel.
  83  // It tracks various events and metadata related to the channel's lifecycle
  84  // and operations.
  85  type ChannelTrace struct {
  86  	cm          *channelMap
  87  	clearCalled bool
  88  	// The time when the trace was created.
  89  	CreationTime time.Time
  90  	// A counter for the number of events recorded in the
  91  	// trace.
  92  	EventNum int64
  93  	mu       sync.Mutex
  94  	// A slice of traceEvent pointers representing the events recorded for
  95  	// this channel.
  96  	Events []*traceEvent
  97  }
  98  
  99  func (c *ChannelTrace) copy() *ChannelTrace {
 100  	return &ChannelTrace{
 101  		CreationTime: c.CreationTime,
 102  		EventNum:     c.EventNum,
 103  		Events:       append(([]*traceEvent)(nil), c.Events...),
 104  	}
 105  }
 106  
 107  func (c *ChannelTrace) append(e *traceEvent) {
 108  	c.mu.Lock()
 109  	if len(c.Events) == getMaxTraceEntry() {
 110  		del := c.Events[0]
 111  		c.Events = c.Events[1:]
 112  		if del.RefID != 0 {
 113  			// start recursive cleanup in a goroutine to not block the call originated from grpc.
 114  			go func() {
 115  				// need to acquire c.cm.mu lock to call the unlocked attemptCleanup func.
 116  				c.cm.mu.Lock()
 117  				c.cm.decrTraceRefCount(del.RefID)
 118  				c.cm.mu.Unlock()
 119  			}()
 120  		}
 121  	}
 122  	e.Timestamp = time.Now()
 123  	c.Events = append(c.Events, e)
 124  	c.EventNum++
 125  	c.mu.Unlock()
 126  }
 127  
 128  func (c *ChannelTrace) clear() {
 129  	if c.clearCalled {
 130  		return
 131  	}
 132  	c.clearCalled = true
 133  	c.mu.Lock()
 134  	for _, e := range c.Events {
 135  		if e.RefID != 0 {
 136  			// caller should have already held the c.cm.mu lock.
 137  			c.cm.decrTraceRefCount(e.RefID)
 138  		}
 139  	}
 140  	c.mu.Unlock()
 141  }
 142  
 143  // Severity is the severity level of a trace event.
 144  // The canonical enumeration of all valid values is here:
 145  // https://github.com/grpc/grpc-proto/blob/9b13d199cc0d4703c7ea26c9c330ba695866eb23/grpc/channelz/v1/channelz.proto#L126.
 146  type Severity int
 147  
 148  const (
 149  	// CtUnknown indicates unknown severity of a trace event.
 150  	CtUnknown Severity = iota
 151  	// CtInfo indicates info level severity of a trace event.
 152  	CtInfo
 153  	// CtWarning indicates warning level severity of a trace event.
 154  	CtWarning
 155  	// CtError indicates error level severity of a trace event.
 156  	CtError
 157  )
 158  
 159  // RefChannelType is the type of the entity being referenced in a trace event.
 160  type RefChannelType int
 161  
 162  const (
 163  	// RefUnknown indicates an unknown entity type, the zero value for this type.
 164  	RefUnknown RefChannelType = iota
 165  	// RefChannel indicates the referenced entity is a Channel.
 166  	RefChannel
 167  	// RefSubChannel indicates the referenced entity is a SubChannel.
 168  	RefSubChannel
 169  	// RefServer indicates the referenced entity is a Server.
 170  	RefServer
 171  	// RefListenSocket indicates the referenced entity is a ListenSocket.
 172  	RefListenSocket
 173  	// RefNormalSocket indicates the referenced entity is a NormalSocket.
 174  	RefNormalSocket
 175  )
 176  
 177  var refChannelTypeToString = map[RefChannelType]string{
 178  	RefUnknown:      "Unknown",
 179  	RefChannel:      "Channel",
 180  	RefSubChannel:   "SubChannel",
 181  	RefServer:       "Server",
 182  	RefListenSocket: "ListenSocket",
 183  	RefNormalSocket: "NormalSocket",
 184  }
 185  
 186  // String returns a string representation of the RefChannelType
 187  func (r RefChannelType) String() string {
 188  	return refChannelTypeToString[r]
 189  }
 190  
 191  // AddTraceEvent adds trace related to the entity with specified id, using the
 192  // provided TraceEventDesc.
 193  //
 194  // If channelz is not turned ON, this will simply log the event descriptions.
 195  func AddTraceEvent(l grpclog.DepthLoggerV2, e Entity, depth int, desc *TraceEvent) {
 196  	// Log only the trace description associated with the bottom most entity.
 197  	d := fmt.Sprintf("[%s] %s", e, desc.Desc)
 198  	switch desc.Severity {
 199  	case CtUnknown, CtInfo:
 200  		l.InfoDepth(depth+1, d)
 201  	case CtWarning:
 202  		l.WarningDepth(depth+1, d)
 203  	case CtError:
 204  		l.ErrorDepth(depth+1, d)
 205  	}
 206  
 207  	if getMaxTraceEntry() == 0 {
 208  		return
 209  	}
 210  	if IsOn() {
 211  		db.traceEvent(e.id(), desc)
 212  	}
 213  }
 214