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
19package grpc
20
21import (
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.
33var EnableTracing bool
34
35// methodFamily returns the trace family for the given method.
36// It turns "/pkg.Service/GetFoo" into "pkg.Service".
37func 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.
48type 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.
57type 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.
68type 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.
76type 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
83func (f *firstLine) SetRemoteAddr(addr net.Addr) {
84 f.mu.Lock()
85 f.remoteAddr = addr
86 f.mu.Unlock()
87}
88
89func (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
109const truncateSize = 100
110
111func 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.
119type 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
125func (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
132type fmtStringer struct {
133 format string
134 a []any
135}
136
137func (f *fmtStringer) String() string {
138 return fmt.Sprintf(f.format, f.a...)
139}
140
141type stringer string
142
143func (s stringer) String() string { return string(s) }