aboutsummaryrefslogtreecommitdiffstats
path: root/client/go/internal/vespa/document/stats.go
blob: e53d787cd01d64ea0e5c0e12c7b6c514f096ac1d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package document

import (
	"time"
)

// Status of a document operation.
type Status int

const (
	// StatusSuccess indicates a successful document operation.
	StatusSuccess Status = iota
	// StatusConditionNotMet indicates that the document operation itself was successful, but did not satisfy its
	// test-and-set condition.
	StatusConditionNotMet
	// StatusVespaFailure indicates that Vespa failed to process the document operation.
	StatusVespaFailure
	// StatusTransportFailure indicates that there was failure in the transport layer error while sending the document
	// operation to Vespa.
	StatusTransportFailure
)

// Result represents the result of a feeding operation.
type Result struct {
	Err        error
	Id         Id
	Trace      string
	Body       []byte
	Status     Status
	HTTPStatus int
	Latency    time.Duration
	BytesSent  int64
	BytesRecv  int64
}

func (r Result) Success() bool {
	return r.HTTPStatus/100 == 2 || r.HTTPStatus == 404 || r.HTTPStatus == 412
}

// Stats represents feeding operation statistics.
type Stats struct {
	ResponsesByCode map[int]int64
	Requests        int64
	Responses       int64
	Errors          int64
	Inflight        int64
	TotalLatency    time.Duration
	MinLatency      time.Duration
	MaxLatency      time.Duration
	BytesSent       int64
	BytesRecv       int64
}

// AvgLatency returns the average latency for a request.
func (s Stats) AvgLatency() time.Duration {
	requests := s.Requests
	if requests == 0 {
		requests = 1
	}
	return s.TotalLatency / time.Duration(requests)
}

func (s Stats) Successful() int64 {
	if s.ResponsesByCode == nil {
		return 0
	}
	return s.ResponsesByCode[200]
}

func (s Stats) Unsuccessful() int64 { return s.Requests - s.Successful() }

func (s Stats) Clone() Stats {
	if s.ResponsesByCode != nil {
		mapCopy := make(map[int]int64)
		for k, v := range s.ResponsesByCode {
			mapCopy[k] = v
		}
		s.ResponsesByCode = mapCopy
	}
	return s
}

// Add statistics from result to this.
func (s *Stats) Add(result Result) {
	s.Requests++
	if s.ResponsesByCode == nil {
		s.ResponsesByCode = make(map[int]int64)
	}
	if result.Err == nil {
		responsesByCode := s.ResponsesByCode[result.HTTPStatus]
		s.ResponsesByCode[result.HTTPStatus] = responsesByCode + 1
		s.Responses++
	} else {
		s.Errors++
	}
	s.TotalLatency += result.Latency
	if result.Latency < s.MinLatency || s.MinLatency == 0 {
		s.MinLatency = result.Latency
	}
	if result.Latency > s.MaxLatency {
		s.MaxLatency = result.Latency
	}
	s.BytesSent += result.BytesSent
	s.BytesRecv += result.BytesRecv
}