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 }