This repository has been archived by the owner on Nov 17, 2021. It is now read-only.
/
binding_fetcher.go
108 lines (90 loc) · 2.67 KB
/
binding_fetcher.go
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
106
107
108
package cups
import (
"code.cloudfoundry.org/loggregator-agent/pkg/metrics"
"math"
"net/url"
"sort"
"time"
"code.cloudfoundry.org/loggregator-agent/pkg/binding"
"code.cloudfoundry.org/loggregator-agent/pkg/egress/syslog"
)
// Metrics is the client used to expose gauge and counter metricsClient.
type Metrics interface {
NewGauge(name string, opts ...metrics.MetricOption) metrics.Gauge
NewCounter(name string, opts ...metrics.MetricOption) metrics.Counter
}
// Getter is configured to fetch HTTP responses
type Getter interface {
Get() ([]binding.Binding, error)
}
// BindingFetcher uses a Getter to fetch and decode Bindings
type BindingFetcher struct {
refreshCount metrics.Counter
maxLatency metrics.Gauge
limit int
getter Getter
}
// NewBindingFetcher returns a new BindingFetcher
func NewBindingFetcher(limit int, g Getter, m Metrics) *BindingFetcher {
refreshCount := m.NewCounter("binding_refresh_count")
maxLatency := m.NewGauge("latency_for_last_binding_refresh", metrics.WithMetricTags(map[string]string{"unit": "ms"}))
return &BindingFetcher{
limit: limit,
getter: g,
refreshCount: refreshCount,
maxLatency: maxLatency,
}
}
// FetchBindings reaches out to the syslog drain binding provider via the Getter and decodes
// the response. If it does not get a 200, it returns an error.
func (f *BindingFetcher) FetchBindings() ([]syslog.Binding, error) {
var latency int64
defer func() {
f.refreshCount.Add(1)
f.maxLatency.Set(toMilliseconds(latency))
}()
start := time.Now()
bindings, err := f.getter.Get()
if err != nil {
return nil, err
}
latency = time.Since(start).Nanoseconds()
syslogBindings := f.toSyslogBindings(bindings, f.limit)
return syslogBindings, nil
}
func (f *BindingFetcher) DrainLimit() int {
return f.limit
}
func (f *BindingFetcher) toSyslogBindings(bs []binding.Binding, perAppLimit int) []syslog.Binding {
var bindings []syslog.Binding
for _, b := range bs {
drains := b.Drains
sort.Strings(drains)
if perAppLimit < len(drains) {
drains = drains[:perAppLimit]
}
for _, d := range drains {
u, err := url.Parse(d)
if err != nil {
continue
}
binding := syslog.Binding{
AppId: b.AppID,
Hostname: b.Hostname,
Drain: u.String(),
}
bindings = append(bindings, binding)
}
}
return bindings
}
// toMilliseconds truncates the calculated milliseconds float to microsecond
// precision.
func toMilliseconds(num int64) float64 {
millis := float64(num) / float64(time.Millisecond)
microsPerMilli := 1000.0
return roundFloat64(millis*microsPerMilli) / microsPerMilli
}
func roundFloat64(num float64) float64 {
return float64(int(num + math.Copysign(0.5, num)))
}