Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add total count and state filter #5745

Merged
merged 2 commits into from
Aug 23, 2024
Merged

Conversation

srikanthccv
Copy link
Member

Summary

@ahmadshaheer highlighted few things to be addressed

  1. if currentAvgResolutionTime or pastAvgResolutionTime in invalid change them to 0
  2. Add a state filter in the timeline API
  3. Add the total count of rows in the timeline API
  4. Add links for explorer pages

The first three changes are simple and need minimal change. The links to related logs and traces are the same as the ones we have here so there is no major logic change but minor changes that don't apply to alers. I created a todo item for myself to combine them the

// The following function is used to prepare the where clause for the query
// `lbls` contains the key value pairs of the labels from the result of the query
// We iterate over the where clause and replace the labels with the actual values
// There are two cases:
// 1. The label is present in the where clause
// 2. The label is not present in the where clause
//
// Example for case 2:
// Latency by serviceName without any filter
// In this case, for each service with latency > threshold we send a notification
// The expectation will be that clicking on the related traces for service A, will
// take us to the traces page with the filter serviceName=A
// So for all the missing labels in the where clause, we add them as key = value
//
// Example for case 1:
// Severity text IN (WARN, ERROR)
// In this case, the Severity text will appear in the `lbls` if it were part of the group
// by clause, in which case we replace it with the actual value for the notification
// i.e Severity text = WARN
// If the Severity text is not part of the group by clause, then we add it as it is
func (r *ThresholdRule) fetchFilters(selectedQuery string, lbls labels.Labels) []v3.FilterItem {
var filterItems []v3.FilterItem
added := make(map[string]struct{})
if r.ruleCondition.CompositeQuery.QueryType == v3.QueryTypeBuilder &&
r.ruleCondition.CompositeQuery.BuilderQueries[selectedQuery] != nil &&
r.ruleCondition.CompositeQuery.BuilderQueries[selectedQuery].Filters != nil {
for _, item := range r.ruleCondition.CompositeQuery.BuilderQueries[selectedQuery].Filters.Items {
exists := false
for _, label := range lbls {
if item.Key.Key == label.Name {
// if the label is present in the where clause, replace it with key = value
filterItems = append(filterItems, v3.FilterItem{
Key: item.Key,
Operator: v3.FilterOperatorEqual,
Value: label.Value,
})
exists = true
added[label.Name] = struct{}{}
break
}
}
if !exists {
// if the label is not present in the where clause, add it as it is
filterItems = append(filterItems, item)
}
}
}
// add the labels which are not present in the where clause
for _, label := range lbls {
if _, ok := added[label.Name]; !ok {
filterItems = append(filterItems, v3.FilterItem{
Key: v3.AttributeKey{Key: label.Name},
Operator: v3.FilterOperatorEqual,
Value: label.Value,
})
}
}
return filterItems
}
func (r *ThresholdRule) prepareLinksToLogs(ts time.Time, lbls labels.Labels) string {
selectedQuery := r.GetSelectedQuery()
// TODO(srikanthccv): handle formula queries
if selectedQuery < "A" || selectedQuery > "Z" {
return ""
}
q := r.prepareQueryRange(ts)
// Logs list view expects time in milliseconds
tr := timeRange{
Start: q.Start,
End: q.End,
PageSize: 100,
}
options := Options{
MaxLines: 2,
Format: "list",
SelectColumns: []v3.AttributeKey{},
}
period, _ := json.Marshal(tr)
urlEncodedTimeRange := url.QueryEscape(string(period))
filterItems := r.fetchFilters(selectedQuery, lbls)
urlData := urlShareableCompositeQuery{
QueryType: string(v3.QueryTypeBuilder),
Builder: builderQuery{
QueryData: []v3.BuilderQuery{
{
DataSource: v3.DataSourceLogs,
QueryName: "A",
AggregateOperator: v3.AggregateOperatorNoOp,
AggregateAttribute: v3.AttributeKey{},
Filters: &v3.FilterSet{
Items: filterItems,
Operator: "AND",
},
Expression: "A",
Disabled: false,
Having: []v3.Having{},
StepInterval: 60,
OrderBy: []v3.OrderBy{
{
ColumnName: "timestamp",
Order: "desc",
},
},
},
},
QueryFormulas: make([]string, 0),
},
}
data, _ := json.Marshal(urlData)
compositeQuery := url.QueryEscape(string(data))
optionsData, _ := json.Marshal(options)
urlEncodedOptions := url.QueryEscape(string(optionsData))
return fmt.Sprintf("compositeQuery=%s&timeRange=%s&startTime=%d&endTime=%d&options=%s", compositeQuery, urlEncodedTimeRange, tr.Start, tr.End, urlEncodedOptions)
}
func (r *ThresholdRule) prepareLinksToTraces(ts time.Time, lbls labels.Labels) string {
selectedQuery := r.GetSelectedQuery()
// TODO(srikanthccv): handle formula queries
if selectedQuery < "A" || selectedQuery > "Z" {
return ""
}
q := r.prepareQueryRange(ts)
// Traces list view expects time in nanoseconds
tr := timeRange{
Start: q.Start * time.Second.Microseconds(),
End: q.End * time.Second.Microseconds(),
PageSize: 100,
}
options := Options{
MaxLines: 2,
Format: "list",
SelectColumns: constants.TracesListViewDefaultSelectedColumns,
}
period, _ := json.Marshal(tr)
urlEncodedTimeRange := url.QueryEscape(string(period))
filterItems := r.fetchFilters(selectedQuery, lbls)
urlData := urlShareableCompositeQuery{
QueryType: string(v3.QueryTypeBuilder),
Builder: builderQuery{
QueryData: []v3.BuilderQuery{
{
DataSource: v3.DataSourceTraces,
QueryName: "A",
AggregateOperator: v3.AggregateOperatorNoOp,
AggregateAttribute: v3.AttributeKey{},
Filters: &v3.FilterSet{
Items: filterItems,
Operator: "AND",
},
Expression: "A",
Disabled: false,
Having: []v3.Having{},
StepInterval: 60,
OrderBy: []v3.OrderBy{
{
ColumnName: "timestamp",
Order: "desc",
},
},
},
},
QueryFormulas: make([]string, 0),
},
}
data, _ := json.Marshal(urlData)
compositeQuery := url.QueryEscape(string(data))
optionsData, _ := json.Marshal(options)
urlEncodedOptions := url.QueryEscape(string(optionsData))
return fmt.Sprintf("compositeQuery=%s&timeRange=%s&startTime=%d&endTime=%d&options=%s", compositeQuery, urlEncodedTimeRange, tr.Start, tr.End, urlEncodedOptions)
}

Copy link

Build Error! No Linked Issue found. Please link an issue or mention it in the body using #<issue_id>

@srikanthccv srikanthccv merged commit b798518 into develop Aug 23, 2024
10 of 12 checks passed
@srikanthccv srikanthccv deleted the gaps-rule-history branch August 23, 2024 15:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants