mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-03 19:12:25 -06:00 
			
		
		
		
	
		
			
	
	
		
			205 lines
		
	
	
	
		
			5.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			205 lines
		
	
	
	
		
			5.5 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
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import (
							 | 
						||
| 
								 | 
							
									"fmt"
							 | 
						||
| 
								 | 
							
									"sync"
							 | 
						||
| 
								 | 
							
									"sync/atomic"
							 | 
						||
| 
								 | 
							
									"time"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									"google.golang.org/grpc/grpclog"
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const (
							 | 
						||
| 
								 | 
							
									defaultMaxTraceEntry int32 = 30
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var maxTraceEntry = defaultMaxTraceEntry
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// SetMaxTraceEntry sets maximum number of trace entries per entity (i.e.
							 | 
						||
| 
								 | 
							
								// channel/subchannel).  Setting it to 0 will disable channel tracing.
							 | 
						||
| 
								 | 
							
								func SetMaxTraceEntry(i int32) {
							 | 
						||
| 
								 | 
							
									atomic.StoreInt32(&maxTraceEntry, i)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// ResetMaxTraceEntryToDefault resets the maximum number of trace entries per
							 | 
						||
| 
								 | 
							
								// entity to default.
							 | 
						||
| 
								 | 
							
								func ResetMaxTraceEntryToDefault() {
							 | 
						||
| 
								 | 
							
									atomic.StoreInt32(&maxTraceEntry, defaultMaxTraceEntry)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func getMaxTraceEntry() int {
							 | 
						||
| 
								 | 
							
									i := atomic.LoadInt32(&maxTraceEntry)
							 | 
						||
| 
								 | 
							
									return int(i)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// traceEvent is an internal representation of a single trace event
							 | 
						||
| 
								 | 
							
								type traceEvent struct {
							 | 
						||
| 
								 | 
							
									// Desc is a simple description of the trace event.
							 | 
						||
| 
								 | 
							
									Desc string
							 | 
						||
| 
								 | 
							
									// Severity states the severity of this trace event.
							 | 
						||
| 
								 | 
							
									Severity Severity
							 | 
						||
| 
								 | 
							
									// Timestamp is the event time.
							 | 
						||
| 
								 | 
							
									Timestamp time.Time
							 | 
						||
| 
								 | 
							
									// RefID is the id of the entity that gets referenced in the event. RefID is 0 if no other entity is
							 | 
						||
| 
								 | 
							
									// involved in this event.
							 | 
						||
| 
								 | 
							
									// e.g. SubChannel (id: 4[]) Created. --> RefID = 4, RefName = "" (inside [])
							 | 
						||
| 
								 | 
							
									RefID int64
							 | 
						||
| 
								 | 
							
									// RefName is the reference name for the entity that gets referenced in the event.
							 | 
						||
| 
								 | 
							
									RefName string
							 | 
						||
| 
								 | 
							
									// RefType indicates the referenced entity type, i.e Channel or SubChannel.
							 | 
						||
| 
								 | 
							
									RefType RefChannelType
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// TraceEvent is what the caller of AddTraceEvent should provide to describe the
							 | 
						||
| 
								 | 
							
								// event to be added to the channel trace.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// The Parent field is optional. It is used for an event that will be recorded
							 | 
						||
| 
								 | 
							
								// in the entity's parent trace.
							 | 
						||
| 
								 | 
							
								type TraceEvent struct {
							 | 
						||
| 
								 | 
							
									Desc     string
							 | 
						||
| 
								 | 
							
									Severity Severity
							 | 
						||
| 
								 | 
							
									Parent   *TraceEvent
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type ChannelTrace struct {
							 | 
						||
| 
								 | 
							
									cm           *channelMap
							 | 
						||
| 
								 | 
							
									clearCalled  bool
							 | 
						||
| 
								 | 
							
									CreationTime time.Time
							 | 
						||
| 
								 | 
							
									EventNum     int64
							 | 
						||
| 
								 | 
							
									mu           sync.Mutex
							 | 
						||
| 
								 | 
							
									Events       []*traceEvent
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (c *ChannelTrace) copy() *ChannelTrace {
							 | 
						||
| 
								 | 
							
									return &ChannelTrace{
							 | 
						||
| 
								 | 
							
										CreationTime: c.CreationTime,
							 | 
						||
| 
								 | 
							
										EventNum:     c.EventNum,
							 | 
						||
| 
								 | 
							
										Events:       append(([]*traceEvent)(nil), c.Events...),
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (c *ChannelTrace) append(e *traceEvent) {
							 | 
						||
| 
								 | 
							
									c.mu.Lock()
							 | 
						||
| 
								 | 
							
									if len(c.Events) == getMaxTraceEntry() {
							 | 
						||
| 
								 | 
							
										del := c.Events[0]
							 | 
						||
| 
								 | 
							
										c.Events = c.Events[1:]
							 | 
						||
| 
								 | 
							
										if del.RefID != 0 {
							 | 
						||
| 
								 | 
							
											// start recursive cleanup in a goroutine to not block the call originated from grpc.
							 | 
						||
| 
								 | 
							
											go func() {
							 | 
						||
| 
								 | 
							
												// need to acquire c.cm.mu lock to call the unlocked attemptCleanup func.
							 | 
						||
| 
								 | 
							
												c.cm.mu.Lock()
							 | 
						||
| 
								 | 
							
												c.cm.decrTraceRefCount(del.RefID)
							 | 
						||
| 
								 | 
							
												c.cm.mu.Unlock()
							 | 
						||
| 
								 | 
							
											}()
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									e.Timestamp = time.Now()
							 | 
						||
| 
								 | 
							
									c.Events = append(c.Events, e)
							 | 
						||
| 
								 | 
							
									c.EventNum++
							 | 
						||
| 
								 | 
							
									c.mu.Unlock()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (c *ChannelTrace) clear() {
							 | 
						||
| 
								 | 
							
									if c.clearCalled {
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									c.clearCalled = true
							 | 
						||
| 
								 | 
							
									c.mu.Lock()
							 | 
						||
| 
								 | 
							
									for _, e := range c.Events {
							 | 
						||
| 
								 | 
							
										if e.RefID != 0 {
							 | 
						||
| 
								 | 
							
											// caller should have already held the c.cm.mu lock.
							 | 
						||
| 
								 | 
							
											c.cm.decrTraceRefCount(e.RefID)
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									c.mu.Unlock()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Severity is the severity level of a trace event.
							 | 
						||
| 
								 | 
							
								// The canonical enumeration of all valid values is here:
							 | 
						||
| 
								 | 
							
								// https://github.com/grpc/grpc-proto/blob/9b13d199cc0d4703c7ea26c9c330ba695866eb23/grpc/channelz/v1/channelz.proto#L126.
							 | 
						||
| 
								 | 
							
								type Severity int
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const (
							 | 
						||
| 
								 | 
							
									// CtUnknown indicates unknown severity of a trace event.
							 | 
						||
| 
								 | 
							
									CtUnknown Severity = iota
							 | 
						||
| 
								 | 
							
									// CtInfo indicates info level severity of a trace event.
							 | 
						||
| 
								 | 
							
									CtInfo
							 | 
						||
| 
								 | 
							
									// CtWarning indicates warning level severity of a trace event.
							 | 
						||
| 
								 | 
							
									CtWarning
							 | 
						||
| 
								 | 
							
									// CtError indicates error level severity of a trace event.
							 | 
						||
| 
								 | 
							
									CtError
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// RefChannelType is the type of the entity being referenced in a trace event.
							 | 
						||
| 
								 | 
							
								type RefChannelType int
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const (
							 | 
						||
| 
								 | 
							
									// RefUnknown indicates an unknown entity type, the zero value for this type.
							 | 
						||
| 
								 | 
							
									RefUnknown RefChannelType = iota
							 | 
						||
| 
								 | 
							
									// RefChannel indicates the referenced entity is a Channel.
							 | 
						||
| 
								 | 
							
									RefChannel
							 | 
						||
| 
								 | 
							
									// RefSubChannel indicates the referenced entity is a SubChannel.
							 | 
						||
| 
								 | 
							
									RefSubChannel
							 | 
						||
| 
								 | 
							
									// RefServer indicates the referenced entity is a Server.
							 | 
						||
| 
								 | 
							
									RefServer
							 | 
						||
| 
								 | 
							
									// RefListenSocket indicates the referenced entity is a ListenSocket.
							 | 
						||
| 
								 | 
							
									RefListenSocket
							 | 
						||
| 
								 | 
							
									// RefNormalSocket indicates the referenced entity is a NormalSocket.
							 | 
						||
| 
								 | 
							
									RefNormalSocket
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var refChannelTypeToString = map[RefChannelType]string{
							 | 
						||
| 
								 | 
							
									RefUnknown:      "Unknown",
							 | 
						||
| 
								 | 
							
									RefChannel:      "Channel",
							 | 
						||
| 
								 | 
							
									RefSubChannel:   "SubChannel",
							 | 
						||
| 
								 | 
							
									RefServer:       "Server",
							 | 
						||
| 
								 | 
							
									RefListenSocket: "ListenSocket",
							 | 
						||
| 
								 | 
							
									RefNormalSocket: "NormalSocket",
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (r RefChannelType) String() string {
							 | 
						||
| 
								 | 
							
									return refChannelTypeToString[r]
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// AddTraceEvent adds trace related to the entity with specified id, using the
							 | 
						||
| 
								 | 
							
								// provided TraceEventDesc.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// If channelz is not turned ON, this will simply log the event descriptions.
							 | 
						||
| 
								 | 
							
								func AddTraceEvent(l grpclog.DepthLoggerV2, e Entity, depth int, desc *TraceEvent) {
							 | 
						||
| 
								 | 
							
									// Log only the trace description associated with the bottom most entity.
							 | 
						||
| 
								 | 
							
									d := fmt.Sprintf("[%s]%s", e, desc.Desc)
							 | 
						||
| 
								 | 
							
									switch desc.Severity {
							 | 
						||
| 
								 | 
							
									case CtUnknown, CtInfo:
							 | 
						||
| 
								 | 
							
										l.InfoDepth(depth+1, d)
							 | 
						||
| 
								 | 
							
									case CtWarning:
							 | 
						||
| 
								 | 
							
										l.WarningDepth(depth+1, d)
							 | 
						||
| 
								 | 
							
									case CtError:
							 | 
						||
| 
								 | 
							
										l.ErrorDepth(depth+1, d)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if getMaxTraceEntry() == 0 {
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if IsOn() {
							 | 
						||
| 
								 | 
							
										db.traceEvent(e.id(), desc)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 |