mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-12 10:59:02 +08:00
chore: add missing shiftby in alert rule (#6239)
This commit is contained in:
parent
00421235b0
commit
6c7167a224
@ -1142,25 +1142,7 @@ func ParseQueryRangeParams(r *http.Request) (*v3.QueryRangeParamsV3, *model.ApiE
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the time shift function from the list of functions and set the shift by value
|
query.SetShiftByFromFunc()
|
||||||
var timeShiftBy int64
|
|
||||||
if len(query.Functions) > 0 {
|
|
||||||
for idx := range query.Functions {
|
|
||||||
function := &query.Functions[idx]
|
|
||||||
if function.Name == v3.FunctionNameTimeShift {
|
|
||||||
// move the function to the beginning of the list
|
|
||||||
// so any other function can use the shifted time
|
|
||||||
var fns []v3.Function
|
|
||||||
fns = append(fns, *function)
|
|
||||||
fns = append(fns, query.Functions[:idx]...)
|
|
||||||
fns = append(fns, query.Functions[idx+1:]...)
|
|
||||||
query.Functions = fns
|
|
||||||
timeShiftBy = int64(function.Args[0].(float64))
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
query.ShiftBy = timeShiftBy
|
|
||||||
|
|
||||||
if query.Filters == nil || len(query.Filters.Items) == 0 {
|
if query.Filters == nil || len(query.Filters.Items) == 0 {
|
||||||
continue
|
continue
|
||||||
|
@ -297,6 +297,8 @@ func TestParseQueryRangeParamsCompositeQuery(t *testing.T) {
|
|||||||
compositeQuery v3.CompositeQuery
|
compositeQuery v3.CompositeQuery
|
||||||
expectErr bool
|
expectErr bool
|
||||||
errMsg string
|
errMsg string
|
||||||
|
hasShiftBy bool
|
||||||
|
shiftBy int64
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "no query in request",
|
desc: "no query in request",
|
||||||
@ -496,6 +498,56 @@ func TestParseQueryRangeParamsCompositeQuery(t *testing.T) {
|
|||||||
expectErr: true,
|
expectErr: true,
|
||||||
errMsg: "builder query A is invalid: group by is invalid",
|
errMsg: "builder query A is invalid: group by is invalid",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "builder query with shift by",
|
||||||
|
compositeQuery: v3.CompositeQuery{
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
|
QueryType: v3.QueryTypeBuilder,
|
||||||
|
BuilderQueries: map[string]*v3.BuilderQuery{
|
||||||
|
"A": {
|
||||||
|
QueryName: "A",
|
||||||
|
DataSource: "logs",
|
||||||
|
AggregateOperator: "sum",
|
||||||
|
AggregateAttribute: v3.AttributeKey{Key: "attribute"},
|
||||||
|
GroupBy: []v3.AttributeKey{{Key: "group_key"}},
|
||||||
|
Expression: "A",
|
||||||
|
Functions: []v3.Function{
|
||||||
|
{
|
||||||
|
Name: v3.FunctionNameTimeShift,
|
||||||
|
Args: []interface{}{float64(10)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
hasShiftBy: true,
|
||||||
|
shiftBy: 10,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "builder query with shift by as string",
|
||||||
|
compositeQuery: v3.CompositeQuery{
|
||||||
|
PanelType: v3.PanelTypeGraph,
|
||||||
|
QueryType: v3.QueryTypeBuilder,
|
||||||
|
BuilderQueries: map[string]*v3.BuilderQuery{
|
||||||
|
"A": {
|
||||||
|
QueryName: "A",
|
||||||
|
DataSource: "logs",
|
||||||
|
AggregateOperator: "sum",
|
||||||
|
AggregateAttribute: v3.AttributeKey{Key: "attribute"},
|
||||||
|
GroupBy: []v3.AttributeKey{{Key: "group_key"}},
|
||||||
|
Expression: "A",
|
||||||
|
Functions: []v3.Function{
|
||||||
|
{
|
||||||
|
Name: v3.FunctionNameTimeShift,
|
||||||
|
Args: []interface{}{"3600"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
hasShiftBy: true,
|
||||||
|
shiftBy: 3600,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range reqCases {
|
for _, tc := range reqCases {
|
||||||
@ -514,13 +566,16 @@ func TestParseQueryRangeParamsCompositeQuery(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
req := httptest.NewRequest(http.MethodPost, "/api/v3/query_range", body)
|
req := httptest.NewRequest(http.MethodPost, "/api/v3/query_range", body)
|
||||||
|
|
||||||
_, apiErr := ParseQueryRangeParams(req)
|
params, apiErr := ParseQueryRangeParams(req)
|
||||||
if tc.expectErr {
|
if tc.expectErr {
|
||||||
require.Error(t, apiErr)
|
require.Error(t, apiErr)
|
||||||
require.Contains(t, apiErr.Error(), tc.errMsg)
|
require.Contains(t, apiErr.Error(), tc.errMsg)
|
||||||
} else {
|
} else {
|
||||||
require.Nil(t, apiErr)
|
require.Nil(t, apiErr)
|
||||||
}
|
}
|
||||||
|
if tc.hasShiftBy {
|
||||||
|
require.Equal(t, tc.shiftBy, params.CompositeQuery.BuilderQueries["A"].ShiftBy)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DataSource string
|
type DataSource string
|
||||||
@ -789,6 +790,38 @@ type BuilderQuery struct {
|
|||||||
QueriesUsedInFormula []string
|
QueriesUsedInFormula []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *BuilderQuery) SetShiftByFromFunc() {
|
||||||
|
// Remove the time shift function from the list of functions and set the shift by value
|
||||||
|
var timeShiftBy int64
|
||||||
|
if len(b.Functions) > 0 {
|
||||||
|
for idx := range b.Functions {
|
||||||
|
function := &b.Functions[idx]
|
||||||
|
if function.Name == FunctionNameTimeShift {
|
||||||
|
// move the function to the beginning of the list
|
||||||
|
// so any other function can use the shifted time
|
||||||
|
var fns []Function
|
||||||
|
fns = append(fns, *function)
|
||||||
|
fns = append(fns, b.Functions[:idx]...)
|
||||||
|
fns = append(fns, b.Functions[idx+1:]...)
|
||||||
|
b.Functions = fns
|
||||||
|
if len(function.Args) > 0 {
|
||||||
|
if shift, ok := function.Args[0].(float64); ok {
|
||||||
|
timeShiftBy = int64(shift)
|
||||||
|
} else if shift, ok := function.Args[0].(string); ok {
|
||||||
|
shiftBy, err := strconv.ParseFloat(shift, 64)
|
||||||
|
if err != nil {
|
||||||
|
zap.L().Error("failed to parse time shift by", zap.String("shift", shift), zap.Error(err))
|
||||||
|
}
|
||||||
|
timeShiftBy = int64(shiftBy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.ShiftBy = timeShiftBy
|
||||||
|
}
|
||||||
|
|
||||||
func (b *BuilderQuery) Clone() *BuilderQuery {
|
func (b *BuilderQuery) Clone() *BuilderQuery {
|
||||||
if b == nil {
|
if b == nil {
|
||||||
return nil
|
return nil
|
||||||
|
@ -152,6 +152,9 @@ func (r *ThresholdRule) prepareQueryRange(ts time.Time) (*v3.QueryRangeParamsV3,
|
|||||||
if minStep := common.MinAllowedStepInterval(start, end); q.StepInterval < minStep {
|
if minStep := common.MinAllowedStepInterval(start, end); q.StepInterval < minStep {
|
||||||
q.StepInterval = minStep
|
q.StepInterval = minStep
|
||||||
}
|
}
|
||||||
|
|
||||||
|
q.SetShiftByFromFunc()
|
||||||
|
|
||||||
if q.DataSource == v3.DataSourceMetrics && constants.UseMetricsPreAggregation() {
|
if q.DataSource == v3.DataSourceMetrics && constants.UseMetricsPreAggregation() {
|
||||||
// if the time range is greater than 1 day, and less than 1 week set the step interval to be multiple of 5 minutes
|
// if the time range is greater than 1 day, and less than 1 week set the step interval to be multiple of 5 minutes
|
||||||
// if the time range is greater than 1 week, set the step interval to be multiple of 30 mins
|
// if the time range is greater than 1 week, set the step interval to be multiple of 30 mins
|
||||||
|
@ -1602,3 +1602,66 @@ func TestThresholdRuleLogsLink(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestThresholdRuleShiftBy(t *testing.T) {
|
||||||
|
target := float64(10)
|
||||||
|
postableRule := PostableRule{
|
||||||
|
AlertName: "Logs link test",
|
||||||
|
AlertType: AlertTypeLogs,
|
||||||
|
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: "component",
|
||||||
|
},
|
||||||
|
AggregateOperator: v3.AggregateOperatorCountDistinct,
|
||||||
|
DataSource: v3.DataSourceLogs,
|
||||||
|
Expression: "A",
|
||||||
|
Filters: &v3.FilterSet{
|
||||||
|
Operator: "AND",
|
||||||
|
Items: []v3.FilterItem{
|
||||||
|
{
|
||||||
|
Key: v3.AttributeKey{Key: "k8s.container.name", IsColumn: false, Type: v3.AttributeKeyTypeTag, DataType: v3.AttributeKeyDataTypeString},
|
||||||
|
Value: "testcontainer",
|
||||||
|
Operator: v3.FilterOperatorEqual,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Functions: []v3.Function{
|
||||||
|
{
|
||||||
|
Name: v3.FunctionNameTimeShift,
|
||||||
|
Args: []interface{}{float64(10)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Target: &target,
|
||||||
|
CompareOp: ValueAboveOrEq,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
rule, err := NewThresholdRule("69", &postableRule, nil, nil, true)
|
||||||
|
if err != nil {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
rule.TemporalityMap = map[string]map[v3.Temporality]bool{
|
||||||
|
"signoz_calls_total": {
|
||||||
|
v3.Delta: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
params, err := rule.prepareQueryRange(time.Now())
|
||||||
|
if err != nil {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, int64(10), params.CompositeQuery.BuilderQueries["A"].ShiftBy)
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user