@@ -16,20 +16,12 @@ package model
1616import (
1717 "encoding/json"
1818 "fmt"
19- "math"
2019 "sort"
2120 "strconv"
2221 "strings"
2322)
2423
2524var (
26- // ZeroSamplePair is the pseudo zero-value of SamplePair used to signal a
27- // non-existing sample pair. It is a SamplePair with timestamp Earliest and
28- // value 0.0. Note that the natural zero value of SamplePair has a timestamp
29- // of 0, which is possible to appear in a real SamplePair and thus not
30- // suitable to signal a non-existing SamplePair.
31- ZeroSamplePair = SamplePair {Timestamp : Earliest }
32-
3325 // ZeroSample is the pseudo zero-value of Sample used to signal a
3426 // non-existing sample. It is a Sample with timestamp Earliest, value 0.0,
3527 // and metric nil. Note that the natural zero value of Sample has a timestamp
@@ -38,82 +30,14 @@ var (
3830 ZeroSample = Sample {Timestamp : Earliest }
3931)
4032
41- // A SampleValue is a representation of a value for a given sample at a given
42- // time.
43- type SampleValue float64
44-
45- // MarshalJSON implements json.Marshaler.
46- func (v SampleValue ) MarshalJSON () ([]byte , error ) {
47- return json .Marshal (v .String ())
48- }
49-
50- // UnmarshalJSON implements json.Unmarshaler.
51- func (v * SampleValue ) UnmarshalJSON (b []byte ) error {
52- if len (b ) < 2 || b [0 ] != '"' || b [len (b )- 1 ] != '"' {
53- return fmt .Errorf ("sample value must be a quoted string" )
54- }
55- f , err := strconv .ParseFloat (string (b [1 :len (b )- 1 ]), 64 )
56- if err != nil {
57- return err
58- }
59- * v = SampleValue (f )
60- return nil
61- }
62-
63- // Equal returns true if the value of v and o is equal or if both are NaN. Note
64- // that v==o is false if both are NaN. If you want the conventional float
65- // behavior, use == to compare two SampleValues.
66- func (v SampleValue ) Equal (o SampleValue ) bool {
67- if v == o {
68- return true
69- }
70- return math .IsNaN (float64 (v )) && math .IsNaN (float64 (o ))
71- }
72-
73- func (v SampleValue ) String () string {
74- return strconv .FormatFloat (float64 (v ), 'f' , - 1 , 64 )
75- }
76-
77- // SamplePair pairs a SampleValue with a Timestamp.
78- type SamplePair struct {
79- Timestamp Time
80- Value SampleValue
81- }
82-
83- // MarshalJSON implements json.Marshaler.
84- func (s SamplePair ) MarshalJSON () ([]byte , error ) {
85- t , err := json .Marshal (s .Timestamp )
86- if err != nil {
87- return nil , err
88- }
89- v , err := json .Marshal (s .Value )
90- if err != nil {
91- return nil , err
92- }
93- return []byte (fmt .Sprintf ("[%s,%s]" , t , v )), nil
94- }
95-
96- // UnmarshalJSON implements json.Unmarshaler.
97- func (s * SamplePair ) UnmarshalJSON (b []byte ) error {
98- v := [... ]json.Unmarshaler {& s .Timestamp , & s .Value }
99- return json .Unmarshal (b , & v )
100- }
101-
102- // Equal returns true if this SamplePair and o have equal Values and equal
103- // Timestamps. The semantics of Value equality is defined by SampleValue.Equal.
104- func (s * SamplePair ) Equal (o * SamplePair ) bool {
105- return s == o || (s .Value .Equal (o .Value ) && s .Timestamp .Equal (o .Timestamp ))
106- }
107-
108- func (s SamplePair ) String () string {
109- return fmt .Sprintf ("%s @[%s]" , s .Value , s .Timestamp )
110- }
111-
112- // Sample is a sample pair associated with a metric.
33+ // Sample is a sample pair associated with a metric. A single sample must either
34+ // define Value or Histogram but not both. Histogram == nil implies the Value
35+ // field is used, otherwise it should be ignored.
11336type Sample struct {
114- Metric Metric `json:"metric"`
115- Value SampleValue `json:"value"`
116- Timestamp Time `json:"timestamp"`
37+ Metric Metric `json:"metric"`
38+ Value SampleValue `json:"value"`
39+ Timestamp Time `json:"timestamp"`
40+ Histogram * SampleHistogram `json:"histogram"`
11741}
11842
11943// Equal compares first the metrics, then the timestamp, then the value. The
@@ -129,11 +53,19 @@ func (s *Sample) Equal(o *Sample) bool {
12953 if ! s .Timestamp .Equal (o .Timestamp ) {
13054 return false
13155 }
132-
56+ if s .Histogram != nil {
57+ return s .Histogram .Equal (o .Histogram )
58+ }
13359 return s .Value .Equal (o .Value )
13460}
13561
13662func (s Sample ) String () string {
63+ if s .Histogram != nil {
64+ return fmt .Sprintf ("%s => %s" , s .Metric , SampleHistogramPair {
65+ Timestamp : s .Timestamp ,
66+ Histogram : * s .Histogram ,
67+ })
68+ }
13769 return fmt .Sprintf ("%s => %s" , s .Metric , SamplePair {
13870 Timestamp : s .Timestamp ,
13971 Value : s .Value ,
@@ -142,6 +74,19 @@ func (s Sample) String() string {
14274
14375// MarshalJSON implements json.Marshaler.
14476func (s Sample ) MarshalJSON () ([]byte , error ) {
77+ if s .Histogram != nil {
78+ v := struct {
79+ Metric Metric `json:"metric"`
80+ Histogram SampleHistogramPair `json:"histogram"`
81+ }{
82+ Metric : s .Metric ,
83+ Histogram : SampleHistogramPair {
84+ Timestamp : s .Timestamp ,
85+ Histogram : * s .Histogram ,
86+ },
87+ }
88+ return json .Marshal (& v )
89+ }
14590 v := struct {
14691 Metric Metric `json:"metric"`
14792 Value SamplePair `json:"value"`
@@ -152,30 +97,57 @@ func (s Sample) MarshalJSON() ([]byte, error) {
15297 Value : s .Value ,
15398 },
15499 }
155-
156100 return json .Marshal (& v )
157101}
158102
103+ type sampleHistogramPairPtr struct {
104+ Timestamp Time
105+ Histogram * SampleHistogram
106+ }
107+
108+ func (s * sampleHistogramPairPtr ) UnmarshalJSON (buf []byte ) error {
109+ tmp := []interface {}{& s .Timestamp , & s .Histogram }
110+ wantLen := len (tmp )
111+ if err := json .Unmarshal (buf , & tmp ); err != nil {
112+ return err
113+ }
114+ if gotLen := len (tmp ); gotLen != wantLen {
115+ return fmt .Errorf ("wrong number of fields: %d != %d" , gotLen , wantLen )
116+ }
117+ return nil
118+ }
119+
159120// UnmarshalJSON implements json.Unmarshaler.
121+ // TODO: simplify and remove the need for both sampleHistogramPairPtr and SampleHistogramPair
160122func (s * Sample ) UnmarshalJSON (b []byte ) error {
161123 v := struct {
162- Metric Metric `json:"metric"`
163- Value SamplePair `json:"value"`
124+ Metric Metric `json:"metric"`
125+ Value SamplePair `json:"value"`
126+ Histogram sampleHistogramPairPtr `json:"histogram"`
164127 }{
165128 Metric : s .Metric ,
166129 Value : SamplePair {
167130 Timestamp : s .Timestamp ,
168131 Value : s .Value ,
169132 },
133+ Histogram : sampleHistogramPairPtr {
134+ Timestamp : s .Timestamp ,
135+ Histogram : s .Histogram ,
136+ },
170137 }
171138
172139 if err := json .Unmarshal (b , & v ); err != nil {
173140 return err
174141 }
175142
176143 s .Metric = v .Metric
177- s .Timestamp = v .Value .Timestamp
178- s .Value = v .Value .Value
144+ if v .Histogram .Histogram != nil {
145+ s .Timestamp = v .Histogram .Timestamp
146+ s .Histogram = v .Histogram .Histogram
147+ } else {
148+ s .Timestamp = v .Value .Timestamp
149+ s .Value = v .Value .Value
150+ }
179151
180152 return nil
181153}
@@ -221,80 +193,76 @@ func (s Samples) Equal(o Samples) bool {
221193
222194// SampleStream is a stream of Values belonging to an attached COWMetric.
223195type SampleStream struct {
224- Metric Metric `json:"metric"`
225- Values []SamplePair `json:"values"`
196+ Metric Metric `json:"metric"`
197+ Values []SamplePair `json:"values"`
198+ Histograms []SampleHistogramPair `json:"histograms"`
226199}
227200
228201func (ss SampleStream ) String () string {
229- vals := make ([]string , len (ss .Values ))
202+ valuesLength := len (ss .Values )
203+ vals := make ([]string , valuesLength + len (ss .Histograms ))
230204 for i , v := range ss .Values {
231205 vals [i ] = v .String ()
232206 }
207+ for i , v := range ss .Histograms {
208+ vals [i + valuesLength ] = v .String ()
209+ }
233210 return fmt .Sprintf ("%s =>\n %s" , ss .Metric , strings .Join (vals , "\n " ))
234211}
235212
236- // Value is a generic interface for values resulting from a query evaluation.
237- type Value interface {
238- Type () ValueType
239- String () string
213+ func (ss SampleStream ) MarshalJSON () ([]byte , error ) {
214+ if len (ss .Histograms ) > 0 && len (ss .Values ) > 0 {
215+ v := struct {
216+ Metric Metric `json:"metric"`
217+ Values []SamplePair `json:"values"`
218+ Histograms []SampleHistogramPair `json:"histograms"`
219+ }{
220+ Metric : ss .Metric ,
221+ Values : ss .Values ,
222+ Histograms : ss .Histograms ,
223+ }
224+ return json .Marshal (& v )
225+ } else if len (ss .Histograms ) > 0 {
226+ v := struct {
227+ Metric Metric `json:"metric"`
228+ Histograms []SampleHistogramPair `json:"histograms"`
229+ }{
230+ Metric : ss .Metric ,
231+ Histograms : ss .Histograms ,
232+ }
233+ return json .Marshal (& v )
234+ } else {
235+ v := struct {
236+ Metric Metric `json:"metric"`
237+ Values []SamplePair `json:"values"`
238+ }{
239+ Metric : ss .Metric ,
240+ Values : ss .Values ,
241+ }
242+ return json .Marshal (& v )
243+ }
240244}
241245
242- func (Matrix ) Type () ValueType { return ValMatrix }
243- func (Vector ) Type () ValueType { return ValVector }
244- func (* Scalar ) Type () ValueType { return ValScalar }
245- func (* String ) Type () ValueType { return ValString }
246-
247- type ValueType int
248-
249- const (
250- ValNone ValueType = iota
251- ValScalar
252- ValVector
253- ValMatrix
254- ValString
255- )
256-
257- // MarshalJSON implements json.Marshaler.
258- func (et ValueType ) MarshalJSON () ([]byte , error ) {
259- return json .Marshal (et .String ())
260- }
246+ func (ss * SampleStream ) UnmarshalJSON (b []byte ) error {
247+ v := struct {
248+ Metric Metric `json:"metric"`
249+ Values []SamplePair `json:"values"`
250+ Histograms []SampleHistogramPair `json:"histograms"`
251+ }{
252+ Metric : ss .Metric ,
253+ Values : ss .Values ,
254+ Histograms : ss .Histograms ,
255+ }
261256
262- func (et * ValueType ) UnmarshalJSON (b []byte ) error {
263- var s string
264- if err := json .Unmarshal (b , & s ); err != nil {
257+ if err := json .Unmarshal (b , & v ); err != nil {
265258 return err
266259 }
267- switch s {
268- case "<ValNone>" :
269- * et = ValNone
270- case "scalar" :
271- * et = ValScalar
272- case "vector" :
273- * et = ValVector
274- case "matrix" :
275- * et = ValMatrix
276- case "string" :
277- * et = ValString
278- default :
279- return fmt .Errorf ("unknown value type %q" , s )
280- }
281- return nil
282- }
283260
284- func (e ValueType ) String () string {
285- switch e {
286- case ValNone :
287- return "<ValNone>"
288- case ValScalar :
289- return "scalar"
290- case ValVector :
291- return "vector"
292- case ValMatrix :
293- return "matrix"
294- case ValString :
295- return "string"
296- }
297- panic ("ValueType.String: unhandled value type" )
261+ ss .Metric = v .Metric
262+ ss .Values = v .Values
263+ ss .Histograms = v .Histograms
264+
265+ return nil
298266}
299267
300268// Scalar is a scalar value evaluated at the set timestamp.
0 commit comments