nightingale/judge/compute.go

427 lines
9.3 KiB
Go
Raw Normal View History

2021-01-18 23:39:23 +08:00
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2020-09-26 16:53:10 +08:00
package judge
import (
"fmt"
"math"
"github.com/didi/nightingale/v5/vos"
2020-09-26 16:53:10 +08:00
)
type Function interface {
Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool)
2020-09-26 16:53:10 +08:00
}
type MaxFunction struct {
Function
Limit int
Operator string
RightValue float64
}
func (f MaxFunction) Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool) {
count := len(vs)
if count < 1 {
return
}
2020-09-26 16:53:10 +08:00
max := vs[0].Value
for i := 1; i < len(vs); i++ {
2020-09-26 16:53:10 +08:00
if max < vs[i].Value {
max = vs[i].Value
}
}
leftValue = max
isTriggered = checkIsTriggered(leftValue, f.Operator, f.RightValue)
return
}
type MinFunction struct {
Function
Limit int
Operator string
RightValue float64
}
func (f MinFunction) Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool) {
count := len(vs)
if count < 1 {
return
}
2020-09-26 16:53:10 +08:00
min := vs[0].Value
for i := 1; i < len(vs); i++ {
2020-09-26 16:53:10 +08:00
if min > vs[i].Value {
min = vs[i].Value
}
}
leftValue = min
isTriggered = checkIsTriggered(leftValue, f.Operator, f.RightValue)
return
}
type AllFunction struct {
Function
Limit int
Operator string
RightValue float64
}
func (f AllFunction) Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool) {
count := len(vs)
if count < 1 {
2020-09-26 16:53:10 +08:00
return
}
for i := 0; i < len(vs); i++ {
2020-09-26 16:53:10 +08:00
isTriggered = checkIsTriggered(vs[i].Value, f.Operator, f.RightValue)
if !isTriggered {
break
}
}
leftValue = vs[0].Value
return
}
type SumFunction struct {
Function
Limit int
Operator string
RightValue float64
}
func (f SumFunction) Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool) {
count := len(vs)
if count < 1 {
return
}
sum := vos.JsonFloat(0.0)
for i := 0; i < count; i++ {
2020-09-26 16:53:10 +08:00
sum += vs[i].Value
}
leftValue = sum
isTriggered = checkIsTriggered(leftValue, f.Operator, f.RightValue)
return
}
type AvgFunction struct {
Function
Limit int
Operator string
RightValue float64
}
func (f AvgFunction) Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool) {
vsLen := len(vs)
if vsLen < 1 {
return
}
sum := vos.JsonFloat(0.0)
for i := 0; i < vsLen; i++ {
2020-09-26 16:53:10 +08:00
sum += vs[i].Value
}
leftValue = sum / vos.JsonFloat(vsLen)
2020-09-26 16:53:10 +08:00
isTriggered = checkIsTriggered(leftValue, f.Operator, f.RightValue)
return
}
type StddevFunction struct {
Function
Num int
Limit int
}
func (f StddevFunction) Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool) {
var sum float64
vsLen := len(vs)
if vsLen < 1 {
2020-09-26 16:53:10 +08:00
return
}
for i := 0; i < vsLen; i++ {
2020-09-26 16:53:10 +08:00
sum += float64(vs[i].Value)
}
mean := sum / float64(vsLen)
2020-09-26 16:53:10 +08:00
var num float64
for i := 0; i < vsLen; i++ {
2020-09-26 16:53:10 +08:00
num += math.Pow(float64(vs[i].Value)-mean, 2)
}
std := math.Sqrt(num / float64(vsLen))
2020-09-26 16:53:10 +08:00
upperBound := mean + std*float64(f.Num)
lowerBound := mean - std*float64(f.Num)
leftValue = vs[0].Value
isTriggered = checkIsTriggered(leftValue, "<", lowerBound) || checkIsTriggered(leftValue, ">", upperBound)
return
}
type DiffFunction struct {
Function
Limit int
Operator string
RightValue float64
}
// 只要有一个点的diff触发阈值就报警
func (f DiffFunction) Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool) {
vsLen := len(vs)
if vsLen < 1 {
return
}
2020-09-26 16:53:10 +08:00
first := vs[0].Value
isTriggered = false
for i := 1; i < vsLen; i++ {
2020-09-26 16:53:10 +08:00
// diff是当前值减去历史值
leftValue = first - vs[i].Value
isTriggered = checkIsTriggered(leftValue, f.Operator, f.RightValue)
if isTriggered {
break
}
}
return
}
// pdiff(#3)
type PDiffFunction struct {
Function
Limit int
Operator string
RightValue float64
}
func (f PDiffFunction) Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool) {
vsLen := len(vs)
if vsLen < 1 {
return
}
2020-09-26 16:53:10 +08:00
first := vs[0].Value
isTriggered = false
for i := 1; i < len(vs); i++ {
2020-09-26 16:53:10 +08:00
if vs[i].Value == 0 {
continue
}
leftValue = (first - vs[i].Value) / vs[i].Value * 100.0
isTriggered = checkIsTriggered(leftValue, f.Operator, f.RightValue)
if isTriggered {
break
}
}
return
}
type HappenFunction struct {
Function
Num int
Limit int
Operator string
RightValue float64
}
func (f HappenFunction) Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool) {
2020-09-26 16:53:10 +08:00
for n, i := 0, 0; i < len(vs); i++ {
if checkIsTriggered(vs[i].Value, f.Operator, f.RightValue) {
n++
if n == f.Num {
isTriggered = true
leftValue = vs[i].Value
return
}
}
}
return
}
type CAvgAbsFunction struct {
Function
Limit int
Operator string
RightValue float64
CompareValue float64
}
func (f CAvgAbsFunction) Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool) {
vsLen := len(vs)
if vsLen < 1 {
return
}
sum := vos.JsonFloat(0.0)
for i := 0; i < vsLen; i++ {
2020-09-26 16:53:10 +08:00
sum += vs[i].Value
}
value := sum / vos.JsonFloat(vsLen)
leftValue = vos.JsonFloat(math.Abs(float64(value) - float64(f.CompareValue)))
2020-09-26 16:53:10 +08:00
isTriggered = checkIsTriggered(leftValue, f.Operator, f.RightValue)
return
}
type CAvgFunction struct {
Function
Limit int
Operator string
RightValue float64
CompareValue float64
}
func (f CAvgFunction) Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool) {
vsLen := len(vs)
if vsLen < 1 {
return
}
sum := vos.JsonFloat(0.0)
for i := 0; i < vsLen; i++ {
2020-09-26 16:53:10 +08:00
sum += vs[i].Value
}
leftValue = sum/vos.JsonFloat(vsLen) - vos.JsonFloat(f.CompareValue)
2020-09-26 16:53:10 +08:00
isTriggered = checkIsTriggered(leftValue, f.Operator, f.RightValue)
return
}
type CAvgRateAbsFunction struct {
Function
Limit int
Operator string
RightValue float64
CompareValue float64
}
func (f CAvgRateAbsFunction) Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool) {
vsLen := len(vs)
if vsLen < 1 {
return
}
sum := vos.JsonFloat(0.0)
for i := 0; i < vsLen; i++ {
2020-09-26 16:53:10 +08:00
sum += vs[i].Value
}
value := sum / vos.JsonFloat(vsLen)
leftValue = vos.JsonFloat(math.Abs((float64(value)-float64(f.CompareValue))/f.CompareValue)) * 100.00
2020-09-26 16:53:10 +08:00
isTriggered = checkIsTriggered(leftValue, f.Operator, f.RightValue)
return
}
type CAvgRateFunction struct {
Function
Limit int
Operator string
RightValue float64
CompareValue float64
}
func (f CAvgRateFunction) Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool) {
vsLen := len(vs)
if vsLen < 1 {
return
}
sum := vos.JsonFloat(0.0)
for i := 0; i < vsLen; i++ {
2020-09-26 16:53:10 +08:00
sum += vs[i].Value
}
value := sum / vos.JsonFloat(vsLen)
leftValue = (value - vos.JsonFloat(f.CompareValue)) / vos.JsonFloat(math.Abs(f.CompareValue)) * 100.00
2020-09-26 16:53:10 +08:00
isTriggered = checkIsTriggered(leftValue, f.Operator, f.RightValue)
return
}
func ParseFuncFromString(str string, span []interface{}, operator string, rightValue float64) (fn Function, err error) {
if str == "" {
return nil, fmt.Errorf("func can not be null")
}
limit := span[0].(int)
switch str {
case "max":
fn = &MaxFunction{Limit: limit, Operator: operator, RightValue: rightValue}
case "min":
fn = &MinFunction{Limit: limit, Operator: operator, RightValue: rightValue}
case "all":
fn = &AllFunction{Limit: limit, Operator: operator, RightValue: rightValue}
case "sum":
fn = &SumFunction{Limit: limit, Operator: operator, RightValue: rightValue}
case "avg":
fn = &AvgFunction{Limit: limit, Operator: operator, RightValue: rightValue}
case "stddev":
fn = &StddevFunction{Limit: limit, Num: span[1].(int)}
case "diff":
fn = &DiffFunction{Limit: limit, Operator: operator, RightValue: rightValue}
case "pdiff":
fn = &PDiffFunction{Limit: limit, Operator: operator, RightValue: rightValue}
case "happen":
fn = &HappenFunction{Limit: limit, Num: span[1].(int), Operator: operator, RightValue: rightValue}
case "c_avg":
fn = &CAvgFunction{Limit: limit, CompareValue: span[1].(float64), Operator: operator, RightValue: rightValue}
case "c_avg_abs":
fn = &CAvgAbsFunction{Limit: limit, CompareValue: span[1].(float64), Operator: operator, RightValue: rightValue}
case "c_avg_rate":
fn = &CAvgRateFunction{Limit: limit, CompareValue: span[1].(float64), Operator: operator, RightValue: rightValue}
case "c_avg_rate_abs":
fn = &CAvgRateAbsFunction{Limit: limit, CompareValue: span[1].(float64), Operator: operator, RightValue: rightValue}
default:
err = fmt.Errorf("not_supported_method")
}
return
}
func checkIsTriggered(leftValue vos.JsonFloat, operator string, rightValue float64) (isTriggered bool) {
2020-09-26 16:53:10 +08:00
switch operator {
case "=", "==":
isTriggered = math.Abs(float64(leftValue)-rightValue) < 0.0001
case "!=":
isTriggered = math.Abs(float64(leftValue)-rightValue) > 0.0001
case "<":
isTriggered = float64(leftValue) < rightValue
case "<=":
isTriggered = float64(leftValue) <= rightValue
case ">":
isTriggered = float64(leftValue) > rightValue
case ">=":
isTriggered = float64(leftValue) >= rightValue
}
return
}