google.golang.org/grpc@v1.72.2/internal/channelz/trace.go (about)

     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  }