1// Copyright 2018, OpenCensus Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package ochttp 16 17import ( 18 "crypto/tls" 19 "net/http" 20 "net/http/httptrace" 21 "strings" 22 23 "go.opencensus.io/trace" 24) 25 26type spanAnnotator struct { 27 sp *trace.Span 28} 29 30// TODO: Remove NewSpanAnnotator at the next release. 31 32// NewSpanAnnotator returns a httptrace.ClientTrace which annotates 33// all emitted httptrace events on the provided Span. 34// Deprecated: Use NewSpanAnnotatingClientTrace instead 35func NewSpanAnnotator(r *http.Request, s *trace.Span) *httptrace.ClientTrace { 36 return NewSpanAnnotatingClientTrace(r, s) 37} 38 39// NewSpanAnnotatingClientTrace returns a httptrace.ClientTrace which annotates 40// all emitted httptrace events on the provided Span. 41func NewSpanAnnotatingClientTrace(_ *http.Request, s *trace.Span) *httptrace.ClientTrace { 42 sa := spanAnnotator{sp: s} 43 44 return &httptrace.ClientTrace{ 45 GetConn: sa.getConn, 46 GotConn: sa.gotConn, 47 PutIdleConn: sa.putIdleConn, 48 GotFirstResponseByte: sa.gotFirstResponseByte, 49 Got100Continue: sa.got100Continue, 50 DNSStart: sa.dnsStart, 51 DNSDone: sa.dnsDone, 52 ConnectStart: sa.connectStart, 53 ConnectDone: sa.connectDone, 54 TLSHandshakeStart: sa.tlsHandshakeStart, 55 TLSHandshakeDone: sa.tlsHandshakeDone, 56 WroteHeaders: sa.wroteHeaders, 57 Wait100Continue: sa.wait100Continue, 58 WroteRequest: sa.wroteRequest, 59 } 60} 61 62func (s spanAnnotator) getConn(hostPort string) { 63 attrs := []trace.Attribute{ 64 trace.StringAttribute("httptrace.get_connection.host_port", hostPort), 65 } 66 s.sp.Annotate(attrs, "GetConn") 67} 68 69func (s spanAnnotator) gotConn(info httptrace.GotConnInfo) { 70 attrs := []trace.Attribute{ 71 trace.BoolAttribute("httptrace.got_connection.reused", info.Reused), 72 trace.BoolAttribute("httptrace.got_connection.was_idle", info.WasIdle), 73 } 74 if info.WasIdle { 75 attrs = append(attrs, 76 trace.StringAttribute("httptrace.got_connection.idle_time", info.IdleTime.String())) 77 } 78 s.sp.Annotate(attrs, "GotConn") 79} 80 81// PutIdleConn implements a httptrace.ClientTrace hook 82func (s spanAnnotator) putIdleConn(err error) { 83 var attrs []trace.Attribute 84 if err != nil { 85 attrs = append(attrs, 86 trace.StringAttribute("httptrace.put_idle_connection.error", err.Error())) 87 } 88 s.sp.Annotate(attrs, "PutIdleConn") 89} 90 91func (s spanAnnotator) gotFirstResponseByte() { 92 s.sp.Annotate(nil, "GotFirstResponseByte") 93} 94 95func (s spanAnnotator) got100Continue() { 96 s.sp.Annotate(nil, "Got100Continue") 97} 98 99func (s spanAnnotator) dnsStart(info httptrace.DNSStartInfo) { 100 attrs := []trace.Attribute{ 101 trace.StringAttribute("httptrace.dns_start.host", info.Host), 102 } 103 s.sp.Annotate(attrs, "DNSStart") 104} 105 106func (s spanAnnotator) dnsDone(info httptrace.DNSDoneInfo) { 107 var addrs []string 108 for _, addr := range info.Addrs { 109 addrs = append(addrs, addr.String()) 110 } 111 attrs := []trace.Attribute{ 112 trace.StringAttribute("httptrace.dns_done.addrs", strings.Join(addrs, " , ")), 113 } 114 if info.Err != nil { 115 attrs = append(attrs, 116 trace.StringAttribute("httptrace.dns_done.error", info.Err.Error())) 117 } 118 s.sp.Annotate(attrs, "DNSDone") 119} 120 121func (s spanAnnotator) connectStart(network, addr string) { 122 attrs := []trace.Attribute{ 123 trace.StringAttribute("httptrace.connect_start.network", network), 124 trace.StringAttribute("httptrace.connect_start.addr", addr), 125 } 126 s.sp.Annotate(attrs, "ConnectStart") 127} 128 129func (s spanAnnotator) connectDone(network, addr string, err error) { 130 attrs := []trace.Attribute{ 131 trace.StringAttribute("httptrace.connect_done.network", network), 132 trace.StringAttribute("httptrace.connect_done.addr", addr), 133 } 134 if err != nil { 135 attrs = append(attrs, 136 trace.StringAttribute("httptrace.connect_done.error", err.Error())) 137 } 138 s.sp.Annotate(attrs, "ConnectDone") 139} 140 141func (s spanAnnotator) tlsHandshakeStart() { 142 s.sp.Annotate(nil, "TLSHandshakeStart") 143} 144 145func (s spanAnnotator) tlsHandshakeDone(_ tls.ConnectionState, err error) { 146 var attrs []trace.Attribute 147 if err != nil { 148 attrs = append(attrs, 149 trace.StringAttribute("httptrace.tls_handshake_done.error", err.Error())) 150 } 151 s.sp.Annotate(attrs, "TLSHandshakeDone") 152} 153 154func (s spanAnnotator) wroteHeaders() { 155 s.sp.Annotate(nil, "WroteHeaders") 156} 157 158func (s spanAnnotator) wait100Continue() { 159 s.sp.Annotate(nil, "Wait100Continue") 160} 161 162func (s spanAnnotator) wroteRequest(info httptrace.WroteRequestInfo) { 163 var attrs []trace.Attribute 164 if info.Err != nil { 165 attrs = append(attrs, 166 trace.StringAttribute("httptrace.wrote_request.error", info.Err.Error())) 167 } 168 s.sp.Annotate(attrs, "WroteRequest") 169} 170