Alerting: support alerting on data.Frame (that can be time series) (#22812)

data.Frame (that can be series) are converted to as tsdb.TimeSeriesSlice - so new backend plugins can be shimmed into existing alerting

use sdk v0.31.0
This commit is contained in:
Kyle Brandt authored and GitHub committed 2020-03-18 10:30:07 -04:00
1 parent 44b7f3ea1c
commit 0e09a3fe15
15 files changed
+808 -55

No files matched your search

+221 -1
View File
@@ -7,6 +7,7 @@ import (
"fmt"
"math"
"sort"
"strconv"
"strings"
"time"
@@ -344,6 +345,151 @@ func (f *Field) Nullable() bool {
return f.Type().Nullable()
}
// FloatAt returns a float64 at the specified index idx.
// It will panic if idx is out of range.
// If the Field type is numeric and the value at idx is nil, NaN is returned. Precision may be lost on large numbers.
// If the Field type is a bool then 0 is return if false or nil, and 1 if true.
// If the Field type is time.Time, then the millisecond epoch representation of the time
// is returned, or NaN is the value is nil.
// If the Field type is a string, then strconv.ParseFloat is called on it and will return
// an error if ParseFloat errors. If the value is nil, NaN is returned.
func (f *Field) FloatAt(idx int) (float64, error) {
switch f.Type() {
case FieldTypeInt8:
return float64(f.At(idx).(int8)), nil
case FieldTypeNullableInt8:
iv := f.At(idx).(*int8)
if iv == nil {
return math.NaN(), nil
}
return float64(*iv), nil
case FieldTypeInt16:
return float64(f.At(idx).(int16)), nil
case FieldTypeNullableInt16:
iv := f.At(idx).(*int16)
if iv == nil {
return math.NaN(), nil
}
return float64(*iv), nil
case FieldTypeInt32:
return float64(f.At(idx).(int32)), nil
case FieldTypeNullableInt32:
iv := f.At(idx).(*int32)
if iv == nil {
return math.NaN(), nil
}
return float64(*iv), nil
case FieldTypeInt64:
return float64(f.At(idx).(int64)), nil
case FieldTypeNullableInt64:
iv := f.At(idx).(*int64)
if iv == nil {
return math.NaN(), nil
}
return float64(*iv), nil
case FieldTypeUint8:
return float64(f.At(idx).(uint8)), nil
case FieldTypeNullableUint8:
uiv := f.At(idx).(*uint8)
if uiv == nil {
return math.NaN(), nil
}
return float64(*uiv), nil
case FieldTypeUint16:
return float64(f.At(idx).(uint16)), nil
case FieldTypeNullableUint16:
uiv := f.At(idx).(*uint16)
if uiv == nil {
return math.NaN(), nil
}
return float64(*uiv), nil
case FieldTypeUint32:
return float64(f.At(idx).(uint32)), nil
case FieldTypeNullableUint32:
uiv := f.At(idx).(*uint32)
if uiv == nil {
return math.NaN(), nil
}
return float64(*uiv), nil
// TODO: third param for loss of precision?
// Maybe something in math/big can help with this (also see https://github.com/golang/go/issues/29463).
case FieldTypeUint64:
return float64(f.At(idx).(uint64)), nil
case FieldTypeNullableUint64:
uiv := f.At(idx).(*uint64)
if uiv == nil {
return math.NaN(), nil
}
return float64(*uiv), nil
case FieldTypeFloat32:
return float64(f.At(idx).(float32)), nil
case FieldTypeNullableFloat32:
fv := f.At(idx).(*float32)
if fv == nil {
return math.NaN(), nil
}
return float64(*fv), nil
case FieldTypeFloat64:
return f.At(idx).(float64), nil
case FieldTypeNullableFloat64:
fv := f.At(idx).(*float64)
if fv == nil {
return math.NaN(), nil
}
return *fv, nil
case FieldTypeString:
s := f.At(idx).(string)
ft, err := strconv.ParseFloat(s, 64)
if err != nil {
return 0, err
}
return ft, nil
case FieldTypeNullableString:
s := f.At(idx).(*string)
if s == nil {
return math.NaN(), nil
}
ft, err := strconv.ParseFloat(*s, 64)
if err != nil {
return 0, err
}
return ft, nil
case FieldTypeBool:
if f.At(idx).(bool) {
return 1, nil
}
return 0, nil
case FieldTypeNullableBool:
b := f.At(idx).(*bool)
if b == nil || !*b {
return 0, nil
}
return 1, nil
case FieldTypeTime:
return float64(f.At(idx).(time.Time).UnixNano() / int64(time.Millisecond)), nil
case FieldTypeNullableTime:
t := f.At(idx).(*time.Time)
if t == nil {
return math.NaN(), nil
}
return float64(f.At(idx).(*time.Time).UnixNano() / int64(time.Millisecond)), nil
}
return 0, fmt.Errorf("unsupported field type %T", f.Type())
}
// SetConfig modifies the Field's Config property to
// be set to conf and returns the Field.
func (f *Field) SetConfig(conf *FieldConfig) *Field {
@@ -507,6 +653,12 @@ func (f *Frame) RowLen() (int, error) {
return l, nil
}
// FloatAt returns a float64 representation of value of the specified fieldIdx and rowIdx as per Field.FloatAt().
// It will panic if either the fieldIdx or rowIdx are out of range.
func (f *Frame) FloatAt(fieldIdx int, rowIdx int) (float64, error) {
return f.Fields[fieldIdx].FloatAt(rowIdx)
}
// FrameTestCompareOptions returns go-cmp testing options to allow testing of Frame equivelnce.
// The intent is to only use this for testing.
func FrameTestCompareOptions() []cmp.Option {
@@ -538,7 +690,75 @@ func FrameTestCompareOptions() []cmp.Option {
}
return *x == *y
})
f64Ptrs := cmp.Comparer(func(x, y *float64) bool {
if x == nil && y == nil {
return true
}
if y == nil {
if math.IsNaN(float64(*x)) {
return true
}
if math.IsInf(float64(*x), 1) {
return true
}
if math.IsInf(float64(*x), -1) {
return true
}
}
if x == nil {
if math.IsNaN(float64(*y)) {
return true
}
if math.IsInf(float64(*y), 1) {
return true
}
if math.IsInf(float64(*y), -1) {
return true
}
}
return *x == *y
})
f64s := cmp.Comparer(func(x, y float64) bool {
return (math.IsNaN(x) && math.IsNaN(y)) ||
(math.IsInf(x, 1) && math.IsInf(y, 1)) ||
(math.IsInf(x, -1) && math.IsInf(y, -1)) ||
x == y
})
f32Ptrs := cmp.Comparer(func(x, y *float32) bool {
if x == nil && y == nil {
return true
}
if y == nil {
if math.IsNaN(float64(*x)) {
return true
}
if math.IsInf(float64(*x), 1) {
return true
}
if math.IsInf(float64(*x), -1) {
return true
}
}
if x == nil {
if math.IsNaN(float64(*y)) {
return true
}
if math.IsInf(float64(*y), 1) {
return true
}
if math.IsInf(float64(*y), -1) {
return true
}
}
return *x == *y
})
f32s := cmp.Comparer(func(x, y float32) bool {
return (math.IsNaN(float64(x)) && math.IsNaN(float64(y))) ||
(math.IsInf(float64(x), 1) && math.IsInf(float64(y), 1)) ||
(math.IsInf(float64(x), -1) && math.IsInf(float64(y), -1)) ||
x == y
})
unexportedField := cmp.AllowUnexported(Field{})
return []cmp.Option{confFloats, unexportedField, cmpopts.EquateEmpty()}
return []cmp.Option{f32s, f32Ptrs, f64s, f64Ptrs, confFloats, unexportedField, cmpopts.EquateEmpty()}
}
+21
View File
@@ -542,6 +542,27 @@ func (p FieldType) Nullable() bool {
return false
}
// Numeric returns if Field type is a nullable type
func (p FieldType) Numeric() bool {
switch p {
case FieldTypeInt8, FieldTypeInt16, FieldTypeInt32, FieldTypeInt64:
return true
case FieldTypeNullableInt8, FieldTypeNullableInt16, FieldTypeNullableInt32, FieldTypeNullableInt64:
return true
case FieldTypeUint8, FieldTypeUint16, FieldTypeUint32, FieldTypeUint64:
return true
case FieldTypeNullableUint8, FieldTypeNullableUint16, FieldTypeNullableUint32, FieldTypeNullableUint64:
return true
case FieldTypeFloat32, FieldTypeFloat64:
return true
case FieldTypeNullableFloat32, FieldTypeNullableFloat64:
return true
}
return false
}
// numericFieldTypes is an array of FieldTypes that are numeric.
var numericFieldTypes = [...]FieldType{
FieldTypeInt8, FieldTypeInt16, FieldTypeInt32, FieldTypeInt64,
+1
View File
@@ -0,0 +1 @@
/coverage.out
+29
View File
@@ -0,0 +1,29 @@
BSD 3-Clause License
Copyright © 2019, Vasiliy Vasilyuk <xorcare@gmail.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+68
View File
@@ -0,0 +1,68 @@
# Based on https://git.io/fjkGc
# The full path to the main package is use in the
# imports tool to format imports correctly.
NAMESPACE = github.com/xorcare/pointer
# The name of the file recommended in the standard
# documentation go test -cover and used codecov.io
# to check code coverage.
COVER_FILE ?= coverage.out
# Main targets.
.DEFAULT_GOAL := help
.PHONY: build
build: ## Build the project binary
@go build ./...
.PHONY: ci
ci: check ## Target for integration with ci pipeline
.PHONY: check
check: static test build ## Check project with static checks and unit tests
.PHONY: help
help: ## Print this help
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | \
awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
.PHONY: imports
imports: tools ## Check and fix import section by import rules
@test -z $$(for d in $$(go list -f {{.Dir}} ./...); do goimports -e -l -local $(NAMESPACE) -w $$d/*.go; done)
.PHONY: lint
lint: tools ## Check the project with lint
@golint -set_exit_status ./...
.PHONY: static
static: imports vet lint ## Run static checks (lint, imports, vet, ...) all over the project
.PHONY: test
test: ## Run unit tests
@go test ./... -count=1 -race
@go test ./... -count=1 -coverprofile=$(COVER_FILE) -covermode=atomic $d
@go tool cover -func=$(COVER_FILE) | grep ^total
CDTOOLS ?= @cd internal/tools &&
.PHONY: tools
tools: ## Install all needed tools, e.g. for static checks
$(CDTOOLS) \
go install \
golang.org/x/lint/golint \
golang.org/x/tools/cmd/goimports
.PHONY: toolsup
toolsup: ## Update all needed tools, e.g. for static checks
$(CDTOOLS) \
go mod tidy && \
go get \
golang.org/x/lint/golint@latest \
golang.org/x/tools/cmd/goimports@latest && \
go mod download && \
go mod verify
$(MAKE) tools
.PHONY: vet
vet: ## Check the project with vet
@go vet ./...
+54
View File
@@ -0,0 +1,54 @@
# pointer
[![Build Status](https://travis-ci.org/xorcare/pointer.svg?branch=master)](https://travis-ci.org/xorcare/pointer)
[![codecov](https://codecov.io/gh/xorcare/pointer/badge.svg)](https://codecov.io/gh/xorcare/pointer)
[![Go Report Card](https://goreportcard.com/badge/github.com/xorcare/pointer)](https://goreportcard.com/report/github.com/xorcare/pointer)
[![GoDoc](https://godoc.org/github.com/xorcare/pointer?status.svg)](https://godoc.org/github.com/xorcare/pointer)
Package pointer contains helper routines for simplifying the creation
of optional fields of basic type.
## Installation
```bash
go get github.com/xorcare/pointer
```
## Examples
Examples of using the library are presented on [godoc.org][GDE]
and in the [source library code](https://git.io/Jeg75).
## FAQ
| Question | Source |
| -------- | ------ |
| How to set **bool** pointer in a struct literal or variable? | `var _ *bool = pointer.Bool(true)` |
| How to set **byte** pointer in a struct literal or variable? | `var _ *byte = pointer.Byte(1)` |
| How to set **complex64** pointer in a struct literal or variable? | `var _ *complex64 = pointer.Complex64(1.1)` |
| How to set **complex128** pointer in a struct literal or variable? | `var _ *complex128 = pointer.Complex128(1.1)` |
| How to set **float32** pointer in a struct literal or variable? | `var _ *float32 = pointer.Float32(1.1)` |
| How to set **float64** pointer in a struct literal or variable? | `var _ *float64 = pointer.Float64(1.1)` |
| How to set **int** pointer in a struct literal or variable? | `var _ *int = pointer.Int(1)` |
| How to set **int8** pointer in a struct literal or variable? | `var _ *int8 = pointer.Int8(8)` |
| How to set **int16** pointer in a struct literal or variable? | `var _ *int16 = pointer.Int16(16)` |
| How to set **int32** pointer in a struct literal or variable? | `var _ *int32 = pointer.Int32(32)` |
| How to set **int64** pointer in a struct literal or variable? | `var _ *int64 = pointer.Int64(64)` |
| How to set **rune** pointer in a struct literal or variable? | `var _ *rune = pointer.Rune(1)` |
| How to set **string** pointer in a struct literal or variable? | `var _ *string = pointer.String("ptr")` |
| How to set **uint** pointer in a struct literal or variable? | `var _ *uint = pointer.Uint(1)` |
| How to set **uint8** pointer in a struct literal or variable? | `var _ *uint8 = pointer.Uint8(8)` |
| How to set **uint16** pointer in a struct literal or variable? | `var _ *uint16 = pointer.Uint16(16)` |
| How to set **uint32** pointer in a struct literal or variable? | `var _ *uint32 = pointer.Uint32(32)` |
| How to set **uint64** pointer in a struct literal or variable? | `var _ *uint64 = pointer.Uint64(64)` |
| How to set **time.Time** pointer in a struct literal or variable? | `var _ *time.Time = pointer.Time(time.Now())` |
| How to set **time.Duration** pointer in a struct literal or variable? | `var _ *time.Duration = pointer.Duration(time.Hour)` |
## License
© Vasiliy Vasilyuk, 2019-2020
Released under the [BSD 3-Clause License][LICENSE].
[LICENSE]: https://git.io/Jeg7Q 'BSD 3-Clause "New" or "Revised" License'
[GDE]: https://godoc.org/github.com/xorcare/pointer#pkg-examples 'Examples of using package pointer'
+3
View File
@@ -0,0 +1,3 @@
module github.com/xorcare/pointer
go 1.13
+126
View File
@@ -0,0 +1,126 @@
// Copyright © 2019-2020 Vasiliy Vasilyuk. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package pointer contains helper routines for simplifying the creation
// of optional fields of basic type.
package pointer
import (
"reflect"
"time"
)
// Any is a helper routine that allocates a new interface value
// to store v and returns a pointer to it.
//
// // Usage: var _ *Type = pointer.Any(Type(value) | value).(*Type)
//
// var _ *bool = pointer.Any(true).(*bool)
// var _ *byte = pointer.Any(byte(1)).(*byte)
// var _ *complex64 = pointer.Any(complex64(1.1)).(*complex64)
// var _ *complex128 = pointer.Any(complex128(1.1)).(*complex128)
// var _ *float32 = pointer.Any(float32(1.1)).(*float32)
// var _ *float64 = pointer.Any(float64(1.1)).(*float64)
// var _ *int = pointer.Any(int(1)).(*int)
// var _ *int8 = pointer.Any(int8(8)).(*int8)
// var _ *int16 = pointer.Any(int16(16)).(*int16)
// var _ *int32 = pointer.Any(int32(32)).(*int32)
// var _ *int64 = pointer.Any(int64(64)).(*int64)
// var _ *rune = pointer.Any(rune(1)).(*rune)
// var _ *string = pointer.Any("ptr").(*string)
// var _ *uint = pointer.Any(uint(1)).(*uint)
// var _ *uint8 = pointer.Any(uint8(8)).(*uint8)
// var _ *uint16 = pointer.Any(uint16(16)).(*uint16)
// var _ *uint32 = pointer.Any(uint32(32)).(*uint32)
// var _ *uint64 = pointer.Any(uint64(64)).(*uint64)
// var _ *uintptr = pointer.Any(uintptr(64)).(*uintptr)
func Any(v interface{}) interface{} {
r := reflect.New(reflect.TypeOf(v))
reflect.ValueOf(r.Interface()).Elem().Set(reflect.ValueOf(v))
return r.Interface()
}
// Bool is a helper routine that allocates a new bool value
// to store v and returns a pointer to it.
func Bool(v bool) *bool { return &v }
// Byte is a helper routine that allocates a new byte value
// to store v and returns a pointer to it.
func Byte(v byte) *byte { return &v }
// Complex64 is a helper routine that allocates a new complex64 value
// to store v and returns a pointer to it.
func Complex64(v complex64) *complex64 { return &v }
// Complex128 is a helper routine that allocates a new complex128 value
// to store v and returns a pointer to it.
func Complex128(v complex128) *complex128 { return &v }
// Float32 is a helper routine that allocates a new float32 value
// to store v and returns a pointer to it.
func Float32(v float32) *float32 { return &v }
// Float64 is a helper routine that allocates a new float64 value
// to store v and returns a pointer to it.
func Float64(v float64) *float64 { return &v }
// Int is a helper routine that allocates a new int value
// to store v and returns a pointer to it.
func Int(v int) *int { return &v }
// Int8 is a helper routine that allocates a new int8 value
// to store v and returns a pointer to it.
func Int8(v int8) *int8 { return &v }
// Int16 is a helper routine that allocates a new int16 value
// to store v and returns a pointer to it.
func Int16(v int16) *int16 { return &v }
// Int32 is a helper routine that allocates a new int32 value
// to store v and returns a pointer to it.
func Int32(v int32) *int32 { return &v }
// Int64 is a helper routine that allocates a new int64 value
// to store v and returns a pointer to it.
func Int64(v int64) *int64 { return &v }
// Rune is a helper routine that allocates a new rune value
// to store v and returns a pointer to it.
func Rune(v rune) *rune { return &v }
// String is a helper routine that allocates a new string value
// to store v and returns a pointer to it.
func String(v string) *string { return &v }
// Uint is a helper routine that allocates a new uint value
// to store v and returns a pointer to it.
func Uint(v uint) *uint { return &v }
// Uint8 is a helper routine that allocates a new uint8 value
// to store v and returns a pointer to it.
func Uint8(v uint8) *uint8 { return &v }
// Uint16 is a helper routine that allocates a new uint16 value
// to store v and returns a pointer to it.
func Uint16(v uint16) *uint16 { return &v }
// Uint32 is a helper routine that allocates a new uint32 value
// to store v and returns a pointer to it.
func Uint32(v uint32) *uint32 { return &v }
// Uint64 is a helper routine that allocates a new uint64 value
// to store v and returns a pointer to it.
func Uint64(v uint64) *uint64 { return &v }
// Uintptr is a helper routine that allocates a new uintptr value
// to store v and returns a pointer to it.
func Uintptr(v uintptr) *uintptr { return &v }
// Time is a helper routine that allocates a new time.Time value
// to store v and returns a pointer to it.
func Time(v time.Time) *time.Time { return &v }
// Duration is a helper routine that allocates a new time.Duration value
// to store v and returns a pointer to it.
func Duration(v time.Duration) *time.Duration { return &v }