trace.go raw

   1  /*
   2   *
   3   * Copyright 2015 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 grpc
  20  
  21  import (
  22  	"bytes"
  23  	"fmt"
  24  	"io"
  25  	"net"
  26  	"strings"
  27  	"sync"
  28  	"time"
  29  )
  30  
  31  // EnableTracing controls whether to trace RPCs using the golang.org/x/net/trace package.
  32  // This should only be set before any RPCs are sent or received by this program.
  33  var EnableTracing bool
  34  
  35  // methodFamily returns the trace family for the given method.
  36  // It turns "/pkg.Service/GetFoo" into "pkg.Service".
  37  func methodFamily(m string) string {
  38  	m = strings.TrimPrefix(m, "/") // remove leading slash
  39  	if i := strings.Index(m, "/"); i >= 0 {
  40  		m = m[:i] // remove everything from second slash
  41  	}
  42  	return m
  43  }
  44  
  45  // traceEventLog mirrors golang.org/x/net/trace.EventLog.
  46  //
  47  // It exists in order to avoid importing x/net/trace on grpcnotrace builds.
  48  type traceEventLog interface {
  49  	Printf(format string, a ...any)
  50  	Errorf(format string, a ...any)
  51  	Finish()
  52  }
  53  
  54  // traceLog mirrors golang.org/x/net/trace.Trace.
  55  //
  56  // It exists in order to avoid importing x/net/trace on grpcnotrace builds.
  57  type traceLog interface {
  58  	LazyLog(x fmt.Stringer, sensitive bool)
  59  	LazyPrintf(format string, a ...any)
  60  	SetError()
  61  	SetRecycler(f func(any))
  62  	SetTraceInfo(traceID, spanID uint64)
  63  	SetMaxEvents(m int)
  64  	Finish()
  65  }
  66  
  67  // traceInfo contains tracing information for an RPC.
  68  type traceInfo struct {
  69  	tr        traceLog
  70  	firstLine firstLine
  71  }
  72  
  73  // firstLine is the first line of an RPC trace.
  74  // It may be mutated after construction; remoteAddr specifically may change
  75  // during client-side use.
  76  type firstLine struct {
  77  	mu         sync.Mutex
  78  	client     bool // whether this is a client (outgoing) RPC
  79  	remoteAddr net.Addr
  80  	deadline   time.Duration // may be zero
  81  }
  82  
  83  func (f *firstLine) SetRemoteAddr(addr net.Addr) {
  84  	f.mu.Lock()
  85  	f.remoteAddr = addr
  86  	f.mu.Unlock()
  87  }
  88  
  89  func (f *firstLine) String() string {
  90  	f.mu.Lock()
  91  	defer f.mu.Unlock()
  92  
  93  	var line bytes.Buffer
  94  	io.WriteString(&line, "RPC: ")
  95  	if f.client {
  96  		io.WriteString(&line, "to")
  97  	} else {
  98  		io.WriteString(&line, "from")
  99  	}
 100  	fmt.Fprintf(&line, " %v deadline:", f.remoteAddr)
 101  	if f.deadline != 0 {
 102  		fmt.Fprint(&line, f.deadline)
 103  	} else {
 104  		io.WriteString(&line, "none")
 105  	}
 106  	return line.String()
 107  }
 108  
 109  const truncateSize = 100
 110  
 111  func truncate(x string, l int) string {
 112  	if l > len(x) {
 113  		return x
 114  	}
 115  	return x[:l]
 116  }
 117  
 118  // payload represents an RPC request or response payload.
 119  type payload struct {
 120  	sent bool // whether this is an outgoing payload
 121  	msg  any  // e.g. a proto.Message
 122  	// TODO(dsymonds): add stringifying info to codec, and limit how much we hold here?
 123  }
 124  
 125  func (p payload) String() string {
 126  	if p.sent {
 127  		return truncate(fmt.Sprintf("sent: %v", p.msg), truncateSize)
 128  	}
 129  	return truncate(fmt.Sprintf("recv: %v", p.msg), truncateSize)
 130  }
 131  
 132  type fmtStringer struct {
 133  	format string
 134  	a      []any
 135  }
 136  
 137  func (f *fmtStringer) String() string {
 138  	return fmt.Sprintf(f.format, f.a...)
 139  }
 140  
 141  type stringer string
 142  
 143  func (s stringer) String() string { return string(s) }
 144