feat: add resource tags to ListErrors API (#2487)

This commit is contained in:
Vishal Sharma 2023-03-28 00:15:15 +05:30 committed by GitHub
parent 8ea0f72178
commit 9d20c2f787
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 139 additions and 98 deletions

View File

@ -1464,13 +1464,13 @@ func createTagQueryFromTagQueryParams(queryParams []model.TagQueryParam) []model
tags := []model.TagQuery{} tags := []model.TagQuery{}
for _, tag := range queryParams { for _, tag := range queryParams {
if len(tag.StringValues) > 0 { if len(tag.StringValues) > 0 {
tags = append(tags, model.NewTagQueryString(tag.Key, tag.StringValues, tag.Operator)) tags = append(tags, model.NewTagQueryString(tag))
} }
if len(tag.NumberValues) > 0 { if len(tag.NumberValues) > 0 {
tags = append(tags, model.NewTagQueryNumber(tag.Key, tag.NumberValues, tag.Operator)) tags = append(tags, model.NewTagQueryNumber(tag))
} }
if len(tag.BoolValues) > 0 { if len(tag.BoolValues) > 0 {
tags = append(tags, model.NewTagQueryBool(tag.Key, tag.BoolValues, tag.Operator)) tags = append(tags, model.NewTagQueryBool(tag))
} }
} }
return tags return tags
@ -1494,18 +1494,7 @@ func buildQueryWithTagParams(ctx context.Context, tags []model.TagQuery) (string
for _, item := range tags { for _, item := range tags {
var subQuery string var subQuery string
var argsSubQuery []interface{} var argsSubQuery []interface{}
tagMapType := "" tagMapType := item.GetTagMapColumn()
switch item.(type) {
case model.TagQueryString:
tagMapType = constants.StringTagMapCol
case model.TagQueryNumber:
tagMapType = constants.NumberTagMapCol
case model.TagQueryBool:
tagMapType = constants.BoolTagMapCol
default:
// type not supported error
return "", nil, &model.ApiError{Typ: model.ErrorBadData, Err: fmt.Errorf("type not supported")}
}
switch item.GetOperator() { switch item.GetOperator() {
case model.EqualOperator: case model.EqualOperator:
subQuery, argsSubQuery = addArithmeticOperator(item, tagMapType, "=") subQuery, argsSubQuery = addArithmeticOperator(item, tagMapType, "=")
@ -2698,6 +2687,17 @@ func (r *ClickHouseReader) ListErrors(ctx context.Context, queryParams *model.Li
query = query + " AND exceptionType ilike @exceptionType" query = query + " AND exceptionType ilike @exceptionType"
args = append(args, clickhouse.Named("exceptionType", "%"+queryParams.ExceptionType+"%")) args = append(args, clickhouse.Named("exceptionType", "%"+queryParams.ExceptionType+"%"))
} }
// create TagQuery from TagQueryParams
tags := createTagQueryFromTagQueryParams(queryParams.Tags)
subQuery, argsSubQuery, errStatus := buildQueryWithTagParams(ctx, tags)
query += subQuery
args = append(args, argsSubQuery...)
if errStatus != nil {
zap.S().Error("Error in processing tags: ", errStatus)
return nil, errStatus
}
query = query + " GROUP BY groupID" query = query + " GROUP BY groupID"
if len(queryParams.ServiceName) != 0 { if len(queryParams.ServiceName) != 0 {
query = query + ", serviceName" query = query + ", serviceName"
@ -2747,6 +2747,18 @@ func (r *ClickHouseReader) CountErrors(ctx context.Context, queryParams *model.C
query = query + " AND exceptionType ilike @exceptionType" query = query + " AND exceptionType ilike @exceptionType"
args = append(args, clickhouse.Named("exceptionType", "%"+queryParams.ExceptionType+"%")) args = append(args, clickhouse.Named("exceptionType", "%"+queryParams.ExceptionType+"%"))
} }
// create TagQuery from TagQueryParams
tags := createTagQueryFromTagQueryParams(queryParams.Tags)
subQuery, argsSubQuery, errStatus := buildQueryWithTagParams(ctx, tags)
query += subQuery
args = append(args, argsSubQuery...)
if errStatus != nil {
zap.S().Error("Error in processing tags: ", errStatus)
return 0, errStatus
}
err := r.db.QueryRow(ctx, query, args...).Scan(&errorCount) err := r.db.QueryRow(ctx, query, args...).Scan(&errorCount)
zap.S().Info(query) zap.S().Info(query)

View File

@ -328,8 +328,8 @@ func (aH *APIHandler) RegisterRoutes(router *mux.Router, am *AuthMiddleware) {
router.HandleFunc("/api/v1/getFilteredSpans/aggregates", am.ViewAccess(aH.getFilteredSpanAggregates)).Methods(http.MethodPost) router.HandleFunc("/api/v1/getFilteredSpans/aggregates", am.ViewAccess(aH.getFilteredSpanAggregates)).Methods(http.MethodPost)
router.HandleFunc("/api/v1/getTagValues", am.ViewAccess(aH.getTagValues)).Methods(http.MethodPost) router.HandleFunc("/api/v1/getTagValues", am.ViewAccess(aH.getTagValues)).Methods(http.MethodPost)
router.HandleFunc("/api/v1/listErrors", am.ViewAccess(aH.listErrors)).Methods(http.MethodGet) router.HandleFunc("/api/v1/listErrors", am.ViewAccess(aH.listErrors)).Methods(http.MethodPost)
router.HandleFunc("/api/v1/countErrors", am.ViewAccess(aH.countErrors)).Methods(http.MethodGet) router.HandleFunc("/api/v1/countErrors", am.ViewAccess(aH.countErrors)).Methods(http.MethodPost)
router.HandleFunc("/api/v1/errorFromErrorID", am.ViewAccess(aH.getErrorFromErrorID)).Methods(http.MethodGet) router.HandleFunc("/api/v1/errorFromErrorID", am.ViewAccess(aH.getErrorFromErrorID)).Methods(http.MethodGet)
router.HandleFunc("/api/v1/errorFromGroupID", am.ViewAccess(aH.getErrorFromGroupID)).Methods(http.MethodGet) router.HandleFunc("/api/v1/errorFromGroupID", am.ViewAccess(aH.getErrorFromGroupID)).Methods(http.MethodGet)
router.HandleFunc("/api/v1/nextPrevErrorIDs", am.ViewAccess(aH.getNextPrevErrorIDs)).Methods(http.MethodGet) router.HandleFunc("/api/v1/nextPrevErrorIDs", am.ViewAccess(aH.getNextPrevErrorIDs)).Methods(http.MethodGet)

View File

@ -494,76 +494,54 @@ func parseListErrorsRequest(r *http.Request) (*model.ListErrorsParams, error) {
var allowedOrderParams = []string{"exceptionType", "exceptionCount", "firstSeen", "lastSeen", "serviceName"} var allowedOrderParams = []string{"exceptionType", "exceptionCount", "firstSeen", "lastSeen", "serviceName"}
var allowedOrderDirections = []string{"ascending", "descending"} var allowedOrderDirections = []string{"ascending", "descending"}
startTime, err := parseTime("start", r) var postData *model.ListErrorsParams
if err != nil { err := json.NewDecoder(r.Body).Decode(&postData)
return nil, err
}
endTime, err := parseTimeMinusBuffer("end", r)
if err != nil { if err != nil {
return nil, err return nil, err
} }
order := r.URL.Query().Get("order") postData.Start, err = parseTimeStr(postData.StartStr, "start")
if len(order) > 0 && !DoesExistInSlice(order, allowedOrderDirections) {
return nil, errors.New(fmt.Sprintf("given order: %s is not allowed in query", order))
}
orderParam := r.URL.Query().Get("orderParam")
if len(order) > 0 && !DoesExistInSlice(orderParam, allowedOrderParams) {
return nil, errors.New(fmt.Sprintf("given orderParam: %s is not allowed in query", orderParam))
}
limit := r.URL.Query().Get("limit")
offset := r.URL.Query().Get("offset")
if len(offset) == 0 || len(limit) == 0 {
return nil, fmt.Errorf("offset or limit param cannot be empty from the query")
}
limitInt, err := strconv.Atoi(limit)
if err != nil { if err != nil {
return nil, errors.New("limit param is not in correct format") return nil, err
} }
offsetInt, err := strconv.Atoi(offset) postData.End, err = parseTimeMinusBufferStr(postData.EndStr, "end")
if err != nil { if err != nil {
return nil, errors.New("offset param is not in correct format") return nil, err
} }
serviceName := r.URL.Query().Get("serviceName") if postData.Limit == 0 {
exceptionType := r.URL.Query().Get("exceptionType") return nil, fmt.Errorf("limit param cannot be empty from the query")
params := &model.ListErrorsParams{
Start: startTime,
End: endTime,
OrderParam: orderParam,
Order: order,
Limit: int64(limitInt),
Offset: int64(offsetInt),
ServiceName: serviceName,
ExceptionType: exceptionType,
} }
return params, nil if len(postData.Order) > 0 && !DoesExistInSlice(postData.Order, allowedOrderDirections) {
return nil, errors.New(fmt.Sprintf("given order: %s is not allowed in query", postData.Order))
}
if len(postData.Order) > 0 && !DoesExistInSlice(postData.OrderParam, allowedOrderParams) {
return nil, errors.New(fmt.Sprintf("given orderParam: %s is not allowed in query", postData.OrderParam))
}
return postData, nil
} }
func parseCountErrorsRequest(r *http.Request) (*model.CountErrorsParams, error) { func parseCountErrorsRequest(r *http.Request) (*model.CountErrorsParams, error) {
startTime, err := parseTime("start", r) var postData *model.CountErrorsParams
err := json.NewDecoder(r.Body).Decode(&postData)
if err != nil { if err != nil {
return nil, err return nil, err
} }
endTime, err := parseTimeMinusBuffer("end", r)
postData.Start, err = parseTimeStr(postData.StartStr, "start")
if err != nil { if err != nil {
return nil, err return nil, err
} }
serviceName := r.URL.Query().Get("serviceName") postData.End, err = parseTimeMinusBufferStr(postData.EndStr, "end")
exceptionType := r.URL.Query().Get("exceptionType") if err != nil {
return nil, err
params := &model.CountErrorsParams{
Start: startTime,
End: endTime,
ServiceName: serviceName,
ExceptionType: exceptionType,
} }
return postData, nil
return params, nil
} }
func parseGetErrorRequest(r *http.Request) (*model.GetErrorParams, error) { func parseGetErrorRequest(r *http.Request) (*model.GetErrorParams, error) {

View File

@ -219,11 +219,5 @@ var ReservedColumnTargetAliases = map[string]struct{}{
"value": {}, "value": {},
} }
const (
StringTagMapCol = "stringTagMap"
NumberTagMapCol = "numberTagMap"
BoolTagMapCol = "boolTagMap"
)
// logsPPLPfx is a short constant for logsPipelinePrefix // logsPPLPfx is a short constant for logsPipelinePrefix
const LogsPPLPfx = "logstransform/pipeline_" const LogsPPLPfx = "logstransform/pipeline_"

View File

@ -122,6 +122,13 @@ const (
LOGS LOGS
) )
const (
StringTagMapCol = "stringTagMap"
NumberTagMapCol = "numberTagMap"
BoolTagMapCol = "boolTagMap"
ResourceTagMapCol = "resourceTagsMap"
)
type QueryRangeParamsV2 struct { type QueryRangeParamsV2 struct {
DataSource DataSource `json:"dataSource"` DataSource DataSource `json:"dataSource"`
Start int64 `json:"start"` Start int64 `json:"start"`
@ -187,6 +194,7 @@ type GetServiceOverviewParams struct {
type TagQueryParam struct { type TagQueryParam struct {
Key string `json:"key"` Key string `json:"key"`
TagType TagType `json:"tagType"`
StringValues []string `json:"stringValues"` StringValues []string `json:"stringValues"`
BoolValues []bool `json:"boolValues"` BoolValues []bool `json:"boolValues"`
NumberValues []float64 `json:"numberValues"` NumberValues []float64 `json:"numberValues"`
@ -212,23 +220,34 @@ const (
NotStartsWithOperator Operator = "NotStartsWith" NotStartsWithOperator Operator = "NotStartsWith"
) )
type TagType string
const (
ResourceAttributeTagType TagType = "ResourceAttribute"
SpanAttributeTagType TagType = "SpanAttribute"
)
type TagQuery interface { type TagQuery interface {
GetKey() string GetKey() string
GetValues() []interface{} GetValues() []interface{}
GetOperator() Operator GetOperator() Operator
GetTagType() TagType
GetTagMapColumn() string
} }
type TagQueryString struct { type TagQueryString struct {
key string key string
values []string values []string
operator Operator operator Operator
tagType TagType
} }
func NewTagQueryString(key string, values []string, operator Operator) TagQueryString { func NewTagQueryString(tag TagQueryParam) TagQueryString {
return TagQueryString{ return TagQueryString{
key: key, key: tag.Key,
values: values, values: tag.StringValues,
operator: operator, operator: tag.Operator,
tagType: tag.TagType,
} }
} }
@ -248,17 +267,31 @@ func (tqs TagQueryString) GetOperator() Operator {
return tqs.operator return tqs.operator
} }
func (tqs TagQueryString) GetTagType() TagType {
return tqs.tagType
}
func (tqs TagQueryString) GetTagMapColumn() string {
if tqs.GetTagType() == ResourceAttributeTagType {
return ResourceTagMapCol
} else {
return StringTagMapCol
}
}
type TagQueryBool struct { type TagQueryBool struct {
key string key string
values []bool values []bool
operator Operator operator Operator
tagType TagType
} }
func NewTagQueryBool(key string, values []bool, operator Operator) TagQueryBool { func NewTagQueryBool(tag TagQueryParam) TagQueryBool {
return TagQueryBool{ return TagQueryBool{
key: key, key: tag.Key,
values: values, values: tag.BoolValues,
operator: operator, operator: tag.Operator,
tagType: tag.TagType,
} }
} }
@ -278,17 +311,27 @@ func (tqb TagQueryBool) GetOperator() Operator {
return tqb.operator return tqb.operator
} }
func (tqb TagQueryBool) GetTagType() TagType {
return tqb.tagType
}
func (tqb TagQueryBool) GetTagMapColumn() string {
return BoolTagMapCol
}
type TagQueryNumber struct { type TagQueryNumber struct {
key string key string
values []float64 values []float64
operator Operator operator Operator
tagType TagType
} }
func NewTagQueryNumber(key string, values []float64, operator Operator) TagQueryNumber { func NewTagQueryNumber(tag TagQueryParam) TagQueryNumber {
return TagQueryNumber{ return TagQueryNumber{
key: key, key: tag.Key,
values: values, values: tag.NumberValues,
operator: operator, operator: tag.Operator,
tagType: tag.TagType,
} }
} }
@ -308,6 +351,14 @@ func (tqn TagQueryNumber) GetOperator() Operator {
return tqn.operator return tqn.operator
} }
func (tqn TagQueryNumber) GetTagType() TagType {
return tqn.tagType
}
func (tqn TagQueryNumber) GetTagMapColumn() string {
return NumberTagMapCol
}
type GetFilteredSpansParams struct { type GetFilteredSpansParams struct {
TraceID []string `json:"traceID"` TraceID []string `json:"traceID"`
ServiceName []string `json:"serviceName"` ServiceName []string `json:"serviceName"`
@ -414,17 +465,17 @@ type TagFilterParams struct {
End *time.Time End *time.Time
} }
type TagType string type TagDataType string
const ( const (
TagTypeString TagType = "string" TagTypeString TagDataType = "string"
TagTypeNumber TagType = "number" TagTypeNumber TagDataType = "number"
TagTypeBool TagType = "bool" TagTypeBool TagDataType = "bool"
) )
type TagKey struct { type TagKey struct {
Key string `json:"key"` Key string `json:"key"`
Type TagType `json:"type"` Type TagDataType `json:"type"`
} }
type TTLParams struct { type TTLParams struct {
@ -439,21 +490,27 @@ type GetTTLParams struct {
} }
type ListErrorsParams struct { type ListErrorsParams struct {
StartStr string `json:"start"`
EndStr string `json:"end"`
Start *time.Time Start *time.Time
End *time.Time End *time.Time
Limit int64 Limit int64 `json:"limit"`
OrderParam string OrderParam string `json:"orderParam"`
Order string Order string `json:"order"`
Offset int64 Offset int64 `json:"offset"`
ServiceName string ServiceName string `json:"serviceName"`
ExceptionType string ExceptionType string `json:"exceptionType"`
Tags []TagQueryParam `json:"tags"`
} }
type CountErrorsParams struct { type CountErrorsParams struct {
StartStr string `json:"start"`
EndStr string `json:"end"`
Start *time.Time Start *time.Time
End *time.Time End *time.Time
ServiceName string ServiceName string `json:"serviceName"`
ExceptionType string ExceptionType string `json:"exceptionType"`
Tags []TagQueryParam `json:"tags"`
} }
type GetErrorParams struct { type GetErrorParams struct {