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 type ChannelTrace struct { 83 cm *channelMap 84 clearCalled bool 85 CreationTime time.Time 86 EventNum int64 87 mu sync.Mutex 88 Events []*traceEvent 89 } 90 91 func (c *ChannelTrace) copy() *ChannelTrace { 92 return &ChannelTrace{ 93 CreationTime: c.CreationTime, 94 EventNum: c.EventNum, 95 Events: append(([]*traceEvent)(nil), c.Events...), 96 } 97 } 98 99 func (c *ChannelTrace) append(e *traceEvent) { 100 c.mu.Lock() 101 if len(c.Events) == getMaxTraceEntry() { 102 del := c.Events[0] 103 c.Events = c.Events[1:] 104 if del.RefID != 0 { 105 // start recursive cleanup in a goroutine to not block the call originated from grpc. 106 go func() { 107 // need to acquire c.cm.mu lock to call the unlocked attemptCleanup func. 108 c.cm.mu.Lock() 109 c.cm.decrTraceRefCount(del.RefID) 110 c.cm.mu.Unlock() 111 }() 112 } 113 } 114 e.Timestamp = time.Now() 115 c.Events = append(c.Events, e) 116 c.EventNum++ 117 c.mu.Unlock() 118 } 119 120 func (c *ChannelTrace) clear() { 121 if c.clearCalled { 122 return 123 } 124 c.clearCalled = true 125 c.mu.Lock() 126 for _, e := range c.Events { 127 if e.RefID != 0 { 128 // caller should have already held the c.cm.mu lock. 129 c.cm.decrTraceRefCount(e.RefID) 130 } 131 } 132 c.mu.Unlock() 133 } 134 135 // Severity is the severity level of a trace event. 136 // The canonical enumeration of all valid values is here: 137 // https://github.com/grpc/grpc-proto/blob/9b13d199cc0d4703c7ea26c9c330ba695866eb23/grpc/channelz/v1/channelz.proto#L126. 138 type Severity int 139 140 const ( 141 // CtUnknown indicates unknown severity of a trace event. 142 CtUnknown Severity = iota 143 // CtInfo indicates info level severity of a trace event. 144 CtInfo 145 // CtWarning indicates warning level severity of a trace event. 146 CtWarning 147 // CtError indicates error level severity of a trace event. 148 CtError 149 ) 150 151 // RefChannelType is the type of the entity being referenced in a trace event. 152 type RefChannelType int 153 154 const ( 155 // RefUnknown indicates an unknown entity type, the zero value for this type. 156 RefUnknown RefChannelType = iota 157 // RefChannel indicates the referenced entity is a Channel. 158 RefChannel 159 // RefSubChannel indicates the referenced entity is a SubChannel. 160 RefSubChannel 161 // RefServer indicates the referenced entity is a Server. 162 RefServer 163 // RefListenSocket indicates the referenced entity is a ListenSocket. 164 RefListenSocket 165 // RefNormalSocket indicates the referenced entity is a NormalSocket. 166 RefNormalSocket 167 ) 168 169 var refChannelTypeToString = map[RefChannelType]string{ 170 RefUnknown: "Unknown", 171 RefChannel: "Channel", 172 RefSubChannel: "SubChannel", 173 RefServer: "Server", 174 RefListenSocket: "ListenSocket", 175 RefNormalSocket: "NormalSocket", 176 } 177 178 func (r RefChannelType) String() string { 179 return refChannelTypeToString[r] 180 } 181 182 // AddTraceEvent adds trace related to the entity with specified id, using the 183 // provided TraceEventDesc. 184 // 185 // If channelz is not turned ON, this will simply log the event descriptions. 186 func AddTraceEvent(l grpclog.DepthLoggerV2, e Entity, depth int, desc *TraceEvent) { 187 // Log only the trace description associated with the bottom most entity. 188 d := fmt.Sprintf("[%s]%s", e, desc.Desc) 189 switch desc.Severity { 190 case CtUnknown, CtInfo: 191 l.InfoDepth(depth+1, d) 192 case CtWarning: 193 l.WarningDepth(depth+1, d) 194 case CtError: 195 l.ErrorDepth(depth+1, d) 196 } 197 198 if getMaxTraceEntry() == 0 { 199 return 200 } 201 if IsOn() { 202 db.traceEvent(e.id(), desc) 203 } 204 } 205