5
5
"crypto/tls"
6
6
"net/http"
7
7
"net/http/httptrace"
8
+ "sync/atomic"
8
9
"time"
9
10
10
11
"github.com/aws/smithy-go/metrics"
@@ -42,10 +43,10 @@ type timedClientDo struct {
42
43
}
43
44
44
45
func (c * timedClientDo ) Do (r * http.Request ) (* http.Response , error ) {
45
- c .hm .doStart = now ()
46
+ c .hm .doStart . Store ( now () )
46
47
resp , err := c .ClientDo .Do (r )
47
48
48
- c .hm .DoRequestDuration .Record (r .Context (), elapsed ( c .hm .doStart ))
49
+ c .hm .DoRequestDuration .Record (r .Context (), c .hm .doStart . Elapsed ( ))
49
50
return resp , err
50
51
}
51
52
@@ -58,10 +59,10 @@ type httpMetrics struct {
58
59
DoRequestDuration metrics.Float64Histogram // client.http.do_request_duration
59
60
TimeToFirstByte metrics.Float64Histogram // client.http.time_to_first_byte
60
61
61
- doStart time. Time
62
- dnsStart time. Time
63
- connectStart time. Time
64
- tlsStart time. Time
62
+ doStart safeTime
63
+ dnsStart safeTime
64
+ connectStart safeTime
65
+ tlsStart safeTime
65
66
}
66
67
67
68
func newHTTPMetrics (meter metrics.Meter ) (* httpMetrics , error ) {
@@ -115,15 +116,15 @@ func newHTTPMetrics(meter metrics.Meter) (*httpMetrics, error) {
115
116
}
116
117
117
118
func (m * httpMetrics ) DNSStart (httptrace.DNSStartInfo ) {
118
- m .dnsStart = now ()
119
+ m .dnsStart . Store ( now () )
119
120
}
120
121
121
122
func (m * httpMetrics ) ConnectStart (string , string ) {
122
- m .connectStart = now ()
123
+ m .connectStart . Store ( now () )
123
124
}
124
125
125
126
func (m * httpMetrics ) TLSHandshakeStart () {
126
- m .tlsStart = now ()
127
+ m .tlsStart . Store ( now () )
127
128
}
128
129
129
130
func (m * httpMetrics ) GotConn (ctx context.Context ) func (httptrace.GotConnInfo ) {
@@ -140,25 +141,25 @@ func (m *httpMetrics) PutIdleConn(ctx context.Context) func(error) {
140
141
141
142
func (m * httpMetrics ) DNSDone (ctx context.Context ) func (httptrace.DNSDoneInfo ) {
142
143
return func (httptrace.DNSDoneInfo ) {
143
- m .DNSLookupDuration .Record (ctx , elapsed ( m .dnsStart ))
144
+ m .DNSLookupDuration .Record (ctx , m .dnsStart . Elapsed ( ))
144
145
}
145
146
}
146
147
147
148
func (m * httpMetrics ) ConnectDone (ctx context.Context ) func (string , string , error ) {
148
149
return func (string , string , error ) {
149
- m .ConnectDuration .Record (ctx , elapsed ( m .connectStart ))
150
+ m .ConnectDuration .Record (ctx , m .connectStart . Elapsed ( ))
150
151
}
151
152
}
152
153
153
154
func (m * httpMetrics ) TLSHandshakeDone (ctx context.Context ) func (tls.ConnectionState , error ) {
154
155
return func (tls.ConnectionState , error ) {
155
- m .TLSHandshakeDuration .Record (ctx , elapsed ( m .tlsStart ))
156
+ m .TLSHandshakeDuration .Record (ctx , m .tlsStart . Elapsed ( ))
156
157
}
157
158
}
158
159
159
160
func (m * httpMetrics ) GotFirstResponseByte (ctx context.Context ) func () {
160
161
return func () {
161
- m .TimeToFirstByte .Record (ctx , elapsed ( m .doStart ))
162
+ m .TimeToFirstByte .Record (ctx , m .doStart . Elapsed ( ))
162
163
}
163
164
}
164
165
@@ -177,8 +178,21 @@ func (m *httpMetrics) addConnIdle(ctx context.Context, incr int64) {
177
178
})
178
179
}
179
180
180
- func elapsed (start time.Time ) float64 {
181
+ type safeTime struct {
182
+ atomic.Value // time.Time
183
+ }
184
+
185
+ func (st * safeTime ) Store (v time.Time ) {
186
+ st .Value .Store (v )
187
+ }
188
+
189
+ func (st * safeTime ) Load () time.Time {
190
+ t , _ := st .Value .Load ().(time.Time )
191
+ return t
192
+ }
193
+
194
+ func (st * safeTime ) Elapsed () float64 {
181
195
end := now ()
182
- elapsed := end .Sub (start )
196
+ elapsed := end .Sub (st . Load () )
183
197
return float64 (elapsed ) / 1e9
184
198
}
0 commit comments