2023-03-23 19:45:15 +05:30
package v3
import (
"fmt"
2023-12-29 12:35:22 +05:30
"math"
2023-03-23 19:45:15 +05:30
"strings"
2023-06-08 15:46:18 +05:30
"time"
2023-03-23 19:45:15 +05:30
2024-05-21 12:01:21 +05:30
"go.signoz.io/signoz/pkg/query-service/app/metrics/v4/helpers"
2023-03-23 19:45:15 +05:30
"go.signoz.io/signoz/pkg/query-service/constants"
2023-06-08 15:46:18 +05:30
"go.signoz.io/signoz/pkg/query-service/model"
2023-03-23 19:45:15 +05:30
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
"go.signoz.io/signoz/pkg/query-service/utils"
)
2023-08-18 07:32:05 +05:30
type Options struct {
PreferRPM bool
}
2023-03-23 19:45:15 +05:30
var aggregateOperatorToPercentile = map [ v3 . AggregateOperator ] float64 {
2023-04-07 09:46:21 +05:30
v3 . AggregateOperatorP05 : 0.05 ,
2023-03-23 19:45:15 +05:30
v3 . AggregateOperatorP10 : 0.10 ,
v3 . AggregateOperatorP20 : 0.20 ,
v3 . AggregateOperatorP25 : 0.25 ,
v3 . AggregateOperatorP50 : 0.50 ,
v3 . AggregateOperatorP75 : 0.75 ,
v3 . AggregateOperatorP90 : 0.90 ,
v3 . AggregateOperatorP95 : 0.95 ,
v3 . AggregateOperatorP99 : 0.99 ,
v3 . AggregateOperatorHistQuant50 : 0.50 ,
v3 . AggregateOperatorHistQuant75 : 0.75 ,
v3 . AggregateOperatorHistQuant90 : 0.90 ,
v3 . AggregateOperatorHistQuant95 : 0.95 ,
v3 . AggregateOperatorHistQuant99 : 0.99 ,
}
var aggregateOperatorToSQLFunc = map [ v3 . AggregateOperator ] string {
v3 . AggregateOperatorAvg : "avg" ,
v3 . AggregateOperatorMax : "max" ,
v3 . AggregateOperatorMin : "min" ,
v3 . AggregateOperatorSum : "sum" ,
v3 . AggregateOperatorRateSum : "sum" ,
v3 . AggregateOperatorRateAvg : "avg" ,
v3 . AggregateOperatorRateMax : "max" ,
v3 . AggregateOperatorRateMin : "min" ,
2023-07-03 13:30:37 +05:30
v3 . AggregateOperatorSumRate : "sum" ,
v3 . AggregateOperatorAvgRate : "avg" ,
v3 . AggregateOperatorMaxRate : "max" ,
v3 . AggregateOperatorMinRate : "min" ,
2023-03-23 19:45:15 +05:30
}
// See https://github.com/SigNoz/signoz/issues/2151#issuecomment-1467249056
2023-11-28 19:16:08 +05:30
var rateWithoutNegative = ` If((value - lagInFrame(value, 1, 0) OVER rate_window) < 0, nan, If((ts - lagInFrame(ts, 1, toDate('1970-01-01')) OVER rate_window) >= 86400, nan, (value - lagInFrame(value, 1, 0) OVER rate_window) / (ts - lagInFrame(ts, 1, toDate('1970-01-01')) OVER rate_window))) `
2023-03-23 19:45:15 +05:30
2024-05-21 12:01:21 +05:30
func buildMetricQuery ( start , end , step int64 , mq * v3 . BuilderQuery ) ( string , error ) {
2023-03-23 19:45:15 +05:30
2023-04-07 09:46:21 +05:30
metricQueryGroupBy := mq . GroupBy
2024-05-21 12:01:21 +05:30
filterSubQuery , err := helpers . PrepareTimeseriesFilterQueryV3 ( start , end , mq )
2023-03-23 19:45:15 +05:30
if err != nil {
return "" , err
}
2024-05-21 12:01:21 +05:30
samplesTableTimeFilter := fmt . Sprintf ( "metric_name = %s AND unix_milli >= %d AND unix_milli < %d" , utils . ClickHouseFormattedValue ( mq . AggregateAttribute . Key ) , start , end )
2023-03-23 19:45:15 +05:30
// Select the aggregate value for interval
queryTmpl :=
"SELECT %s" +
2024-05-21 12:01:21 +05:30
" toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL %d SECOND) as ts," +
2023-03-23 19:45:15 +05:30
" %s as value" +
2024-05-21 12:01:21 +05:30
" FROM " + constants . SIGNOZ_METRIC_DBNAME + "." + constants . SIGNOZ_SAMPLES_V4_TABLENAME +
2023-07-24 12:28:29 +05:30
" INNER JOIN" +
2023-03-23 19:45:15 +05:30
" (%s) as filtered_time_series" +
" USING fingerprint" +
" WHERE " + samplesTableTimeFilter +
" GROUP BY %s" +
" ORDER BY %s ts"
// tagsWithoutLe is used to group by all tags except le
// This is done because we want to group by le only when we are calculating quantile
// Otherwise, we want to group by all tags except le
tagsWithoutLe := [ ] string { }
for _ , tag := range mq . GroupBy {
if tag . Key != "le" {
tagsWithoutLe = append ( tagsWithoutLe , tag . Key )
}
}
groupByWithoutLe := groupBy ( tagsWithoutLe ... )
groupTagsWithoutLe := groupSelect ( tagsWithoutLe ... )
orderWithoutLe := orderBy ( mq . OrderBy , tagsWithoutLe )
2023-04-07 09:46:21 +05:30
groupBy := groupByAttributeKeyTags ( metricQueryGroupBy ... )
groupTags := groupSelectAttributeKeyTags ( metricQueryGroupBy ... )
2023-07-13 14:22:30 +05:30
groupSets := groupingSetsByAttributeKeyTags ( metricQueryGroupBy ... )
2023-04-07 09:46:21 +05:30
orderBy := orderByAttributeKeyTags ( mq . OrderBy , metricQueryGroupBy )
2023-03-23 19:45:15 +05:30
if len ( orderBy ) != 0 {
orderBy += ","
}
2023-04-07 09:46:21 +05:30
if len ( orderWithoutLe ) != 0 {
orderWithoutLe += ","
}
2023-03-23 19:45:15 +05:30
switch mq . AggregateOperator {
case v3 . AggregateOperatorRate :
// Calculate rate of change of metric for each unique time series
groupBy = "fingerprint, ts"
2023-04-07 09:46:21 +05:30
orderBy = "fingerprint, "
2023-03-23 19:45:15 +05:30
groupTags = "fingerprint,"
2023-11-28 19:16:08 +05:30
partitionBy := "fingerprint"
2023-03-23 19:45:15 +05:30
op := "max(value)" // max value should be the closest value for point in time
subQuery := fmt . Sprintf (
queryTmpl , "any(labels) as labels, " + groupTags , step , op , filterSubQuery , groupBy , orderBy ,
) // labels will be same so any should be fine
2023-11-28 19:16:08 +05:30
query := ` SELECT %s ts, ` + rateWithoutNegative + ` as value FROM(%s) WINDOW rate_window as (PARTITION BY %s ORDER BY %s ts) `
2023-03-23 19:45:15 +05:30
2023-11-28 19:16:08 +05:30
query = fmt . Sprintf ( query , "labels as fullLabels," , subQuery , partitionBy , orderBy )
2023-03-23 19:45:15 +05:30
return query , nil
2023-07-03 13:30:37 +05:30
case v3 . AggregateOperatorSumRate , v3 . AggregateOperatorAvgRate , v3 . AggregateOperatorMaxRate , v3 . AggregateOperatorMinRate :
2023-03-23 19:45:15 +05:30
rateGroupBy := "fingerprint, " + groupBy
rateGroupTags := "fingerprint, " + groupTags
rateOrderBy := "fingerprint, " + orderBy
2023-11-28 19:16:08 +05:30
partitionBy := "fingerprint"
if len ( groupTags ) != 0 {
partitionBy += ", " + groupTags
partitionBy = strings . Trim ( partitionBy , ", " )
}
2023-03-23 19:45:15 +05:30
op := "max(value)"
subQuery := fmt . Sprintf (
queryTmpl , rateGroupTags , step , op , filterSubQuery , rateGroupBy , rateOrderBy ,
) // labels will be same so any should be fine
2023-11-28 19:16:08 +05:30
query := ` SELECT %s ts, ` + rateWithoutNegative + ` as rate_value FROM(%s) WINDOW rate_window as (PARTITION BY %s ORDER BY %s ts) `
query = fmt . Sprintf ( query , groupTags , subQuery , partitionBy , rateOrderBy )
query = fmt . Sprintf ( ` SELECT %s ts, %s(rate_value) as value FROM (%s) WHERE isNaN(rate_value) = 0 GROUP BY %s ORDER BY %s ts ` , groupTags , aggregateOperatorToSQLFunc [ mq . AggregateOperator ] , query , groupSets , orderBy )
2023-03-23 19:45:15 +05:30
return query , nil
case
v3 . AggregateOperatorRateSum ,
v3 . AggregateOperatorRateMax ,
v3 . AggregateOperatorRateAvg ,
v3 . AggregateOperatorRateMin :
2023-11-28 19:16:08 +05:30
partitionBy := ""
if len ( groupTags ) != 0 {
partitionBy = "PARTITION BY " + groupTags
partitionBy = strings . Trim ( partitionBy , ", " )
}
2023-03-23 19:45:15 +05:30
op := fmt . Sprintf ( "%s(value)" , aggregateOperatorToSQLFunc [ mq . AggregateOperator ] )
2023-07-13 14:22:30 +05:30
subQuery := fmt . Sprintf ( queryTmpl , groupTags , step , op , filterSubQuery , groupSets , orderBy )
2023-11-28 19:16:08 +05:30
query := ` SELECT %s ts, ` + rateWithoutNegative + ` as value FROM(%s) WINDOW rate_window as (%s ORDER BY %s ts) `
query = fmt . Sprintf ( query , groupTags , subQuery , partitionBy , groupTags )
2023-03-23 19:45:15 +05:30
return query , nil
case
v3 . AggregateOperatorP05 ,
v3 . AggregateOperatorP10 ,
v3 . AggregateOperatorP20 ,
v3 . AggregateOperatorP25 ,
v3 . AggregateOperatorP50 ,
v3 . AggregateOperatorP75 ,
v3 . AggregateOperatorP90 ,
v3 . AggregateOperatorP95 ,
v3 . AggregateOperatorP99 :
op := fmt . Sprintf ( "quantile(%v)(value)" , aggregateOperatorToPercentile [ mq . AggregateOperator ] )
2023-07-13 14:22:30 +05:30
query := fmt . Sprintf ( queryTmpl , groupTags , step , op , filterSubQuery , groupSets , orderBy )
2023-03-23 19:45:15 +05:30
return query , nil
case v3 . AggregateOperatorHistQuant50 , v3 . AggregateOperatorHistQuant75 , v3 . AggregateOperatorHistQuant90 , v3 . AggregateOperatorHistQuant95 , v3 . AggregateOperatorHistQuant99 :
rateGroupBy := "fingerprint, " + groupBy
rateGroupTags := "fingerprint, " + groupTags
rateOrderBy := "fingerprint, " + orderBy
2023-11-28 19:16:08 +05:30
partitionBy := "fingerprint"
if len ( groupTags ) != 0 {
partitionBy += ", " + groupTags
partitionBy = strings . Trim ( partitionBy , ", " )
}
2023-03-23 19:45:15 +05:30
op := "max(value)"
subQuery := fmt . Sprintf (
queryTmpl , rateGroupTags , step , op , filterSubQuery , rateGroupBy , rateOrderBy ,
) // labels will be same so any should be fine
2023-11-28 19:16:08 +05:30
query := ` SELECT %s ts, ` + rateWithoutNegative + ` as rate_value FROM(%s) WINDOW rate_window as (PARTITION BY %s ORDER BY %s ts) `
query = fmt . Sprintf ( query , groupTags , subQuery , partitionBy , rateOrderBy )
query = fmt . Sprintf ( ` SELECT %s ts, sum(rate_value) as value FROM (%s) WHERE isNaN(rate_value) = 0 GROUP BY %s ORDER BY %s ts ` , groupTags , query , groupSets , orderBy )
2023-03-23 19:45:15 +05:30
value := aggregateOperatorToPercentile [ mq . AggregateOperator ]
query = fmt . Sprintf ( ` SELECT %s ts, histogramQuantile(arrayMap(x -> toFloat64(x), groupArray(le)), groupArray(value), %.3f) as value FROM (%s) GROUP BY %s ORDER BY %s ts ` , groupTagsWithoutLe , value , query , groupByWithoutLe , orderWithoutLe )
return query , nil
case v3 . AggregateOperatorAvg , v3 . AggregateOperatorSum , v3 . AggregateOperatorMin , v3 . AggregateOperatorMax :
op := fmt . Sprintf ( "%s(value)" , aggregateOperatorToSQLFunc [ mq . AggregateOperator ] )
2023-07-13 14:22:30 +05:30
query := fmt . Sprintf ( queryTmpl , groupTags , step , op , filterSubQuery , groupSets , orderBy )
2023-03-23 19:45:15 +05:30
return query , nil
2023-04-25 21:53:46 +05:30
case v3 . AggregateOperatorCount :
2023-03-23 19:45:15 +05:30
op := "toFloat64(count(*))"
2023-07-13 14:22:30 +05:30
query := fmt . Sprintf ( queryTmpl , groupTags , step , op , filterSubQuery , groupSets , orderBy )
2023-03-23 19:45:15 +05:30
return query , nil
case v3 . AggregateOperatorCountDistinct :
op := "toFloat64(count(distinct(value)))"
2023-07-13 14:22:30 +05:30
query := fmt . Sprintf ( queryTmpl , groupTags , step , op , filterSubQuery , groupSets , orderBy )
2023-03-23 19:45:15 +05:30
return query , nil
case v3 . AggregateOperatorNoOp :
queryTmpl :=
"SELECT fingerprint, labels as fullLabels," +
2024-05-21 12:01:21 +05:30
" toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL %d SECOND) as ts," +
2023-03-23 19:45:15 +05:30
" any(value) as value" +
2024-05-21 12:01:21 +05:30
" FROM " + constants . SIGNOZ_METRIC_DBNAME + "." + constants . SIGNOZ_SAMPLES_V4_TABLENAME +
2023-07-24 12:28:29 +05:30
" INNER JOIN" +
2023-03-23 19:45:15 +05:30
" (%s) as filtered_time_series" +
" USING fingerprint" +
" WHERE " + samplesTableTimeFilter +
" GROUP BY fingerprint, labels, ts" +
" ORDER BY fingerprint, labels, ts"
query := fmt . Sprintf ( queryTmpl , step , filterSubQuery )
return query , nil
default :
return "" , fmt . Errorf ( "unsupported aggregate operator" )
}
}
2023-07-13 14:22:30 +05:30
// groupingSets returns a string of comma separated tags for group by clause
// `ts` is always added to the group by clause
func groupingSets ( tags ... string ) string {
withTs := append ( tags , "ts" )
2024-06-05 19:33:45 +05:30
return strings . Join ( withTs , ", " )
2023-07-13 14:22:30 +05:30
}
2023-03-23 19:45:15 +05:30
// groupBy returns a string of comma separated tags for group by clause
// `ts` is always added to the group by clause
func groupBy ( tags ... string ) string {
tags = append ( tags , "ts" )
return strings . Join ( tags , "," )
}
// groupSelect returns a string of comma separated tags for select clause
func groupSelect ( tags ... string ) string {
groupTags := strings . Join ( tags , "," )
if len ( tags ) != 0 {
groupTags += ", "
}
return groupTags
}
2023-07-13 14:22:30 +05:30
func groupingSetsByAttributeKeyTags ( tags ... v3 . AttributeKey ) string {
groupTags := [ ] string { }
for _ , tag := range tags {
groupTags = append ( groupTags , tag . Key )
}
return groupingSets ( groupTags ... )
}
2023-03-23 19:45:15 +05:30
func groupByAttributeKeyTags ( tags ... v3 . AttributeKey ) string {
groupTags := [ ] string { }
for _ , tag := range tags {
groupTags = append ( groupTags , tag . Key )
}
return groupBy ( groupTags ... )
}
func groupSelectAttributeKeyTags ( tags ... v3 . AttributeKey ) string {
groupTags := [ ] string { }
for _ , tag := range tags {
groupTags = append ( groupTags , tag . Key )
}
return groupSelect ( groupTags ... )
}
// orderBy returns a string of comma separated tags for order by clause
// if the order is not specified, it defaults to ASC
func orderBy ( items [ ] v3 . OrderBy , tags [ ] string ) string {
var orderBy [ ] string
for _ , tag := range tags {
found := false
for _ , item := range items {
if item . ColumnName == tag {
found = true
orderBy = append ( orderBy , fmt . Sprintf ( "%s %s" , item . ColumnName , item . Order ) )
break
}
}
if ! found {
orderBy = append ( orderBy , fmt . Sprintf ( "%s ASC" , tag ) )
}
}
2023-07-13 14:22:30 +05:30
2023-03-23 19:45:15 +05:30
return strings . Join ( orderBy , "," )
}
func orderByAttributeKeyTags ( items [ ] v3 . OrderBy , tags [ ] v3 . AttributeKey ) string {
var groupTags [ ] string
for _ , tag := range tags {
groupTags = append ( groupTags , tag . Key )
}
return orderBy ( items , groupTags )
}
func having ( items [ ] v3 . Having ) string {
var having [ ] string
for _ , item := range items {
2023-05-12 16:25:22 +05:30
having = append ( having , fmt . Sprintf ( "%s %s %v" , "value" , item . Operator , utils . ClickHouseFormattedValue ( item . Value ) ) )
2023-03-23 19:45:15 +05:30
}
return strings . Join ( having , " AND " )
}
func reduceQuery ( query string , reduceTo v3 . ReduceToOperator , aggregateOperator v3 . AggregateOperator ) ( string , error ) {
var selectLabels string
var groupBy string
// NOOP and RATE can possibly return multiple time series and reduce should be applied
// for each uniques series. When the final result contains more than one series we throw
// an error post DB fetching. Otherwise just return the single data. This is not known until queried so the
// the query is prepared accordingly.
if aggregateOperator == v3 . AggregateOperatorNoOp || aggregateOperator == v3 . AggregateOperatorRate {
selectLabels = ", any(fullLabels) as fullLabels"
groupBy = "GROUP BY fingerprint"
}
// the timestamp picked is not relevant here since the final value used is show the single
// chart with just the query value. For the quer
switch reduceTo {
case v3 . ReduceToOperatorLast :
2023-12-27 19:25:24 +05:30
query = fmt . Sprintf ( "SELECT *, now() AS ts FROM (SELECT anyLastIf(value, toUnixTimestamp(ts) != 0) as value, anyIf(ts, toUnixTimestamp(ts) != 0) AS timestamp %s FROM (%s) %s)" , selectLabels , query , groupBy )
2023-03-23 19:45:15 +05:30
case v3 . ReduceToOperatorSum :
2023-12-27 19:25:24 +05:30
query = fmt . Sprintf ( "SELECT *, now() AS ts FROM (SELECT sumIf(value, toUnixTimestamp(ts) != 0) as value, anyIf(ts, toUnixTimestamp(ts) != 0) AS timestamp %s FROM (%s) %s)" , selectLabels , query , groupBy )
2023-03-23 19:45:15 +05:30
case v3 . ReduceToOperatorAvg :
2023-12-27 19:25:24 +05:30
query = fmt . Sprintf ( "SELECT *, now() AS ts FROM (SELECT avgIf(value, toUnixTimestamp(ts) != 0) as value, anyIf(ts, toUnixTimestamp(ts) != 0) AS timestamp %s FROM (%s) %s)" , selectLabels , query , groupBy )
2023-03-23 19:45:15 +05:30
case v3 . ReduceToOperatorMax :
2023-12-27 19:25:24 +05:30
query = fmt . Sprintf ( "SELECT *, now() AS ts FROM (SELECT maxIf(value, toUnixTimestamp(ts) != 0) as value, anyIf(ts, toUnixTimestamp(ts) != 0) AS timestamp %s FROM (%s) %s)" , selectLabels , query , groupBy )
2023-03-23 19:45:15 +05:30
case v3 . ReduceToOperatorMin :
2023-12-27 19:25:24 +05:30
query = fmt . Sprintf ( "SELECT *, now() AS ts FROM (SELECT minIf(value, toUnixTimestamp(ts) != 0) as value, anyIf(ts, toUnixTimestamp(ts) != 0) AS timestamp %s FROM (%s) %s)" , selectLabels , query , groupBy )
2023-03-23 19:45:15 +05:30
default :
return "" , fmt . Errorf ( "unsupported reduce operator" )
}
return query , nil
}
2023-08-22 17:09:58 +05:30
// PrepareMetricQuery prepares the query to be used for fetching metrics
// from the database
// start and end are in milliseconds
// step is in seconds
2023-08-18 07:32:05 +05:30
func PrepareMetricQuery ( start , end int64 , queryType v3 . QueryType , panelType v3 . PanelType , mq * v3 . BuilderQuery , options Options ) ( string , error ) {
2023-08-22 17:09:58 +05:30
start = start - ( start % ( mq . StepInterval * 1000 ) )
2023-12-29 12:35:22 +05:30
// if the query is a rate query, we adjust the start time by one more step
// so that we can calculate the rate for the first data point
if mq . AggregateOperator . IsRateOperator ( ) && mq . Temporality != v3 . Delta {
start -= mq . StepInterval * 1000
}
adjustStep := int64 ( math . Min ( float64 ( mq . StepInterval ) , 60 ) )
end = end - ( end % ( adjustStep * 1000 ) )
2023-08-22 17:09:58 +05:30
2024-05-24 12:11:34 +05:30
// if the aggregate operator is a histogram quantile, and user has not forgotten
// the le tag in the group by then add the le tag to the group by
if mq . AggregateOperator == v3 . AggregateOperatorHistQuant50 ||
mq . AggregateOperator == v3 . AggregateOperatorHistQuant75 ||
mq . AggregateOperator == v3 . AggregateOperatorHistQuant90 ||
mq . AggregateOperator == v3 . AggregateOperatorHistQuant95 ||
mq . AggregateOperator == v3 . AggregateOperatorHistQuant99 {
found := false
for _ , tag := range mq . GroupBy {
if tag . Key == "le" {
found = true
break
}
}
if ! found {
mq . GroupBy = append (
mq . GroupBy ,
v3 . AttributeKey {
Key : "le" ,
DataType : v3 . AttributeKeyDataTypeString ,
Type : v3 . AttributeKeyTypeTag ,
IsColumn : false ,
} ,
)
}
}
2023-07-13 18:50:19 +05:30
var query string
var err error
if mq . Temporality == v3 . Delta {
2023-07-17 21:08:54 +05:30
if panelType == v3 . PanelTypeTable {
2024-05-21 12:01:21 +05:30
query , err = buildDeltaMetricQueryForTable ( start , end , mq . StepInterval , mq )
2023-07-17 21:08:54 +05:30
} else {
2024-05-21 12:01:21 +05:30
query , err = buildDeltaMetricQuery ( start , end , mq . StepInterval , mq )
2023-07-17 21:08:54 +05:30
}
2023-07-13 18:50:19 +05:30
} else {
2023-07-17 21:08:54 +05:30
if panelType == v3 . PanelTypeTable {
2024-05-21 12:01:21 +05:30
query , err = buildMetricQueryForTable ( start , end , mq . StepInterval , mq )
2023-07-17 21:08:54 +05:30
} else {
2024-05-21 12:01:21 +05:30
query , err = buildMetricQuery ( start , end , mq . StepInterval , mq )
2023-07-17 21:08:54 +05:30
}
2023-07-13 18:50:19 +05:30
}
2023-08-18 07:32:05 +05:30
2023-03-23 19:45:15 +05:30
if err != nil {
return "" , err
}
2023-08-18 07:32:05 +05:30
if options . PreferRPM && ( mq . AggregateOperator == v3 . AggregateOperatorRate ||
mq . AggregateOperator == v3 . AggregateOperatorSumRate ||
mq . AggregateOperator == v3 . AggregateOperatorAvgRate ||
mq . AggregateOperator == v3 . AggregateOperatorMaxRate ||
mq . AggregateOperator == v3 . AggregateOperatorMinRate ||
mq . AggregateOperator == v3 . AggregateOperatorRateSum ||
mq . AggregateOperator == v3 . AggregateOperatorRateAvg ||
mq . AggregateOperator == v3 . AggregateOperatorRateMax ||
mq . AggregateOperator == v3 . AggregateOperatorRateMin ) {
var selectLabels string
if mq . AggregateOperator == v3 . AggregateOperatorRate {
selectLabels = "fullLabels,"
} else {
selectLabels = groupSelectAttributeKeyTags ( mq . GroupBy ... )
}
query = ` SELECT ` + selectLabels + ` ts, ceil(value * 60) as value FROM ( ` + query + ` ) `
}
2023-05-12 16:25:22 +05:30
if having ( mq . Having ) != "" {
query = fmt . Sprintf ( "SELECT * FROM (%s) HAVING %s" , query , having ( mq . Having ) )
}
2023-03-23 19:45:15 +05:30
if panelType == v3 . PanelTypeValue {
query , err = reduceQuery ( query , mq . ReduceTo , mq . AggregateOperator )
}
return query , err
}
2023-06-08 15:46:18 +05:30
func BuildPromQuery ( promQuery * v3 . PromQuery , step , start , end int64 ) * model . QueryRangeParams {
return & model . QueryRangeParams {
Query : promQuery . Query ,
Start : time . UnixMilli ( start ) ,
End : time . UnixMilli ( end ) ,
Step : time . Duration ( step * int64 ( time . Second ) ) ,
}
}