khenaidoo | 59ce9dd | 2019-11-11 13:05:32 -0500 | [diff] [blame] | 1 | // Copyright 2013 The Prometheus Authors |
| 2 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 3 | // you may not use this file except in compliance with the License. |
| 4 | // You may obtain a copy of the License at |
| 5 | // |
| 6 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 7 | // |
| 8 | // Unless required by applicable law or agreed to in writing, software |
| 9 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 11 | // See the License for the specific language governing permissions and |
| 12 | // limitations under the License. |
| 13 | |
| 14 | package model |
| 15 | |
| 16 | import ( |
| 17 | "encoding/json" |
| 18 | "fmt" |
| 19 | "math" |
| 20 | "sort" |
| 21 | "strconv" |
| 22 | "strings" |
| 23 | ) |
| 24 | |
| 25 | var ( |
| 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 | |
| 33 | // ZeroSample is the pseudo zero-value of Sample used to signal a |
| 34 | // non-existing sample. It is a Sample with timestamp Earliest, value 0.0, |
| 35 | // and metric nil. Note that the natural zero value of Sample has a timestamp |
| 36 | // of 0, which is possible to appear in a real Sample and thus not suitable |
| 37 | // to signal a non-existing Sample. |
| 38 | ZeroSample = Sample{Timestamp: Earliest} |
| 39 | ) |
| 40 | |
| 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. |
| 113 | type Sample struct { |
| 114 | Metric Metric `json:"metric"` |
| 115 | Value SampleValue `json:"value"` |
| 116 | Timestamp Time `json:"timestamp"` |
| 117 | } |
| 118 | |
| 119 | // Equal compares first the metrics, then the timestamp, then the value. The |
| 120 | // semantics of value equality is defined by SampleValue.Equal. |
| 121 | func (s *Sample) Equal(o *Sample) bool { |
| 122 | if s == o { |
| 123 | return true |
| 124 | } |
| 125 | |
| 126 | if !s.Metric.Equal(o.Metric) { |
| 127 | return false |
| 128 | } |
| 129 | if !s.Timestamp.Equal(o.Timestamp) { |
| 130 | return false |
| 131 | } |
| 132 | |
| 133 | return s.Value.Equal(o.Value) |
| 134 | } |
| 135 | |
| 136 | func (s Sample) String() string { |
| 137 | return fmt.Sprintf("%s => %s", s.Metric, SamplePair{ |
| 138 | Timestamp: s.Timestamp, |
| 139 | Value: s.Value, |
| 140 | }) |
| 141 | } |
| 142 | |
| 143 | // MarshalJSON implements json.Marshaler. |
| 144 | func (s Sample) MarshalJSON() ([]byte, error) { |
| 145 | v := struct { |
| 146 | Metric Metric `json:"metric"` |
| 147 | Value SamplePair `json:"value"` |
| 148 | }{ |
| 149 | Metric: s.Metric, |
| 150 | Value: SamplePair{ |
| 151 | Timestamp: s.Timestamp, |
| 152 | Value: s.Value, |
| 153 | }, |
| 154 | } |
| 155 | |
| 156 | return json.Marshal(&v) |
| 157 | } |
| 158 | |
| 159 | // UnmarshalJSON implements json.Unmarshaler. |
| 160 | func (s *Sample) UnmarshalJSON(b []byte) error { |
| 161 | v := struct { |
| 162 | Metric Metric `json:"metric"` |
| 163 | Value SamplePair `json:"value"` |
| 164 | }{ |
| 165 | Metric: s.Metric, |
| 166 | Value: SamplePair{ |
| 167 | Timestamp: s.Timestamp, |
| 168 | Value: s.Value, |
| 169 | }, |
| 170 | } |
| 171 | |
| 172 | if err := json.Unmarshal(b, &v); err != nil { |
| 173 | return err |
| 174 | } |
| 175 | |
| 176 | s.Metric = v.Metric |
| 177 | s.Timestamp = v.Value.Timestamp |
| 178 | s.Value = v.Value.Value |
| 179 | |
| 180 | return nil |
| 181 | } |
| 182 | |
| 183 | // Samples is a sortable Sample slice. It implements sort.Interface. |
| 184 | type Samples []*Sample |
| 185 | |
| 186 | func (s Samples) Len() int { |
| 187 | return len(s) |
| 188 | } |
| 189 | |
| 190 | // Less compares first the metrics, then the timestamp. |
| 191 | func (s Samples) Less(i, j int) bool { |
| 192 | switch { |
| 193 | case s[i].Metric.Before(s[j].Metric): |
| 194 | return true |
| 195 | case s[j].Metric.Before(s[i].Metric): |
| 196 | return false |
| 197 | case s[i].Timestamp.Before(s[j].Timestamp): |
| 198 | return true |
| 199 | default: |
| 200 | return false |
| 201 | } |
| 202 | } |
| 203 | |
| 204 | func (s Samples) Swap(i, j int) { |
| 205 | s[i], s[j] = s[j], s[i] |
| 206 | } |
| 207 | |
| 208 | // Equal compares two sets of samples and returns true if they are equal. |
| 209 | func (s Samples) Equal(o Samples) bool { |
| 210 | if len(s) != len(o) { |
| 211 | return false |
| 212 | } |
| 213 | |
| 214 | for i, sample := range s { |
| 215 | if !sample.Equal(o[i]) { |
| 216 | return false |
| 217 | } |
| 218 | } |
| 219 | return true |
| 220 | } |
| 221 | |
| 222 | // SampleStream is a stream of Values belonging to an attached COWMetric. |
| 223 | type SampleStream struct { |
| 224 | Metric Metric `json:"metric"` |
| 225 | Values []SamplePair `json:"values"` |
| 226 | } |
| 227 | |
| 228 | func (ss SampleStream) String() string { |
| 229 | vals := make([]string, len(ss.Values)) |
| 230 | for i, v := range ss.Values { |
| 231 | vals[i] = v.String() |
| 232 | } |
| 233 | return fmt.Sprintf("%s =>\n%s", ss.Metric, strings.Join(vals, "\n")) |
| 234 | } |
| 235 | |
| 236 | // Value is a generic interface for values resulting from a query evaluation. |
| 237 | type Value interface { |
| 238 | Type() ValueType |
| 239 | String() string |
| 240 | } |
| 241 | |
| 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 | } |
| 261 | |
| 262 | func (et *ValueType) UnmarshalJSON(b []byte) error { |
| 263 | var s string |
| 264 | if err := json.Unmarshal(b, &s); err != nil { |
| 265 | return err |
| 266 | } |
| 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 | } |
| 283 | |
| 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") |
| 298 | } |
| 299 | |
| 300 | // Scalar is a scalar value evaluated at the set timestamp. |
| 301 | type Scalar struct { |
| 302 | Value SampleValue `json:"value"` |
| 303 | Timestamp Time `json:"timestamp"` |
| 304 | } |
| 305 | |
| 306 | func (s Scalar) String() string { |
| 307 | return fmt.Sprintf("scalar: %v @[%v]", s.Value, s.Timestamp) |
| 308 | } |
| 309 | |
| 310 | // MarshalJSON implements json.Marshaler. |
| 311 | func (s Scalar) MarshalJSON() ([]byte, error) { |
| 312 | v := strconv.FormatFloat(float64(s.Value), 'f', -1, 64) |
| 313 | return json.Marshal([...]interface{}{s.Timestamp, string(v)}) |
| 314 | } |
| 315 | |
| 316 | // UnmarshalJSON implements json.Unmarshaler. |
| 317 | func (s *Scalar) UnmarshalJSON(b []byte) error { |
| 318 | var f string |
| 319 | v := [...]interface{}{&s.Timestamp, &f} |
| 320 | |
| 321 | if err := json.Unmarshal(b, &v); err != nil { |
| 322 | return err |
| 323 | } |
| 324 | |
| 325 | value, err := strconv.ParseFloat(f, 64) |
| 326 | if err != nil { |
| 327 | return fmt.Errorf("error parsing sample value: %s", err) |
| 328 | } |
| 329 | s.Value = SampleValue(value) |
| 330 | return nil |
| 331 | } |
| 332 | |
| 333 | // String is a string value evaluated at the set timestamp. |
| 334 | type String struct { |
| 335 | Value string `json:"value"` |
| 336 | Timestamp Time `json:"timestamp"` |
| 337 | } |
| 338 | |
| 339 | func (s *String) String() string { |
| 340 | return s.Value |
| 341 | } |
| 342 | |
| 343 | // MarshalJSON implements json.Marshaler. |
| 344 | func (s String) MarshalJSON() ([]byte, error) { |
| 345 | return json.Marshal([]interface{}{s.Timestamp, s.Value}) |
| 346 | } |
| 347 | |
| 348 | // UnmarshalJSON implements json.Unmarshaler. |
| 349 | func (s *String) UnmarshalJSON(b []byte) error { |
| 350 | v := [...]interface{}{&s.Timestamp, &s.Value} |
| 351 | return json.Unmarshal(b, &v) |
| 352 | } |
| 353 | |
| 354 | // Vector is basically only an alias for Samples, but the |
| 355 | // contract is that in a Vector, all Samples have the same timestamp. |
| 356 | type Vector []*Sample |
| 357 | |
| 358 | func (vec Vector) String() string { |
| 359 | entries := make([]string, len(vec)) |
| 360 | for i, s := range vec { |
| 361 | entries[i] = s.String() |
| 362 | } |
| 363 | return strings.Join(entries, "\n") |
| 364 | } |
| 365 | |
| 366 | func (vec Vector) Len() int { return len(vec) } |
| 367 | func (vec Vector) Swap(i, j int) { vec[i], vec[j] = vec[j], vec[i] } |
| 368 | |
| 369 | // Less compares first the metrics, then the timestamp. |
| 370 | func (vec Vector) Less(i, j int) bool { |
| 371 | switch { |
| 372 | case vec[i].Metric.Before(vec[j].Metric): |
| 373 | return true |
| 374 | case vec[j].Metric.Before(vec[i].Metric): |
| 375 | return false |
| 376 | case vec[i].Timestamp.Before(vec[j].Timestamp): |
| 377 | return true |
| 378 | default: |
| 379 | return false |
| 380 | } |
| 381 | } |
| 382 | |
| 383 | // Equal compares two sets of samples and returns true if they are equal. |
| 384 | func (vec Vector) Equal(o Vector) bool { |
| 385 | if len(vec) != len(o) { |
| 386 | return false |
| 387 | } |
| 388 | |
| 389 | for i, sample := range vec { |
| 390 | if !sample.Equal(o[i]) { |
| 391 | return false |
| 392 | } |
| 393 | } |
| 394 | return true |
| 395 | } |
| 396 | |
| 397 | // Matrix is a list of time series. |
| 398 | type Matrix []*SampleStream |
| 399 | |
| 400 | func (m Matrix) Len() int { return len(m) } |
| 401 | func (m Matrix) Less(i, j int) bool { return m[i].Metric.Before(m[j].Metric) } |
| 402 | func (m Matrix) Swap(i, j int) { m[i], m[j] = m[j], m[i] } |
| 403 | |
| 404 | func (mat Matrix) String() string { |
| 405 | matCp := make(Matrix, len(mat)) |
| 406 | copy(matCp, mat) |
| 407 | sort.Sort(matCp) |
| 408 | |
| 409 | strs := make([]string, len(matCp)) |
| 410 | |
| 411 | for i, ss := range matCp { |
| 412 | strs[i] = ss.String() |
| 413 | } |
| 414 | |
| 415 | return strings.Join(strs, "\n") |
| 416 | } |