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	"time"
28
29	"golang.org/x/net/trace"
30)
31
32// EnableTracing controls whether to trace RPCs using the golang.org/x/net/trace package.
33// This should only be set before any RPCs are sent or received by this program.
34var EnableTracing bool
35
36// methodFamily returns the trace family for the given method.
37// It turns "/pkg.Service/GetFoo" into "pkg.Service".
38func methodFamily(m string) string {
39	m = strings.TrimPrefix(m, "/") // remove leading slash
40	if i := strings.Index(m, "/"); i >= 0 {
41		m = m[:i] // remove everything from second slash
42	}
43	if i := strings.LastIndex(m, "."); i >= 0 {
44		m = m[i+1:] // cut down to last dotted component
45	}
46	return m
47}
48
49// traceInfo contains tracing information for an RPC.
50type traceInfo struct {
51	tr        trace.Trace
52	firstLine firstLine
53}
54
55// firstLine is the first line of an RPC trace.
56type firstLine struct {
57	client     bool // whether this is a client (outgoing) RPC
58	remoteAddr net.Addr
59	deadline   time.Duration // may be zero
60}
61
62func (f *firstLine) String() string {
63	var line bytes.Buffer
64	io.WriteString(&line, "RPC: ")
65	if f.client {
66		io.WriteString(&line, "to")
67	} else {
68		io.WriteString(&line, "from")
69	}
70	fmt.Fprintf(&line, " %v deadline:", f.remoteAddr)
71	if f.deadline != 0 {
72		fmt.Fprint(&line, f.deadline)
73	} else {
74		io.WriteString(&line, "none")
75	}
76	return line.String()
77}
78
79const truncateSize = 100
80
81func truncate(x string, l int) string {
82	if l > len(x) {
83		return x
84	}
85	return x[:l]
86}
87
88// payload represents an RPC request or response payload.
89type payload struct {
90	sent bool        // whether this is an outgoing payload
91	msg  interface{} // e.g. a proto.Message
92	// TODO(dsymonds): add stringifying info to codec, and limit how much we hold here?
93}
94
95func (p payload) String() string {
96	if p.sent {
97		return truncate(fmt.Sprintf("sent: %v", p.msg), truncateSize)
98	}
99	return truncate(fmt.Sprintf("recv: %v", p.msg), truncateSize)
100}
101
102type fmtStringer struct {
103	format string
104	a      []interface{}
105}
106
107func (f *fmtStringer) String() string {
108	return fmt.Sprintf(f.format, f.a...)
109}
110
111type stringer string
112
113func (s stringer) String() string { return string(s) }
114