Merge pull request #689 from SigNoz/feat/tagValueSuggestion

feat: tag value suggestion API
This commit is contained in:
Ankit Nayan 2022-02-25 17:44:49 +05:30 committed by GitHub
commit 2800b021e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 125 additions and 0 deletions

View File

@ -1839,6 +1839,79 @@ func excludeTags(ctx context.Context, tags []model.TagFilters) []model.TagFilter
return newTags
}
func (r *ClickHouseReader) GetTagValues(ctx context.Context, queryParams *model.TagFilterParams) (*[]model.TagValues, *model.ApiError) {
excludeMap := make(map[string]struct{})
for _, e := range queryParams.Exclude {
if e == constants.OperationRequest {
excludeMap[constants.OperationDB] = struct{}{}
continue
}
excludeMap[e] = struct{}{}
}
var query string
args := []interface{}{queryParams.TagKey, strconv.FormatInt(queryParams.Start.UnixNano(), 10), strconv.FormatInt(queryParams.End.UnixNano(), 10)}
if len(queryParams.ServiceName) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.ServiceName, constants.ServiceName, &query, args)
}
if len(queryParams.HttpRoute) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.HttpRoute, constants.HttpRoute, &query, args)
}
if len(queryParams.HttpCode) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.HttpCode, constants.HttpCode, &query, args)
}
if len(queryParams.HttpHost) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.HttpHost, constants.HttpHost, &query, args)
}
if len(queryParams.HttpMethod) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.HttpMethod, constants.HttpMethod, &query, args)
}
if len(queryParams.HttpUrl) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.HttpUrl, constants.HttpUrl, &query, args)
}
if len(queryParams.Component) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.Component, constants.Component, &query, args)
}
if len(queryParams.Operation) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.Operation, constants.OperationDB, &query, args)
}
if len(queryParams.MinDuration) != 0 {
query = query + " AND durationNano >= ?"
args = append(args, queryParams.MinDuration)
}
if len(queryParams.MaxDuration) != 0 {
query = query + " AND durationNano <= ?"
args = append(args, queryParams.MaxDuration)
}
query = getStatusFilters(query, queryParams.Status, excludeMap)
tagValues := []model.TagValues{}
finalQuery := fmt.Sprintf(`SELECT tagMap[?] as tagValues FROM %s WHERE timestamp >= ? AND timestamp <= ?`, r.indexTable)
finalQuery += query
fmt.Println(finalQuery)
finalQuery += "GROUP BY tagMap[?]"
args = append(args, queryParams.TagKey)
err := r.db.Select(&tagValues, finalQuery, args...)
zap.S().Info(query)
if err != nil {
zap.S().Debug("Error in processing sql query: ", err)
return nil, &model.ApiError{model.ErrorExec, fmt.Errorf("Error in processing sql query")}
}
cleanedTagValues := []model.TagValues{}
for _, e := range tagValues {
if e.TagValues != "" {
cleanedTagValues = append(cleanedTagValues, e)
}
}
return &cleanedTagValues, nil
}
func (r *ClickHouseReader) GetServiceDBOverview(ctx context.Context, queryParams *model.GetServiceOverviewParams) (*[]model.ServiceDBOverviewItem, error) {
var serviceDBOverviewItems []model.ServiceDBOverviewItem

View File

@ -173,6 +173,10 @@ func (druid *DruidReader) GetTagFilters(_ context.Context, _ *model.TagFilterPar
return nil, &model.ApiError{model.ErrorNotImplemented, fmt.Errorf("druid does not support getting tagFilters")}
}
func (druid *DruidReader) GetTagValues(_ context.Context, _ *model.TagFilterParams) (*[]model.TagValues, *model.ApiError) {
return nil, &model.ApiError{model.ErrorNotImplemented, fmt.Errorf("druid does not support getting tagValues")}
}
func (druid *DruidReader) GetFilteredSpans(_ context.Context, _ *model.GetFilteredSpansParams) (*model.GetFilterSpansResponse, *model.ApiError) {
return nil, &model.ApiError{model.ErrorNotImplemented, fmt.Errorf("druid does not support getting FilteredSpans")}
}

View File

@ -214,6 +214,7 @@ func (aH *APIHandler) RegisterRoutes(router *mux.Router) {
router.HandleFunc("/api/v1/getFilteredSpans", aH.getFilteredSpans).Methods(http.MethodPost)
router.HandleFunc("/api/v1/getFilteredSpans/aggregates", aH.getFilteredSpanAggregates).Methods(http.MethodPost)
router.HandleFunc("/api/v1/getTagValues", aH.getTagValues).Methods(http.MethodPost)
router.HandleFunc("/api/v1/errors", aH.getErrors).Methods(http.MethodGet)
router.HandleFunc("/api/v1/errorWithId", aH.getErrorForId).Methods(http.MethodGet)
router.HandleFunc("/api/v1/errorWithType", aH.getErrorForType).Methods(http.MethodGet)
@ -1040,6 +1041,22 @@ func (aH *APIHandler) getTagFilters(w http.ResponseWriter, r *http.Request) {
aH.writeJSON(w, r, result)
}
func (aH *APIHandler) getTagValues(w http.ResponseWriter, r *http.Request) {
query, err := parseTagValueRequest(r)
if aH.handleError(w, err, http.StatusBadRequest) {
return
}
result, apiErr := (*aH.reader).GetTagValues(context.Background(), query)
if apiErr != nil && aH.handleError(w, apiErr.Err, http.StatusInternalServerError) {
return
}
aH.writeJSON(w, r, result)
}
func (aH *APIHandler) setTTL(w http.ResponseWriter, r *http.Request) {
ttlParams, err := parseDuration(r)
if aH.handleError(w, err, http.StatusBadRequest) {

View File

@ -39,6 +39,7 @@ type Reader interface {
GetTTL(ctx context.Context, ttlParams *model.GetTTLParams) (*model.GetTTLResponseItem, *model.ApiError)
GetSpanFilters(ctx context.Context, query *model.SpanFilterParams) (*model.SpanFiltersResponse, *model.ApiError)
GetTagFilters(ctx context.Context, query *model.TagFilterParams) (*[]model.TagFilters, *model.ApiError)
GetTagValues(ctx context.Context, query *model.TagFilterParams) (*[]model.TagValues, *model.ApiError)
GetFilteredSpans(ctx context.Context, query *model.GetFilteredSpansParams) (*model.GetFilterSpansResponse, *model.ApiError)
GetFilteredSpansAggregates(ctx context.Context, query *model.GetFilteredSpanAggregatesParams) (*model.GetFilteredSpansAggregatesResponse, *model.ApiError)

View File

@ -650,6 +650,31 @@ func parseTagFilterRequest(r *http.Request) (*model.TagFilterParams, error) {
return postData, nil
}
func parseTagValueRequest(r *http.Request) (*model.TagFilterParams, error) {
var postData *model.TagFilterParams
err := json.NewDecoder(r.Body).Decode(&postData)
if err != nil {
return nil, err
}
if postData.TagKey == "" {
return nil, fmt.Errorf("%s param missing in query", postData.TagKey)
}
postData.Start, err = parseTimeStr(postData.StartStr, "start")
if err != nil {
return nil, err
}
postData.End, err = parseTimeMinusBufferStr(postData.EndStr, "end")
if err != nil {
return nil, err
}
return postData, nil
}
func parseErrorsRequest(r *http.Request) (*model.GetErrorsParams, error) {
startTime, err := parseTime("start", r)

View File

@ -201,6 +201,7 @@ type TagFilterParams struct {
MaxDuration string `json:"maxDuration"`
StartStr string `json:"start"`
EndStr string `json:"end"`
TagKey string `json:"tagKey"`
Start *time.Time
End *time.Time
}

View File

@ -268,6 +268,10 @@ type TagItem struct {
type TagFilters struct {
TagKeys string `json:"tagKeys" db:"tagKeys"`
}
type TagValues struct {
TagValues string `json:"tagValues" db:"tagValues"`
}
type ServiceMapDependencyResponseItem struct {
Parent string `json:"parent,omitempty" db:"parent,omitempty"`
Child string `json:"child,omitempty" db:"child,omitempty"`