mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-10-18 03:01:32 +08:00
fix: alert eval for "="/"!=" combination with "at least once"/"all the times" (#3613)
This commit is contained in:
parent
e3f4fc2967
commit
4076cd9847
3
Makefile
3
Makefile
@ -151,4 +151,5 @@ test:
|
||||
go test ./pkg/query-service/app/querier/...
|
||||
go test ./pkg/query-service/converter/...
|
||||
go test ./pkg/query-service/formatter/...
|
||||
go test ./pkg/query-service/tests/integration/...
|
||||
go test ./pkg/query-service/tests/integration/...
|
||||
go test ./pkg/query-service/rules/...
|
||||
|
14
go.mod
14
go.mod
@ -3,7 +3,7 @@ module go.signoz.io/signoz
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.13.2
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.14.0
|
||||
github.com/SigNoz/govaluate v0.0.0-20220522085550-d19c08c206cb
|
||||
github.com/SigNoz/zap_otlp/zap_otlp_encoder v0.0.0-20230822164844-1b861a431974
|
||||
github.com/SigNoz/zap_otlp/zap_otlp_sync v0.0.0-20230822164844-1b861a431974
|
||||
@ -18,7 +18,7 @@ require (
|
||||
github.com/go-redis/redis/v8 v8.11.5
|
||||
github.com/go-redis/redismock/v8 v8.11.5
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/google/uuid v1.3.1
|
||||
github.com/gorilla/handlers v1.5.1
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/gosimple/slug v1.10.0
|
||||
@ -45,9 +45,10 @@ require (
|
||||
github.com/smartystreets/assertions v1.13.1
|
||||
github.com/smartystreets/goconvey v1.8.1
|
||||
github.com/soheilhy/cmux v0.1.5
|
||||
github.com/srikanthccv/ClickHouse-go-mock v0.4.0
|
||||
github.com/stretchr/testify v1.8.4
|
||||
go.opentelemetry.io/collector/confmap v0.70.0
|
||||
go.opentelemetry.io/otel v1.16.0
|
||||
go.opentelemetry.io/otel v1.17.0
|
||||
go.opentelemetry.io/otel/sdk v1.16.0
|
||||
go.uber.org/multierr v1.11.0
|
||||
go.uber.org/zap v1.25.0
|
||||
@ -69,6 +70,7 @@ require (
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 // indirect
|
||||
github.com/ClickHouse/ch-go v0.58.2 // indirect
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0 // indirect
|
||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
|
||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
||||
github.com/aws/aws-sdk-go v1.44.302 // indirect
|
||||
@ -135,13 +137,13 @@ require (
|
||||
go.opentelemetry.io/collector/pdata v1.0.0-rcv0014 // indirect
|
||||
go.opentelemetry.io/collector/semconv v0.81.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.16.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.16.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.17.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.17.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
go.uber.org/goleak v1.2.1 // indirect
|
||||
golang.org/x/sync v0.3.0 // indirect
|
||||
golang.org/x/sys v0.10.0 // indirect
|
||||
golang.org/x/sys v0.11.0 // indirect
|
||||
golang.org/x/text v0.11.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
|
40
go.sum
40
go.sum
@ -84,10 +84,12 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/ClickHouse/ch-go v0.58.2 h1:jSm2szHbT9MCAB1rJ3WuCJqmGLi5UTjlNu+f530UTS0=
|
||||
github.com/ClickHouse/ch-go v0.58.2/go.mod h1:Ap/0bEmiLa14gYjCiRkYGbXvbe8vwdrfTYWhsuQ99aw=
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.13.2 h1:LSg6670+xbd5VczO5Ei3DHZBIeGulfwhNuHCUth/qOA=
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.13.2/go.mod h1:4QITCrdY/ugPYA+QGnJ92h+v7TGaZQ7l0393Q/wlM3Q=
|
||||
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
|
||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.14.0 h1:7pzOLkWTc+Kn6e8Q2jtkTT9G+7RFY6QCw1Kc2nQ5pW4=
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.14.0/go.mod h1:PHqbMvJTQ0EI4a1vJhmbmL/Ajr+Cin2O+WJjnYctJvg=
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/SigNoz/govaluate v0.0.0-20220522085550-d19c08c206cb h1:bneLSKPf9YUSFmafKx32bynV6QrzViL/s+ZDvQxH1E4=
|
||||
@ -186,8 +188,8 @@ github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
|
||||
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
|
||||
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v24.0.4+incompatible h1:s/LVDftw9hjblvqIeTiGYXBCD95nOEEl7qRsRrIOuQI=
|
||||
github.com/docker/docker v24.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v24.0.5+incompatible h1:WmgcE4fxyI6EEXxBRxsHnZXrO1pQ3smi0k/jho4HLeY=
|
||||
github.com/docker/docker v24.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
@ -367,8 +369,8 @@ github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLe
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
@ -614,8 +616,8 @@ github.com/open-telemetry/opamp-go v0.5.0 h1:2YFbb6G4qBkq3yTRdVb5Nfz9hKHW/ldUyex
|
||||
github.com/open-telemetry/opamp-go v0.5.0/go.mod h1:IMdeuHGVc5CjKSu5/oNV0o+UmiXuahoHvoZ4GOmAI9M=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec=
|
||||
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
|
||||
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
|
||||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
||||
github.com/ovh/go-ovh v1.4.1 h1:VBGa5wMyQtTP7Zb+w97zRCh9sLtM/2YKRyy+MEJmWaM=
|
||||
@ -729,6 +731,8 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/srikanthccv/ClickHouse-go-mock v0.4.0 h1:tLk7qoDLg7Z5YD5mOmNqjRDbsm6ehJVXOFvSnG+gQAg=
|
||||
github.com/srikanthccv/ClickHouse-go-mock v0.4.0/go.mod h1:kRG9cuhS527AMXqKYgsii/CP28L/22fyJcOBExmLpEw=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
@ -784,14 +788,14 @@ go.opentelemetry.io/collector/semconv v0.81.0 h1:lCYNNo3powDvFIaTPP2jDKIrBiV1T92
|
||||
go.opentelemetry.io/collector/semconv v0.81.0/go.mod h1:TlYPtzvsXyHOgr5eATi43qEMqwSmIziivJB2uctKswo=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 h1:pginetY7+onl4qN1vl0xW/V/v6OBZ0vVdH+esuJgvmM=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0/go.mod h1:XiYsayHc36K3EByOO6nbAXnAWbrUxdjUROCEeeROOH8=
|
||||
go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=
|
||||
go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4=
|
||||
go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo=
|
||||
go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4=
|
||||
go.opentelemetry.io/otel v1.17.0 h1:MW+phZ6WZ5/uk2nd93ANk/6yJ+dVrvNWUjGhnnFU5jM=
|
||||
go.opentelemetry.io/otel v1.17.0/go.mod h1:I2vmBGtFaODIVMBSTPVDlJSzBDNf93k60E6Ft0nyjo0=
|
||||
go.opentelemetry.io/otel/metric v1.17.0 h1:iG6LGVz5Gh+IuO0jmgvpTB6YVrCGngi8QGm+pMd8Pdc=
|
||||
go.opentelemetry.io/otel/metric v1.17.0/go.mod h1:h4skoxdZI17AxwITdmdZjjYJQH5nzijUUjm+wtPph5o=
|
||||
go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE=
|
||||
go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4=
|
||||
go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs=
|
||||
go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0=
|
||||
go.opentelemetry.io/otel/trace v1.17.0 h1:/SWhSRHmDPOImIAetP1QAeMnZYiQXrTy4fMMYOdSKWQ=
|
||||
go.opentelemetry.io/otel/trace v1.17.0/go.mod h1:I/4vKTgFclIsXRVucpH25X0mpFSczM7aHeaz0ZBLWjY=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
|
||||
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
|
||||
@ -1043,8 +1047,8 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
|
@ -521,6 +521,7 @@ func (r *ThresholdRule) runChQuery(ctx context.Context, db clickhouse.Conn, quer
|
||||
if math.IsNaN(sample.Point.V) {
|
||||
continue
|
||||
}
|
||||
sample.Point.Vs = append(sample.Point.Vs, sample.Point.V)
|
||||
|
||||
// capture lables in result
|
||||
sample.Metric = lbls.Labels()
|
||||
@ -540,6 +541,9 @@ func (r *ThresholdRule) runChQuery(ctx context.Context, db clickhouse.Conn, quer
|
||||
} else if r.compareOp() == ValueIsBelow {
|
||||
sample.Point.V = math.Max(existing.Point.V, sample.Point.V)
|
||||
resultMap[labelHash] = sample
|
||||
} else {
|
||||
sample.Point.Vs = append(existing.Point.Vs, sample.Point.V)
|
||||
resultMap[labelHash] = sample
|
||||
}
|
||||
case AtleastOnce:
|
||||
if r.compareOp() == ValueIsAbove {
|
||||
@ -548,6 +552,9 @@ func (r *ThresholdRule) runChQuery(ctx context.Context, db clickhouse.Conn, quer
|
||||
} else if r.compareOp() == ValueIsBelow {
|
||||
sample.Point.V = math.Min(existing.Point.V, sample.Point.V)
|
||||
resultMap[labelHash] = sample
|
||||
} else {
|
||||
sample.Point.Vs = append(existing.Point.Vs, sample.Point.V)
|
||||
resultMap[labelHash] = sample
|
||||
}
|
||||
case OnAverage:
|
||||
sample.Point.V = (existing.Point.V + sample.Point.V) / 2
|
||||
@ -578,36 +585,37 @@ func (r *ThresholdRule) runChQuery(ctx context.Context, db clickhouse.Conn, quer
|
||||
|
||||
}
|
||||
|
||||
if s, ok := resultMap[labelHash]; ok {
|
||||
s.Point.Vs = append(s.Point.Vs, s.Point.V)
|
||||
}
|
||||
}
|
||||
|
||||
for _, s := range resultMap {
|
||||
for hash, s := range resultMap {
|
||||
if r.matchType() == AllTheTimes && r.compareOp() == ValueIsEq {
|
||||
for _, v := range s.Point.Vs {
|
||||
if v != r.targetVal() { // if any of the values is not equal to target, alert shouldn't be sent
|
||||
s.Point.V = v
|
||||
}
|
||||
}
|
||||
resultMap[hash] = s
|
||||
} else if r.matchType() == AllTheTimes && r.compareOp() == ValueIsNotEq {
|
||||
for _, v := range s.Point.Vs {
|
||||
if v == r.targetVal() { // if any of the values is equal to target, alert shouldn't be sent
|
||||
s.Point.V = v
|
||||
}
|
||||
}
|
||||
resultMap[hash] = s
|
||||
} else if r.matchType() == AtleastOnce && r.compareOp() == ValueIsEq {
|
||||
for _, v := range s.Point.Vs {
|
||||
if v == r.targetVal() { // if any of the values is equal to target, alert should be sent
|
||||
s.Point.V = v
|
||||
}
|
||||
}
|
||||
resultMap[hash] = s
|
||||
} else if r.matchType() == AtleastOnce && r.compareOp() == ValueIsNotEq {
|
||||
for _, v := range s.Point.Vs {
|
||||
if v != r.targetVal() { // if any of the values is not equal to target, alert should be sent
|
||||
s.Point.V = v
|
||||
}
|
||||
}
|
||||
resultMap[hash] = s
|
||||
}
|
||||
}
|
||||
|
||||
|
297
pkg/query-service/rules/thresholdRule_test.go
Normal file
297
pkg/query-service/rules/thresholdRule_test.go
Normal file
@ -0,0 +1,297 @@
|
||||
package rules
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
cmock "github.com/srikanthccv/ClickHouse-go-mock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"go.signoz.io/signoz/pkg/query-service/featureManager"
|
||||
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||||
)
|
||||
|
||||
func TestThresholdRuleCombinations(t *testing.T) {
|
||||
postableRule := PostableRule{
|
||||
Alert: "Tricky Condition Tests",
|
||||
AlertType: "METRICS_BASED_ALERT",
|
||||
RuleType: RuleTypeThreshold,
|
||||
EvalWindow: Duration(5 * time.Minute),
|
||||
Frequency: Duration(1 * time.Minute),
|
||||
RuleCondition: &RuleCondition{
|
||||
CompositeQuery: &v3.CompositeQuery{
|
||||
QueryType: v3.QueryTypeBuilder,
|
||||
BuilderQueries: map[string]*v3.BuilderQuery{
|
||||
"A": {
|
||||
QueryName: "A",
|
||||
StepInterval: 60,
|
||||
AggregateAttribute: v3.AttributeKey{
|
||||
Key: "probe_success",
|
||||
},
|
||||
AggregateOperator: v3.AggregateOperatorNoOp,
|
||||
DataSource: v3.DataSourceMetrics,
|
||||
Expression: "A",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
fm := featureManager.StartManager()
|
||||
mock, err := cmock.NewClickHouseNative(nil)
|
||||
if err != nil {
|
||||
t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
|
||||
}
|
||||
|
||||
cols := make([]cmock.ColumnType, 0)
|
||||
cols = append(cols, cmock.ColumnType{Name: "value", Type: "Int32"})
|
||||
cols = append(cols, cmock.ColumnType{Name: "endpoint", Type: "String"})
|
||||
|
||||
cases := []struct {
|
||||
values [][]interface{}
|
||||
expectAlert bool
|
||||
compareOp string
|
||||
matchType string
|
||||
target float64
|
||||
}{
|
||||
// Test cases for Equals Always
|
||||
{
|
||||
values: [][]interface{}{
|
||||
{int32(0), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
},
|
||||
expectAlert: true,
|
||||
compareOp: "3", // Equals
|
||||
matchType: "2", // Always
|
||||
target: 0.0,
|
||||
},
|
||||
{
|
||||
values: [][]interface{}{
|
||||
{int32(0), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
},
|
||||
expectAlert: false,
|
||||
compareOp: "3", // Equals
|
||||
matchType: "2", // Always
|
||||
target: 0.0,
|
||||
},
|
||||
{
|
||||
values: [][]interface{}{
|
||||
{int32(0), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
},
|
||||
expectAlert: false,
|
||||
compareOp: "3", // Equals
|
||||
matchType: "2", // Always
|
||||
target: 0.0,
|
||||
},
|
||||
{
|
||||
values: [][]interface{}{
|
||||
{int32(1), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
},
|
||||
expectAlert: false,
|
||||
compareOp: "3", // Equals
|
||||
matchType: "2", // Always
|
||||
target: 0.0,
|
||||
},
|
||||
// Test cases for Equals Once
|
||||
{
|
||||
values: [][]interface{}{
|
||||
{int32(0), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
},
|
||||
expectAlert: true,
|
||||
compareOp: "3", // Equals
|
||||
matchType: "1", // Once
|
||||
target: 0.0,
|
||||
},
|
||||
{
|
||||
values: [][]interface{}{
|
||||
{int32(0), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
},
|
||||
expectAlert: true,
|
||||
compareOp: "3", // Equals
|
||||
matchType: "1", // Once
|
||||
target: 0.0,
|
||||
},
|
||||
{
|
||||
values: [][]interface{}{
|
||||
{int32(0), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
},
|
||||
expectAlert: true,
|
||||
compareOp: "3", // Equals
|
||||
matchType: "1", // Once
|
||||
target: 0.0,
|
||||
},
|
||||
{
|
||||
values: [][]interface{}{
|
||||
{int32(1), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
},
|
||||
expectAlert: false,
|
||||
compareOp: "3", // Equals
|
||||
matchType: "1", // Once
|
||||
target: 0.0,
|
||||
},
|
||||
// Test cases for Not Equals Always
|
||||
{
|
||||
values: [][]interface{}{
|
||||
{int32(0), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
},
|
||||
expectAlert: false,
|
||||
compareOp: "4", // Not Equals
|
||||
matchType: "2", // Always
|
||||
target: 0.0,
|
||||
},
|
||||
{
|
||||
values: [][]interface{}{
|
||||
{int32(1), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
},
|
||||
expectAlert: false,
|
||||
compareOp: "4", // Not Equals
|
||||
matchType: "2", // Always
|
||||
target: 0.0,
|
||||
},
|
||||
{
|
||||
values: [][]interface{}{
|
||||
{int32(1), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
},
|
||||
expectAlert: true,
|
||||
compareOp: "4", // Not Equals
|
||||
matchType: "2", // Always
|
||||
target: 0.0,
|
||||
},
|
||||
{
|
||||
values: [][]interface{}{
|
||||
{int32(1), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
},
|
||||
expectAlert: false,
|
||||
compareOp: "4", // Not Equals
|
||||
matchType: "2", // Always
|
||||
target: 0.0,
|
||||
},
|
||||
// Test cases for Not Equals Once
|
||||
{
|
||||
values: [][]interface{}{
|
||||
{int32(0), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
},
|
||||
expectAlert: true,
|
||||
compareOp: "4", // Not Equals
|
||||
matchType: "1", // Once
|
||||
target: 0.0,
|
||||
},
|
||||
{
|
||||
values: [][]interface{}{
|
||||
{int32(0), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
},
|
||||
expectAlert: false,
|
||||
compareOp: "4", // Not Equals
|
||||
matchType: "1", // Once
|
||||
target: 0.0,
|
||||
},
|
||||
{
|
||||
values: [][]interface{}{
|
||||
{int32(0), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
{int32(0), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
},
|
||||
expectAlert: true,
|
||||
compareOp: "4", // Not Equals
|
||||
matchType: "1", // Once
|
||||
target: 0.0,
|
||||
},
|
||||
{
|
||||
values: [][]interface{}{
|
||||
{int32(1), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
{int32(1), "endpoint"},
|
||||
},
|
||||
expectAlert: true,
|
||||
compareOp: "4", // Not Equals
|
||||
matchType: "1", // Once
|
||||
target: 0.0,
|
||||
},
|
||||
}
|
||||
|
||||
for idx, c := range cases {
|
||||
rows := cmock.NewRows(cols, c.values)
|
||||
// We are testing the eval logic after the query is run
|
||||
// so we don't care about the query string here
|
||||
queryString := "SELECT value, endpoint FROM table"
|
||||
mock.
|
||||
ExpectQuery(queryString).
|
||||
WillReturnRows(rows)
|
||||
postableRule.RuleCondition.CompareOp = CompareOp(c.compareOp)
|
||||
postableRule.RuleCondition.MatchType = MatchType(c.matchType)
|
||||
postableRule.RuleCondition.Target = &c.target
|
||||
|
||||
rule, err := NewThresholdRule("69", &postableRule, ThresholdRuleOpts{}, fm)
|
||||
if err != nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
result, err := rule.runChQuery(context.Background(), mock, queryString)
|
||||
if err != nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if c.expectAlert {
|
||||
assert.Equal(t, 1, len(result), "case %d", idx)
|
||||
} else {
|
||||
assert.Equal(t, 0, len(result), "case %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user