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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
|
package unistat
import (
"encoding/json"
"errors"
"fmt"
"time"
)
// StructuredAggregation provides type safe API to create an Aggregation. For more
// information see: https://wiki.yandex-team.ru/golovan/aggregation-types/
type StructuredAggregation struct {
AggregationType AggregationType
Group AggregationRule
MetaGroup AggregationRule
Rollup AggregationRule
}
// Aggregation defines rules how to aggregate signal on each level. For more
// information see: https://wiki.yandex-team.ru/golovan/aggregation-types/
type Aggregation interface {
Suffix() string
}
const (
AggregationUnknown = "<unknown>"
)
// Suffix defines signal aggregation on each level:
// 1 - Signal type: absolute (A) or delta (D).
// 2 - Group aggregation.
// 3 - Meta-group aggregation type.
// 4 - Time aggregation for roll-up.
//
// Doc: https://doc.yandex-team.ru/Search/golovan-quickstart/concepts/signal-aggregation.html#agrr-levels
func (a StructuredAggregation) Suffix() string {
return fmt.Sprintf("%s%s%s%s", a.AggregationType, a.Group, a.MetaGroup, a.Rollup)
}
// Priority is used to order signals in unistat report.
// https://wiki.yandex-team.ru/golovan/stat-handle/#protokol
type Priority int
// AggregationType is Absolute or Delta.
type AggregationType int
// Value types
const (
Absolute AggregationType = iota // Absolute value. Use for gauges.
Delta // Delta value. Use for increasing counters.
)
func (v AggregationType) String() string {
switch v {
case Absolute:
return "a"
case Delta:
return "d"
default:
return AggregationUnknown
}
}
// AggregationRule defines aggregation rules:
//
// https://wiki.yandex-team.ru/golovan/aggregation-types/#algoritmyagregacii
type AggregationRule int
// Aggregation rules
const (
Hgram AggregationRule = iota // Hgram is histogram aggregation.
Max // Max value.
Min // Min value.
Sum // Sum with default 0.
SumNone // SumNone is sum with default None.
Last // Last value.
Average // Average value.
)
func (r AggregationRule) String() string {
switch r {
case Hgram:
return "h"
case Max:
return "x"
case Min:
return "n"
case Sum:
return "m"
case SumNone:
return "e"
case Last:
return "t"
case Average:
return "v"
default:
return AggregationUnknown
}
}
func (r *AggregationRule) UnmarshalText(source []byte) error {
text := string(source)
switch text {
case "h":
*r = Hgram
case "x":
*r = Max
case "n":
*r = Min
case "m":
*r = Sum
case "e":
*r = SumNone
case "t":
*r = Last
case "v":
*r = Average
default:
return fmt.Errorf("unknown aggregation rule '%s'", text)
}
return nil
}
// ErrDuplicate is raised on duplicate metric name registration.
var ErrDuplicate = errors.New("unistat: duplicate metric")
// Metric is interface that accepted by Registry.
type Metric interface {
Name() string
Priority() Priority
Aggregation() Aggregation
MarshalJSON() ([]byte, error)
}
// Updater is interface that wraps basic Update() method.
type Updater interface {
Update(value float64)
}
// Registry is interface for container that generates stat report
type Registry interface {
Register(metric Metric)
MarshalJSON() ([]byte, error)
}
var defaultRegistry = NewRegistry()
// Register metric in default registry.
func Register(metric Metric) {
defaultRegistry.Register(metric)
}
// MarshalJSON marshals default registry to JSON.
func MarshalJSON() ([]byte, error) {
return json.Marshal(defaultRegistry)
}
// MeasureMicrosecondsSince updates metric with duration that started
// at ts and ends now.
func MeasureMicrosecondsSince(m Updater, ts time.Time) {
measureMicrosecondsSince(time.Since, m, ts)
}
// For unittest
type timeSinceFunc func(t time.Time) time.Duration
func measureMicrosecondsSince(sinceFunc timeSinceFunc, m Updater, ts time.Time) {
dur := sinceFunc(ts)
m.Update(float64(dur / time.Microsecond)) // to microseconds
}
|