git-lfs/lfsapi/stats.go

109 lines
2.3 KiB
Go
Raw Normal View History

2016-12-21 18:22:22 +00:00
package lfsapi
import (
"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"
"sync"
2016-12-21 18:22:22 +00:00
"time"
)
type httpTransfer struct {
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
}
type statsContextKey string
2017-04-27 18:33:50 +00:00
const transferKey = statsContextKey("transfer")
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)
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
// 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,
})
return r.WithContext(ctx)
}
2016-12-21 18:22:22 +00:00
// LogResponse sends the current response stats to the http log.
//
// DEPRECATED: Use LogRequest() instead.
func (c *Client) LogResponse(key string, res *http.Response) {}
2016-12-21 18:22:22 +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
}
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 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 {
return
}
l.wg.Add(1)
l.ch <- fmt.Sprintf("key=%s event=%s url=%s method=%s %ssince=%d\n",
t.Key,
event,
t.URL,
2017-04-27 20:02:59 +00:00
t.Method,
extra,
time.Since(t.Start).Nanoseconds(),
)
2016-12-21 18:22:22 +00:00
}
2017-04-27 17:15:13 +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
}