mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-10 22:29:00 +08:00
Merge pull request #689 from SigNoz/feat/tagValueSuggestion
feat: tag value suggestion API
This commit is contained in:
commit
2800b021e6
@ -1839,6 +1839,79 @@ func excludeTags(ctx context.Context, tags []model.TagFilters) []model.TagFilter
|
|||||||
return newTags
|
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) {
|
func (r *ClickHouseReader) GetServiceDBOverview(ctx context.Context, queryParams *model.GetServiceOverviewParams) (*[]model.ServiceDBOverviewItem, error) {
|
||||||
|
|
||||||
var serviceDBOverviewItems []model.ServiceDBOverviewItem
|
var serviceDBOverviewItems []model.ServiceDBOverviewItem
|
||||||
|
@ -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")}
|
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) {
|
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")}
|
return nil, &model.ApiError{model.ErrorNotImplemented, fmt.Errorf("druid does not support getting FilteredSpans")}
|
||||||
}
|
}
|
||||||
|
@ -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", aH.getFilteredSpans).Methods(http.MethodPost)
|
||||||
router.HandleFunc("/api/v1/getFilteredSpans/aggregates", aH.getFilteredSpanAggregates).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/errors", aH.getErrors).Methods(http.MethodGet)
|
||||||
router.HandleFunc("/api/v1/errorWithId", aH.getErrorForId).Methods(http.MethodGet)
|
router.HandleFunc("/api/v1/errorWithId", aH.getErrorForId).Methods(http.MethodGet)
|
||||||
router.HandleFunc("/api/v1/errorWithType", aH.getErrorForType).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)
|
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) {
|
func (aH *APIHandler) setTTL(w http.ResponseWriter, r *http.Request) {
|
||||||
ttlParams, err := parseDuration(r)
|
ttlParams, err := parseDuration(r)
|
||||||
if aH.handleError(w, err, http.StatusBadRequest) {
|
if aH.handleError(w, err, http.StatusBadRequest) {
|
||||||
|
@ -39,6 +39,7 @@ type Reader interface {
|
|||||||
GetTTL(ctx context.Context, ttlParams *model.GetTTLParams) (*model.GetTTLResponseItem, *model.ApiError)
|
GetTTL(ctx context.Context, ttlParams *model.GetTTLParams) (*model.GetTTLResponseItem, *model.ApiError)
|
||||||
GetSpanFilters(ctx context.Context, query *model.SpanFilterParams) (*model.SpanFiltersResponse, *model.ApiError)
|
GetSpanFilters(ctx context.Context, query *model.SpanFilterParams) (*model.SpanFiltersResponse, *model.ApiError)
|
||||||
GetTagFilters(ctx context.Context, query *model.TagFilterParams) (*[]model.TagFilters, *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)
|
GetFilteredSpans(ctx context.Context, query *model.GetFilteredSpansParams) (*model.GetFilterSpansResponse, *model.ApiError)
|
||||||
GetFilteredSpansAggregates(ctx context.Context, query *model.GetFilteredSpanAggregatesParams) (*model.GetFilteredSpansAggregatesResponse, *model.ApiError)
|
GetFilteredSpansAggregates(ctx context.Context, query *model.GetFilteredSpanAggregatesParams) (*model.GetFilteredSpansAggregatesResponse, *model.ApiError)
|
||||||
|
|
||||||
|
@ -650,6 +650,31 @@ func parseTagFilterRequest(r *http.Request) (*model.TagFilterParams, error) {
|
|||||||
return postData, nil
|
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) {
|
func parseErrorsRequest(r *http.Request) (*model.GetErrorsParams, error) {
|
||||||
|
|
||||||
startTime, err := parseTime("start", r)
|
startTime, err := parseTime("start", r)
|
||||||
|
@ -201,6 +201,7 @@ type TagFilterParams struct {
|
|||||||
MaxDuration string `json:"maxDuration"`
|
MaxDuration string `json:"maxDuration"`
|
||||||
StartStr string `json:"start"`
|
StartStr string `json:"start"`
|
||||||
EndStr string `json:"end"`
|
EndStr string `json:"end"`
|
||||||
|
TagKey string `json:"tagKey"`
|
||||||
Start *time.Time
|
Start *time.Time
|
||||||
End *time.Time
|
End *time.Time
|
||||||
}
|
}
|
||||||
|
@ -268,6 +268,10 @@ type TagItem struct {
|
|||||||
type TagFilters struct {
|
type TagFilters struct {
|
||||||
TagKeys string `json:"tagKeys" db:"tagKeys"`
|
TagKeys string `json:"tagKeys" db:"tagKeys"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TagValues struct {
|
||||||
|
TagValues string `json:"tagValues" db:"tagValues"`
|
||||||
|
}
|
||||||
type ServiceMapDependencyResponseItem struct {
|
type ServiceMapDependencyResponseItem struct {
|
||||||
Parent string `json:"parent,omitempty" db:"parent,omitempty"`
|
Parent string `json:"parent,omitempty" db:"parent,omitempty"`
|
||||||
Child string `json:"child,omitempty" db:"child,omitempty"`
|
Child string `json:"child,omitempty" db:"child,omitempty"`
|
||||||
|
Loading…
x
Reference in New Issue
Block a user