2016-12-21 18:22:22 +00:00
|
|
|
package lfsapi
|
|
|
|
|
|
|
|
import (
|
2017-04-27 16:07:12 +00:00
|
|
|
"context"
|
2016-12-22 18:20:39 +00:00
|
|
|
"fmt"
|
|
|
|
"io"
|
2016-12-21 18:22:22 +00:00
|
|
|
"net/http"
|
2017-04-27 18:33:50 +00:00
|
|
|
"strings"
|
2017-04-27 18:57:26 +00:00
|
|
|
"sync"
|
2016-12-21 18:22:22 +00:00
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
type httpTransfer struct {
|
2017-04-27 19:12:43 +00:00
|
|
|
URL string
|
2017-04-27 20:02:59 +00:00
|
|
|
Method string
|
2017-04-27 18:33:50 +00:00
|
|
|
Key string
|
|
|
|
RequestBodySize int64
|
|
|
|
Start time.Time
|
2016-12-21 18:22:22 +00:00
|
|
|
}
|
|
|
|
|
2017-04-27 16:07:12 +00:00
|
|
|
type statsContextKey string
|
|
|
|
|
2017-04-27 18:33:50 +00:00
|
|
|
const transferKey = statsContextKey("transfer")
|
2017-04-27 16:07:12 +00:00
|
|
|
|
2017-04-27 17:15:13 +00:00
|
|
|
func (c *Client) LogHTTPStats(w io.WriteCloser) {
|
|
|
|
fmt.Fprintf(w, "concurrent=%d time=%d version=%s\n", c.ConcurrentTransfers, time.Now().Unix(), UserAgent)
|
2017-04-27 18:57:26 +00:00
|
|
|
c.httpLogger = newSyncLogger(w)
|
2017-04-27 17:15:13 +00:00
|
|
|
}
|
|
|
|
|
2016-12-22 18:20:39 +00:00
|
|
|
// LogStats is intended to be called after all HTTP operations for the
|
|
|
|
// commmand have finished. It dumps k/v logs, one line per httpTransfer into
|
|
|
|
// a log file with the current timestamp.
|
2017-04-27 17:15:13 +00:00
|
|
|
//
|
|
|
|
// DEPRECATED: Call LogHTTPStats() before the first HTTP request.
|
|
|
|
func (c *Client) LogStats(out io.Writer) {}
|
2016-12-22 18:20:39 +00:00
|
|
|
|
2017-04-27 16:07:12 +00:00
|
|
|
// LogRequest tells the client to log the request's stats to the http log
|
|
|
|
// after the response body has been read.
|
|
|
|
func (c *Client) LogRequest(r *http.Request, reqKey string) *http.Request {
|
2017-04-27 20:02:59 +00:00
|
|
|
ctx := context.WithValue(r.Context(), transferKey, &httpTransfer{
|
|
|
|
URL: strings.SplitN(r.URL.String(), "?", 2)[0],
|
|
|
|
Method: r.Method,
|
|
|
|
Key: reqKey,
|
2017-04-27 19:12:43 +00:00
|
|
|
})
|
2017-04-27 16:07:12 +00:00
|
|
|
return r.WithContext(ctx)
|
|
|
|
}
|
2016-12-21 18:22:22 +00:00
|
|
|
|
2017-04-27 16:07:12 +00:00
|
|
|
// LogResponse sends the current response stats to the http log.
|
|
|
|
//
|
|
|
|
// DEPRECATED: Use LogRequest() instead.
|
2017-04-27 16:47:10 +00:00
|
|
|
func (c *Client) LogResponse(key string, res *http.Response) {}
|
2016-12-21 18:22:22 +00:00
|
|
|
|
2017-04-27 18:57:26 +00:00
|
|
|
func newSyncLogger(w io.WriteCloser) *syncLogger {
|
|
|
|
ch := make(chan string, 100)
|
|
|
|
wg := &sync.WaitGroup{}
|
|
|
|
wg.Add(1)
|
|
|
|
|
|
|
|
go func(c chan string, w io.Writer, wg *sync.WaitGroup) {
|
|
|
|
for l := range c {
|
|
|
|
w.Write([]byte(l))
|
|
|
|
wg.Done()
|
|
|
|
}
|
|
|
|
}(ch, w, wg)
|
|
|
|
|
|
|
|
return &syncLogger{w: w, ch: ch, wg: wg}
|
|
|
|
}
|
|
|
|
|
|
|
|
type syncLogger struct {
|
|
|
|
w io.WriteCloser
|
|
|
|
ch chan string
|
|
|
|
wg *sync.WaitGroup
|
|
|
|
}
|
|
|
|
|
2017-04-27 19:12:43 +00:00
|
|
|
func (l *syncLogger) Log(req *http.Request, event, extra string) {
|
|
|
|
if l == nil {
|
|
|
|
return
|
2016-12-21 18:22:22 +00:00
|
|
|
}
|
2017-04-27 19:12:43 +00:00
|
|
|
|
2017-04-27 20:02:59 +00:00
|
|
|
if v := req.Context().Value(transferKey); v != nil {
|
|
|
|
l.LogTransfer(v.(*httpTransfer), event, extra)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *syncLogger) LogTransfer(t *httpTransfer, event, extra string) {
|
|
|
|
if l == nil {
|
2017-04-27 19:12:43 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
l.wg.Add(1)
|
2017-04-27 19:46:54 +00:00
|
|
|
l.ch <- fmt.Sprintf("key=%s event=%s url=%s method=%s %ssince=%d\n",
|
2017-04-27 19:12:43 +00:00
|
|
|
t.Key,
|
|
|
|
event,
|
|
|
|
t.URL,
|
2017-04-27 20:02:59 +00:00
|
|
|
t.Method,
|
2017-04-27 19:12:43 +00:00
|
|
|
extra,
|
|
|
|
time.Since(t.Start).Nanoseconds(),
|
|
|
|
)
|
2016-12-21 18:22:22 +00:00
|
|
|
}
|
2017-04-27 17:15:13 +00:00
|
|
|
|
2017-04-27 18:57:26 +00:00
|
|
|
func (l *syncLogger) Close() error {
|
|
|
|
if l == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
l.wg.Done()
|
|
|
|
l.wg.Wait()
|
|
|
|
return l.w.Close()
|
2017-04-27 17:15:13 +00:00
|
|
|
}
|