mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-14 14:35:56 +08:00
feat: metric attribute autocomplete for the aggregation type (#2263)
This commit is contained in:
parent
e3fee332c7
commit
6defa0ac8b
@ -231,6 +231,7 @@ func (s *Server) createPublicServer(apiHandler *api.APIHandler) (*http.Server, e
|
|||||||
apiHandler.RegisterRoutes(r, am)
|
apiHandler.RegisterRoutes(r, am)
|
||||||
apiHandler.RegisterMetricsRoutes(r, am)
|
apiHandler.RegisterMetricsRoutes(r, am)
|
||||||
apiHandler.RegisterLogsRoutes(r, am)
|
apiHandler.RegisterLogsRoutes(r, am)
|
||||||
|
apiHandler.RegisterQueryRangeV3Routes(r, am)
|
||||||
|
|
||||||
c := cors.New(cors.Options{
|
c := cors.New(cors.Options{
|
||||||
AllowedOrigins: []string{"*"},
|
AllowedOrigins: []string{"*"},
|
||||||
|
@ -45,6 +45,7 @@ import (
|
|||||||
am "go.signoz.io/signoz/pkg/query-service/integrations/alertManager"
|
am "go.signoz.io/signoz/pkg/query-service/integrations/alertManager"
|
||||||
"go.signoz.io/signoz/pkg/query-service/interfaces"
|
"go.signoz.io/signoz/pkg/query-service/interfaces"
|
||||||
"go.signoz.io/signoz/pkg/query-service/model"
|
"go.signoz.io/signoz/pkg/query-service/model"
|
||||||
|
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||||||
"go.signoz.io/signoz/pkg/query-service/telemetry"
|
"go.signoz.io/signoz/pkg/query-service/telemetry"
|
||||||
"go.signoz.io/signoz/pkg/query-service/utils"
|
"go.signoz.io/signoz/pkg/query-service/utils"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
@ -3654,6 +3655,41 @@ func (r *ClickHouseReader) QueryDashboardVars(ctx context.Context, query string)
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *ClickHouseReader) GetMetricAggregateAttributes(ctx context.Context, req *v3.AggregateAttributeRequest) (*v3.AggregateAttributeResponse, error) {
|
||||||
|
|
||||||
|
var query string
|
||||||
|
var err error
|
||||||
|
var rows driver.Rows
|
||||||
|
var response v3.AggregateAttributeResponse
|
||||||
|
|
||||||
|
query = fmt.Sprintf("SELECT DISTINCT(metric_name) from %s.%s WHERE metric_name ILIKE $1", signozMetricDBName, signozTSTableName)
|
||||||
|
if req.Limit != 0 {
|
||||||
|
query = query + fmt.Sprintf(" LIMIT %d;", req.Limit)
|
||||||
|
}
|
||||||
|
rows, err = r.db.Query(ctx, query, fmt.Sprintf("%%%s%%", req.SearchText))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
zap.S().Error(err)
|
||||||
|
return nil, fmt.Errorf("error while executing query: %s", err.Error())
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var metricName string
|
||||||
|
for rows.Next() {
|
||||||
|
if err := rows.Scan(&metricName); err != nil {
|
||||||
|
return nil, fmt.Errorf("error while scanning rows: %s", err.Error())
|
||||||
|
}
|
||||||
|
key := v3.AttributeKey{
|
||||||
|
Key: metricName,
|
||||||
|
DataType: v3.AttributeKeyDataTypeNumber,
|
||||||
|
Type: v3.AttributeKeyTypeTag,
|
||||||
|
}
|
||||||
|
response.AttributeKeys = append(response.AttributeKeys, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &response, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *ClickHouseReader) CheckClickHouse(ctx context.Context) error {
|
func (r *ClickHouseReader) CheckClickHouse(ctx context.Context) error {
|
||||||
rows, err := r.db.Query(ctx, "SELECT 1")
|
rows, err := r.db.Query(ctx, "SELECT 1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
"go.signoz.io/signoz/pkg/query-service/app/parser"
|
"go.signoz.io/signoz/pkg/query-service/app/parser"
|
||||||
"go.signoz.io/signoz/pkg/query-service/auth"
|
"go.signoz.io/signoz/pkg/query-service/auth"
|
||||||
"go.signoz.io/signoz/pkg/query-service/constants"
|
"go.signoz.io/signoz/pkg/query-service/constants"
|
||||||
|
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||||||
querytemplate "go.signoz.io/signoz/pkg/query-service/utils/queryTemplate"
|
querytemplate "go.signoz.io/signoz/pkg/query-service/utils/queryTemplate"
|
||||||
|
|
||||||
"go.signoz.io/signoz/pkg/query-service/dao"
|
"go.signoz.io/signoz/pkg/query-service/dao"
|
||||||
@ -237,6 +238,11 @@ func (aH *APIHandler) RegisterMetricsRoutes(router *mux.Router, am *AuthMiddlewa
|
|||||||
subRouter.HandleFunc("/autocomplete/tagValue", am.ViewAccess(aH.metricAutocompleteTagValue)).Methods(http.MethodGet)
|
subRouter.HandleFunc("/autocomplete/tagValue", am.ViewAccess(aH.metricAutocompleteTagValue)).Methods(http.MethodGet)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (aH *APIHandler) RegisterQueryRangeV3Routes(router *mux.Router, am *AuthMiddleware) {
|
||||||
|
subRouter := router.PathPrefix("/api/v3").Subrouter()
|
||||||
|
subRouter.HandleFunc("/autocomplete/aggregate_attributes", am.ViewAccess(aH.autocompleteAggregateAttributes)).Methods(http.MethodGet)
|
||||||
|
}
|
||||||
|
|
||||||
func (aH *APIHandler) Respond(w http.ResponseWriter, data interface{}) {
|
func (aH *APIHandler) Respond(w http.ResponseWriter, data interface{}) {
|
||||||
writeHttpResponse(w, data)
|
writeHttpResponse(w, data)
|
||||||
}
|
}
|
||||||
@ -2246,3 +2252,32 @@ func (aH *APIHandler) logAggregate(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
aH.WriteJSON(w, r, res)
|
aH.WriteJSON(w, r, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (aH *APIHandler) autocompleteAggregateAttributes(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var response *v3.AggregateAttributeResponse
|
||||||
|
req, err := parseAggregateAttributeRequest(r)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: err}, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch req.DataSource {
|
||||||
|
case v3.DataSourceMetrics:
|
||||||
|
response, err = aH.reader.GetMetricAggregateAttributes(r.Context(), req)
|
||||||
|
case v3.DataSourceLogs:
|
||||||
|
// TODO: implement
|
||||||
|
case v3.DataSourceTraces:
|
||||||
|
// TODO: implement
|
||||||
|
default:
|
||||||
|
RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: fmt.Errorf("invalid data source")}, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: err}, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
aH.Respond(w, response)
|
||||||
|
}
|
||||||
|
@ -16,6 +16,7 @@ import (
|
|||||||
"go.signoz.io/signoz/pkg/query-service/auth"
|
"go.signoz.io/signoz/pkg/query-service/auth"
|
||||||
"go.signoz.io/signoz/pkg/query-service/constants"
|
"go.signoz.io/signoz/pkg/query-service/constants"
|
||||||
"go.signoz.io/signoz/pkg/query-service/model"
|
"go.signoz.io/signoz/pkg/query-service/model"
|
||||||
|
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var allowedFunctions = []string{"count", "ratePerSec", "sum", "avg", "min", "max", "p50", "p90", "p95", "p99"}
|
var allowedFunctions = []string{"count", "ratePerSec", "sum", "avg", "min", "max", "p50", "p90", "p95", "p99"}
|
||||||
@ -412,11 +413,11 @@ func extractTagKeys(tags []model.TagQueryParam) ([]model.TagQueryParam, error) {
|
|||||||
tag.Key = customStr[0]
|
tag.Key = customStr[0]
|
||||||
}
|
}
|
||||||
if tag.Operator == model.ExistsOperator || tag.Operator == model.NotExistsOperator {
|
if tag.Operator == model.ExistsOperator || tag.Operator == model.NotExistsOperator {
|
||||||
if customStr[1] == string(model.TagTypeString) + ")" {
|
if customStr[1] == string(model.TagTypeString)+")" {
|
||||||
tag.StringValues = []string{" "}
|
tag.StringValues = []string{" "}
|
||||||
} else if customStr[1] ==string(model.TagTypeBool) + ")" {
|
} else if customStr[1] == string(model.TagTypeBool)+")" {
|
||||||
tag.BoolValues = []bool{true}
|
tag.BoolValues = []bool{true}
|
||||||
} else if customStr[1] == string(model.TagTypeNumber) + ")" {
|
} else if customStr[1] == string(model.TagTypeNumber)+")" {
|
||||||
tag.NumberValues = []float64{0}
|
tag.NumberValues = []float64{0}
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("TagKey param is not valid in query")
|
return nil, fmt.Errorf("TagKey param is not valid in query")
|
||||||
@ -811,3 +812,32 @@ func parseFilterSet(r *http.Request) (*model.FilterSet, error) {
|
|||||||
}
|
}
|
||||||
return &filterSet, nil
|
return &filterSet, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseAggregateAttributeRequest(r *http.Request) (*v3.AggregateAttributeRequest, error) {
|
||||||
|
var req v3.AggregateAttributeRequest
|
||||||
|
|
||||||
|
aggregateOperator := v3.AggregateOperator(r.URL.Query().Get("aggregateOperator"))
|
||||||
|
dataSource := v3.DataSource(r.URL.Query().Get("dataSource"))
|
||||||
|
aggregateAttribute := r.URL.Query().Get("searchText")
|
||||||
|
|
||||||
|
limit, err := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||||
|
if err != nil {
|
||||||
|
limit = 50
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := aggregateOperator.Validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := dataSource.Validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req = v3.AggregateAttributeRequest{
|
||||||
|
Operator: aggregateOperator,
|
||||||
|
SearchText: aggregateAttribute,
|
||||||
|
Limit: limit,
|
||||||
|
DataSource: dataSource,
|
||||||
|
}
|
||||||
|
return &req, nil
|
||||||
|
}
|
||||||
|
@ -3,13 +3,16 @@ package app
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/smartystreets/assertions/should"
|
"github.com/smartystreets/assertions/should"
|
||||||
|
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
"go.signoz.io/signoz/pkg/query-service/app/metrics"
|
"go.signoz.io/signoz/pkg/query-service/app/metrics"
|
||||||
"go.signoz.io/signoz/pkg/query-service/model"
|
"go.signoz.io/signoz/pkg/query-service/model"
|
||||||
|
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParseFilterSingleFilter(t *testing.T) {
|
func TestParseFilterSingleFilter(t *testing.T) {
|
||||||
@ -58,3 +61,89 @@ func TestParseFilterNotSupportedOp(t *testing.T) {
|
|||||||
So(err, should.BeError, "unsupported operation")
|
So(err, should.BeError, "unsupported operation")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseAggregateAttrReques(t *testing.T) {
|
||||||
|
reqCases := []struct {
|
||||||
|
desc string
|
||||||
|
queryString string
|
||||||
|
expectedOperator v3.AggregateOperator
|
||||||
|
expectedDataSource v3.DataSource
|
||||||
|
expectedLimit int
|
||||||
|
expectedSearchText string
|
||||||
|
expectErr bool
|
||||||
|
errMsg string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "valid operator and data source",
|
||||||
|
queryString: "aggregateOperator=sum&dataSource=metrics&searchText=abc",
|
||||||
|
expectedOperator: v3.AggregateOperatorSum,
|
||||||
|
expectedDataSource: v3.DataSourceMetrics,
|
||||||
|
expectedLimit: 50,
|
||||||
|
expectedSearchText: "abc",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "different valid operator and data source as logs",
|
||||||
|
queryString: "aggregateOperator=avg&dataSource=logs&searchText=abc",
|
||||||
|
expectedOperator: v3.AggregateOperatorAvg,
|
||||||
|
expectedDataSource: v3.DataSourceLogs,
|
||||||
|
expectedLimit: 50,
|
||||||
|
expectedSearchText: "abc",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "different valid operator and with default search text and limit",
|
||||||
|
queryString: "aggregateOperator=avg&dataSource=metrics",
|
||||||
|
expectedOperator: v3.AggregateOperatorAvg,
|
||||||
|
expectedDataSource: v3.DataSourceMetrics,
|
||||||
|
expectedLimit: 50,
|
||||||
|
expectedSearchText: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "valid operator and data source with limit",
|
||||||
|
queryString: "aggregateOperator=avg&dataSource=traces&limit=10",
|
||||||
|
expectedOperator: v3.AggregateOperatorAvg,
|
||||||
|
expectedDataSource: v3.DataSourceTraces,
|
||||||
|
expectedLimit: 10,
|
||||||
|
expectedSearchText: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "invalid operator",
|
||||||
|
queryString: "aggregateOperator=avg1&dataSource=traces&limit=10",
|
||||||
|
expectErr: true,
|
||||||
|
errMsg: "invalid operator",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "invalid data source",
|
||||||
|
queryString: "aggregateOperator=avg&dataSource=traces1&limit=10",
|
||||||
|
expectErr: true,
|
||||||
|
errMsg: "invalid data source",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "invalid limit",
|
||||||
|
queryString: "aggregateOperator=avg&dataSource=traces&limit=abc",
|
||||||
|
expectedOperator: v3.AggregateOperatorAvg,
|
||||||
|
expectedDataSource: v3.DataSourceTraces,
|
||||||
|
expectedLimit: 50,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, reqCase := range reqCases {
|
||||||
|
r := httptest.NewRequest("GET", "/api/v3/autocomplete/aggregate_attributes?"+reqCase.queryString, nil)
|
||||||
|
aggregateAttrRequest, err := parseAggregateAttributeRequest(r)
|
||||||
|
if reqCase.expectErr {
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("expected error: %s", reqCase.errMsg)
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(), reqCase.errMsg) {
|
||||||
|
t.Errorf("expected error to contain: %s, got: %s", reqCase.errMsg, err.Error())
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
assert.Equal(t, reqCase.expectedOperator, aggregateAttrRequest.Operator)
|
||||||
|
assert.Equal(t, reqCase.expectedDataSource, aggregateAttrRequest.DataSource)
|
||||||
|
assert.Equal(t, reqCase.expectedLimit, aggregateAttrRequest.Limit)
|
||||||
|
assert.Equal(t, reqCase.expectedSearchText, aggregateAttrRequest.SearchText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -182,6 +182,7 @@ func (s *Server) createPublicServer(api *APIHandler) (*http.Server, error) {
|
|||||||
api.RegisterRoutes(r, am)
|
api.RegisterRoutes(r, am)
|
||||||
api.RegisterMetricsRoutes(r, am)
|
api.RegisterMetricsRoutes(r, am)
|
||||||
api.RegisterLogsRoutes(r, am)
|
api.RegisterLogsRoutes(r, am)
|
||||||
|
api.RegisterQueryRangeV3Routes(r, am)
|
||||||
|
|
||||||
c := cors.New(cors.Options{
|
c := cors.New(cors.Options{
|
||||||
AllowedOrigins: []string{"*"},
|
AllowedOrigins: []string{"*"},
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/prometheus/prometheus/util/stats"
|
"github.com/prometheus/prometheus/util/stats"
|
||||||
am "go.signoz.io/signoz/pkg/query-service/integrations/alertManager"
|
am "go.signoz.io/signoz/pkg/query-service/integrations/alertManager"
|
||||||
"go.signoz.io/signoz/pkg/query-service/model"
|
"go.signoz.io/signoz/pkg/query-service/model"
|
||||||
|
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Reader interface {
|
type Reader interface {
|
||||||
@ -56,6 +57,7 @@ type Reader interface {
|
|||||||
GetMetricAutocompleteTagValue(ctx context.Context, params *model.MetricAutocompleteTagParams) (*[]string, *model.ApiError)
|
GetMetricAutocompleteTagValue(ctx context.Context, params *model.MetricAutocompleteTagParams) (*[]string, *model.ApiError)
|
||||||
GetMetricResult(ctx context.Context, query string) ([]*model.Series, error)
|
GetMetricResult(ctx context.Context, query string) ([]*model.Series, error)
|
||||||
GetMetricResultEE(ctx context.Context, query string) ([]*model.Series, string, error)
|
GetMetricResultEE(ctx context.Context, query string) ([]*model.Series, string, error)
|
||||||
|
GetMetricAggregateAttributes(ctx context.Context, req *v3.AggregateAttributeRequest) (*v3.AggregateAttributeResponse, error)
|
||||||
|
|
||||||
GetTotalSpans(ctx context.Context) (uint64, error)
|
GetTotalSpans(ctx context.Context) (uint64, error)
|
||||||
GetSpansInLastHeartBeatInterval(ctx context.Context) (uint64, error)
|
GetSpansInLastHeartBeatInterval(ctx context.Context) (uint64, error)
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package v3
|
package v3
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
type DataSource string
|
type DataSource string
|
||||||
|
|
||||||
@ -10,6 +13,15 @@ const (
|
|||||||
DataSourceMetrics DataSource = "metrics"
|
DataSourceMetrics DataSource = "metrics"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (d DataSource) Validate() error {
|
||||||
|
switch d {
|
||||||
|
case DataSourceTraces, DataSourceLogs, DataSourceMetrics:
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid data source: %s", d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type AggregateOperator string
|
type AggregateOperator string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -45,6 +57,44 @@ const (
|
|||||||
AggregateOperatorHistQuant99 AggregateOperator = "hist_quantile_99"
|
AggregateOperatorHistQuant99 AggregateOperator = "hist_quantile_99"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (a AggregateOperator) Validate() error {
|
||||||
|
switch a {
|
||||||
|
case AggregateOperatorNoOp,
|
||||||
|
AggregateOpeatorCount,
|
||||||
|
AggregateOperatorCountDistinct,
|
||||||
|
AggregateOperatorSum,
|
||||||
|
AggregateOperatorAvg,
|
||||||
|
AggregateOperatorMin,
|
||||||
|
AggregateOperatorMax,
|
||||||
|
AggregateOperatorP05,
|
||||||
|
AggregateOperatorP10,
|
||||||
|
AggregateOperatorP20,
|
||||||
|
AggregateOperatorP25,
|
||||||
|
AggregateOperatorP50,
|
||||||
|
AggregateOperatorP75,
|
||||||
|
AggregateOperatorP90,
|
||||||
|
AggregateOperatorP95,
|
||||||
|
AggregateOperatorP99,
|
||||||
|
AggregateOperatorRate,
|
||||||
|
AggregateOperatorSumRate,
|
||||||
|
AggregateOperatorAvgRate,
|
||||||
|
AggregateOperatorMinRate,
|
||||||
|
AggregateOperatorMaxRate,
|
||||||
|
AggregateOperatorRateSum,
|
||||||
|
AggregateOperatorRateAvg,
|
||||||
|
AggregateOperatorRateMin,
|
||||||
|
AggregateOperatorRateMax,
|
||||||
|
AggregateOperatorHistQuant50,
|
||||||
|
AggregateOperatorHistQuant75,
|
||||||
|
AggregateOperatorHistQuant90,
|
||||||
|
AggregateOperatorHistQuant95,
|
||||||
|
AggregateOperatorHistQuant99:
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid operator: %s", a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type ReduceToOperator string
|
type ReduceToOperator string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -55,6 +105,15 @@ const (
|
|||||||
ReduceToOperatorMax ReduceToOperator = "max"
|
ReduceToOperatorMax ReduceToOperator = "max"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (r ReduceToOperator) Validate() error {
|
||||||
|
switch r {
|
||||||
|
case ReduceToOperatorLast, ReduceToOperatorSum, ReduceToOperatorAvg, ReduceToOperatorMin, ReduceToOperatorMax:
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid reduce to operator: %s", r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type QueryType string
|
type QueryType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -63,6 +122,15 @@ const (
|
|||||||
QueryTypePromQL QueryType = "promql"
|
QueryTypePromQL QueryType = "promql"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (q QueryType) Validate() error {
|
||||||
|
switch q {
|
||||||
|
case QueryTypeBuilder, QueryTypeClickHouseSQL, QueryTypePromQL:
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid query type: %s", q)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type PanelType string
|
type PanelType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -72,6 +140,15 @@ const (
|
|||||||
PanelTypeList PanelType = "list"
|
PanelTypeList PanelType = "list"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (p PanelType) Validate() error {
|
||||||
|
switch p {
|
||||||
|
case PanelTypeValue, PanelTypeGraph, PanelTypeTable, PanelTypeList:
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid panel type: %s", p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// AggregateAttributeRequest is a request to fetch possible attribute keys
|
// AggregateAttributeRequest is a request to fetch possible attribute keys
|
||||||
// for a selected aggregate operator and search text.
|
// for a selected aggregate operator and search text.
|
||||||
// The context of the selected aggregate operator is used as the
|
// The context of the selected aggregate operator is used as the
|
||||||
@ -104,26 +181,26 @@ type FilterAttributeKeyRequest struct {
|
|||||||
Limit int `json:"limit"`
|
Limit int `json:"limit"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type FilterAttributeKeyDataType string
|
type AttributeKeyDataType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
FilterAttributeKeyDataTypeString FilterAttributeKeyDataType = "string"
|
AttributeKeyDataTypeString AttributeKeyDataType = "string"
|
||||||
FilterAttributeKeyDataTypeNumber FilterAttributeKeyDataType = "number"
|
AttributeKeyDataTypeNumber AttributeKeyDataType = "number"
|
||||||
FilterAttributeKeyDataTypeBool FilterAttributeKeyDataType = "bool"
|
AttributeKeyDataTypeBool AttributeKeyDataType = "bool"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FilterAttributeValueRequest is a request to fetch possible attribute values
|
// FilterAttributeValueRequest is a request to fetch possible attribute values
|
||||||
// for a selected aggregate operator, aggregate attribute, filter attribute key
|
// for a selected aggregate operator, aggregate attribute, filter attribute key
|
||||||
// and search text.
|
// and search text.
|
||||||
type FilterAttributeValueRequest struct {
|
type FilterAttributeValueRequest struct {
|
||||||
DataSource DataSource `json:"dataSource"`
|
DataSource DataSource `json:"dataSource"`
|
||||||
AggregateOperator AggregateOperator `json:"aggregateOperator"`
|
AggregateOperator AggregateOperator `json:"aggregateOperator"`
|
||||||
AggregateAttribute string `json:"aggregateAttribute"`
|
AggregateAttribute string `json:"aggregateAttribute"`
|
||||||
FilterAttributeKey string `json:"filterAttributeKey"`
|
FilterAttributeKey string `json:"filterAttributeKey"`
|
||||||
FilterAttributeKeyDataType FilterAttributeKeyDataType `json:"filterAttributeKeyDataType"`
|
FilterAttributeKeyDataType AttributeKeyDataType `json:"filterAttributeKeyDataType"`
|
||||||
TagType TagType `json:"tagType"`
|
TagType TagType `json:"tagType"`
|
||||||
SearchText string `json:"searchText"`
|
SearchText string `json:"searchText"`
|
||||||
Limit int `json:"limit"`
|
Limit int `json:"limit"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AggregateAttributeResponse struct {
|
type AggregateAttributeResponse struct {
|
||||||
@ -134,10 +211,18 @@ type FilterAttributeKeyResponse struct {
|
|||||||
AttributeKeys []AttributeKey `json:"attributeKeys"`
|
AttributeKeys []AttributeKey `json:"attributeKeys"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AttributeKeyType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
AttributeKeyTypeColumn AttributeKeyType = "column"
|
||||||
|
AttributeKeyTypeTag AttributeKeyType = "tag"
|
||||||
|
AttributeKeyTypeResource AttributeKeyType = "resource"
|
||||||
|
)
|
||||||
|
|
||||||
type AttributeKey struct {
|
type AttributeKey struct {
|
||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
DataType string `json:"dataType"`
|
DataType AttributeKeyDataType `json:"dataType"`
|
||||||
Type string `json:"type"` // "column" or "tag"/"attr"/"attribute" or "resource"?
|
Type AttributeKeyType `json:"type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type FilterAttributeValueResponse struct {
|
type FilterAttributeValueResponse struct {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user