2024-06-11 19:58:52 +05:30
package postprocess
import (
"github.com/SigNoz/govaluate"
2025-03-20 21:01:41 +05:30
"github.com/SigNoz/signoz/pkg/query-service/common"
v3 "github.com/SigNoz/signoz/pkg/query-service/model/v3"
2024-06-11 19:58:52 +05:30
)
2024-06-12 12:21:27 +05:30
func StepIntervalForFunction ( params * v3 . QueryRangeParamsV3 , query string ) int64 {
2024-06-11 19:58:52 +05:30
q := params . CompositeQuery . BuilderQueries [ query ]
if q . QueryName != q . Expression {
expression , _ := govaluate . NewEvaluableExpressionWithFunctions ( q . Expression , EvalFuncs ( ) )
steps := [ ] int64 { }
for _ , v := range expression . Vars ( ) {
steps = append ( steps , params . CompositeQuery . BuilderQueries [ v ] . StepInterval )
}
return common . LCMList ( steps )
}
return q . StepInterval
}
2025-05-23 09:33:47 +05:30
func fillGap ( series * v3 . Series , start , end , step , shiftBy int64 ) * v3 . Series {
2024-06-11 19:58:52 +05:30
v := make ( map [ int64 ] float64 )
for _ , point := range series . Points {
v [ point . Timestamp ] = point . Value
}
// For all the values from start to end, find the timestamps
// that don't have value and add zero point
start = start - ( start % ( step * 1000 ) )
2025-05-23 09:33:47 +05:30
start += shiftBy * 1000
end += shiftBy * 1000
2024-06-11 19:58:52 +05:30
for i := start ; i <= end ; i += step * 1000 {
if _ , ok := v [ i ] ; ! ok {
v [ i ] = 0
}
}
newSeries := & v3 . Series {
Labels : series . Labels ,
LabelsArray : series . LabelsArray ,
Points : make ( [ ] v3 . Point , 0 ) ,
}
for i := start ; i <= end ; i += step * 1000 {
newSeries . Points = append ( newSeries . Points , v3 . Point { Timestamp : i , Value : v [ i ] } )
}
return newSeries
}
// TODO(srikanthccv): can WITH FILL be perfect substitute for all cases https://clickhouse.com/docs/en/sql-reference/statements/select/order-by#order-by-expr-with-fill-modifier
func FillGaps ( results [ ] * v3 . Result , params * v3 . QueryRangeParamsV3 ) {
2024-07-01 14:06:28 +05:30
if params . CompositeQuery . PanelType != v3 . PanelTypeGraph {
return
}
2024-06-11 19:58:52 +05:30
for _ , result := range results {
// A `result` item in `results` contains the query result for individual query.
// If there are no series in the result, we add empty series and `fillGap` adds all zeros
if len ( result . Series ) == 0 {
result . Series = [ ] * v3 . Series {
{
Labels : make ( map [ string ] string ) ,
LabelsArray : make ( [ ] map [ string ] string , 0 ) ,
} ,
}
}
builderQueries := params . CompositeQuery . BuilderQueries
if builderQueries != nil {
// The values should be added at the intervals of `step`
2024-06-12 12:21:27 +05:30
step := StepIntervalForFunction ( params , result . QueryName )
2025-05-23 09:33:47 +05:30
shiftBy := builderQueries [ result . QueryName ] . ShiftBy
start := params . Start - shiftBy * 1000
end := params . End - shiftBy * 1000
2024-06-11 19:58:52 +05:30
for idx := range result . Series {
2025-05-23 09:33:47 +05:30
result . Series [ idx ] = fillGap ( result . Series [ idx ] , start , end , step , shiftBy )
2024-06-11 19:58:52 +05:30
}
}
}
}