mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-12 07:19:00 +08:00
fix: remove service overview API (#6495)
This commit is contained in:
parent
d7bd72e2aa
commit
5044861773
@ -642,130 +642,6 @@ func (r *ClickHouseReader) GetServices(ctx context.Context, queryParams *model.G
|
||||
}
|
||||
return &serviceItems, nil
|
||||
}
|
||||
|
||||
func (r *ClickHouseReader) GetServiceOverview(ctx context.Context, queryParams *model.GetServiceOverviewParams, skipConfig *model.SkipConfig) (*[]model.ServiceOverviewItem, *model.ApiError) {
|
||||
|
||||
topLevelOps, apiErr := r.GetTopLevelOperations(ctx, skipConfig, *queryParams.Start, *queryParams.End, nil)
|
||||
if apiErr != nil {
|
||||
return nil, apiErr
|
||||
}
|
||||
ops, ok := (*topLevelOps)[queryParams.ServiceName]
|
||||
if !ok {
|
||||
return nil, &model.ApiError{Typ: model.ErrorNotFound, Err: fmt.Errorf("service not found")}
|
||||
}
|
||||
|
||||
namedArgs := []interface{}{
|
||||
clickhouse.Named("interval", strconv.Itoa(int(queryParams.StepSeconds/60))),
|
||||
clickhouse.Named("start", strconv.FormatInt(queryParams.Start.UnixNano(), 10)),
|
||||
clickhouse.Named("end", strconv.FormatInt(queryParams.End.UnixNano(), 10)),
|
||||
clickhouse.Named("serviceName", queryParams.ServiceName),
|
||||
clickhouse.Named("names", ops),
|
||||
}
|
||||
|
||||
serviceOverviewItems := []model.ServiceOverviewItem{}
|
||||
|
||||
query := fmt.Sprintf(`
|
||||
SELECT
|
||||
toStartOfInterval(timestamp, INTERVAL @interval minute) as time,
|
||||
quantile(0.99)(durationNano) as p99,
|
||||
quantile(0.95)(durationNano) as p95,
|
||||
quantile(0.50)(durationNano) as p50,
|
||||
count(*) as numCalls
|
||||
FROM %s.%s
|
||||
WHERE serviceName = @serviceName AND name In @names AND timestamp>= @start AND timestamp<= @end`,
|
||||
r.TraceDB, r.indexTable,
|
||||
)
|
||||
args := []interface{}{}
|
||||
args = append(args, namedArgs...)
|
||||
|
||||
// create TagQuery from TagQueryParams
|
||||
tags := createTagQueryFromTagQueryParams(queryParams.Tags)
|
||||
subQuery, argsSubQuery, errStatus := buildQueryWithTagParams(ctx, tags)
|
||||
query += subQuery
|
||||
args = append(args, argsSubQuery...)
|
||||
if errStatus != nil {
|
||||
return nil, errStatus
|
||||
}
|
||||
query += " GROUP BY time ORDER BY time DESC"
|
||||
err := r.db.Select(ctx, &serviceOverviewItems, query, args...)
|
||||
|
||||
zap.L().Debug("running query", zap.String("query", query))
|
||||
|
||||
if err != nil {
|
||||
zap.L().Error("Error in processing sql query", zap.Error(err))
|
||||
return nil, &model.ApiError{Typ: model.ErrorExec, Err: fmt.Errorf("error in processing sql query")}
|
||||
}
|
||||
|
||||
serviceErrorItems := []model.ServiceErrorItem{}
|
||||
|
||||
query = fmt.Sprintf(`
|
||||
SELECT
|
||||
toStartOfInterval(timestamp, INTERVAL @interval minute) as time,
|
||||
count(*) as numErrors
|
||||
FROM %s.%s
|
||||
WHERE serviceName = @serviceName AND name In @names AND timestamp>= @start AND timestamp<= @end AND statusCode=2`,
|
||||
r.TraceDB, r.indexTable,
|
||||
)
|
||||
args = []interface{}{}
|
||||
args = append(args, namedArgs...)
|
||||
subQuery, argsSubQuery, errStatus = buildQueryWithTagParams(ctx, tags)
|
||||
query += subQuery
|
||||
args = append(args, argsSubQuery...)
|
||||
if errStatus != nil {
|
||||
return nil, errStatus
|
||||
}
|
||||
query += " GROUP BY time ORDER BY time DESC"
|
||||
err = r.db.Select(ctx, &serviceErrorItems, query, args...)
|
||||
|
||||
if err != nil {
|
||||
zap.L().Error("Error in processing sql query", zap.Error(err))
|
||||
return nil, &model.ApiError{Typ: model.ErrorExec, Err: fmt.Errorf("error in processing sql query")}
|
||||
}
|
||||
|
||||
m := make(map[int64]int)
|
||||
|
||||
for j := range serviceErrorItems {
|
||||
m[int64(serviceErrorItems[j].Time.UnixNano())] = int(serviceErrorItems[j].NumErrors)
|
||||
}
|
||||
|
||||
for i := range serviceOverviewItems {
|
||||
serviceOverviewItems[i].Timestamp = int64(serviceOverviewItems[i].Time.UnixNano())
|
||||
|
||||
if val, ok := m[serviceOverviewItems[i].Timestamp]; ok {
|
||||
serviceOverviewItems[i].NumErrors = uint64(val)
|
||||
}
|
||||
serviceOverviewItems[i].ErrorRate = float64(serviceOverviewItems[i].NumErrors) * 100 / float64(serviceOverviewItems[i].NumCalls)
|
||||
serviceOverviewItems[i].CallRate = float64(serviceOverviewItems[i].NumCalls) / float64(queryParams.StepSeconds)
|
||||
}
|
||||
|
||||
return &serviceOverviewItems, nil
|
||||
}
|
||||
|
||||
func buildFilterArrayQuery(_ context.Context, excludeMap map[string]struct{}, params []string, filter string, query *string, args []interface{}) []interface{} {
|
||||
for i, e := range params {
|
||||
filterKey := filter + String(5)
|
||||
if i == 0 && i == len(params)-1 {
|
||||
if _, ok := excludeMap[filter]; ok {
|
||||
*query += fmt.Sprintf(" AND NOT (%s=@%s)", filter, filterKey)
|
||||
} else {
|
||||
*query += fmt.Sprintf(" AND (%s=@%s)", filter, filterKey)
|
||||
}
|
||||
} else if i == 0 && i != len(params)-1 {
|
||||
if _, ok := excludeMap[filter]; ok {
|
||||
*query += fmt.Sprintf(" AND NOT (%s=@%s", filter, filterKey)
|
||||
} else {
|
||||
*query += fmt.Sprintf(" AND (%s=@%s", filter, filterKey)
|
||||
}
|
||||
} else if i != 0 && i == len(params)-1 {
|
||||
*query += fmt.Sprintf(" OR %s=@%s)", filter, filterKey)
|
||||
} else {
|
||||
*query += fmt.Sprintf(" OR %s=@%s", filter, filterKey)
|
||||
}
|
||||
args = append(args, clickhouse.Named(filterKey, e))
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
func getStatusFilters(query string, statusParams []string, excludeMap map[string]struct{}) string {
|
||||
|
||||
// status can only be two and if both are selected than they are equivalent to none selected
|
||||
|
@ -508,7 +508,6 @@ func (aH *APIHandler) RegisterRoutes(router *mux.Router, am *AuthMiddleware) {
|
||||
// router.HandleFunc("/api/v1/get_percentiles", aH.getApplicationPercentiles).Methods(http.MethodGet)
|
||||
router.HandleFunc("/api/v1/services", am.ViewAccess(aH.getServices)).Methods(http.MethodPost)
|
||||
router.HandleFunc("/api/v1/services/list", am.ViewAccess(aH.getServicesList)).Methods(http.MethodGet)
|
||||
router.HandleFunc("/api/v1/service/overview", am.ViewAccess(aH.getServiceOverview)).Methods(http.MethodPost)
|
||||
router.HandleFunc("/api/v1/service/top_operations", am.ViewAccess(aH.getTopOperations)).Methods(http.MethodPost)
|
||||
router.HandleFunc("/api/v1/service/top_level_operations", am.ViewAccess(aH.getServicesTopLevelOps)).Methods(http.MethodPost)
|
||||
router.HandleFunc("/api/v1/traces/{traceId}", am.ViewAccess(aH.SearchTraces)).Methods(http.MethodGet)
|
||||
@ -1632,22 +1631,6 @@ func (aH *APIHandler) getUsage(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
}
|
||||
|
||||
func (aH *APIHandler) getServiceOverview(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
query, err := parseGetServiceOverviewRequest(r)
|
||||
if aH.HandleError(w, err, http.StatusBadRequest) {
|
||||
return
|
||||
}
|
||||
|
||||
result, apiErr := aH.reader.GetServiceOverview(r.Context(), query, aH.skipConfig)
|
||||
if apiErr != nil && aH.HandleError(w, apiErr.Err, http.StatusInternalServerError) {
|
||||
return
|
||||
}
|
||||
|
||||
aH.WriteJSON(w, r, result)
|
||||
|
||||
}
|
||||
|
||||
func (aH *APIHandler) getServicesTopLevelOps(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
var start, end time.Time
|
||||
|
@ -195,28 +195,6 @@ func parseGetUsageRequest(r *http.Request) (*model.GetUsageParams, error) {
|
||||
|
||||
}
|
||||
|
||||
func parseGetServiceOverviewRequest(r *http.Request) (*model.GetServiceOverviewParams, error) {
|
||||
|
||||
var postData *model.GetServiceOverviewParams
|
||||
err := json.NewDecoder(r.Body).Decode(&postData)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
postData.Start, err = parseTimeStr(postData.StartTime, "start")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
postData.End, err = parseTimeMinusBufferStr(postData.EndTime, "end")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
postData.Period = fmt.Sprintf("PT%dM", postData.StepSeconds/60)
|
||||
return postData, nil
|
||||
}
|
||||
|
||||
func parseGetServicesRequest(r *http.Request) (*model.GetServicesParams, error) {
|
||||
|
||||
var postData *model.GetServicesParams
|
||||
@ -289,229 +267,6 @@ func DoesExistInSlice(item string, list []string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func parseSpanFilterRequestBody(r *http.Request) (*model.SpanFilterParams, error) {
|
||||
|
||||
var postData *model.SpanFilterParams
|
||||
err := json.NewDecoder(r.Body).Decode(&postData)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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 parseFilteredSpansRequest(r *http.Request, aH *APIHandler) (*model.GetFilteredSpansParams, error) {
|
||||
|
||||
var postData *model.GetFilteredSpansParams
|
||||
err := json.NewDecoder(r.Body).Decode(&postData)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
if postData.Limit == 0 {
|
||||
postData.Limit = 10
|
||||
}
|
||||
|
||||
if len(postData.Order) != 0 {
|
||||
if postData.Order != baseconstants.Ascending && postData.Order != baseconstants.Descending {
|
||||
return nil, errors.New("order param is not in correct format")
|
||||
}
|
||||
if postData.OrderParam != baseconstants.Duration && postData.OrderParam != baseconstants.Timestamp {
|
||||
return nil, errors.New("order param is not in correct format")
|
||||
}
|
||||
if postData.OrderParam == baseconstants.Duration && !aH.CheckFeature(baseconstants.DurationSort) {
|
||||
return nil, model.ErrFeatureUnavailable{Key: baseconstants.DurationSort}
|
||||
} else if postData.OrderParam == baseconstants.Timestamp && !aH.CheckFeature(baseconstants.TimestampSort) {
|
||||
return nil, model.ErrFeatureUnavailable{Key: baseconstants.TimestampSort}
|
||||
}
|
||||
}
|
||||
tags, err := extractTagKeys(postData.Tags)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
postData.Tags = tags
|
||||
return postData, nil
|
||||
}
|
||||
|
||||
func parseFilteredSpanAggregatesRequest(r *http.Request) (*model.GetFilteredSpanAggregatesParams, error) {
|
||||
|
||||
var postData *model.GetFilteredSpanAggregatesParams
|
||||
err := json.NewDecoder(r.Body).Decode(&postData)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
step := postData.StepSeconds
|
||||
if step == 0 {
|
||||
return nil, errors.New("step param missing in query")
|
||||
}
|
||||
|
||||
function := postData.Function
|
||||
if len(function) == 0 {
|
||||
return nil, errors.New("function param missing in query")
|
||||
} else {
|
||||
if !DoesExistInSlice(function, allowedFunctions) {
|
||||
return nil, fmt.Errorf("given function: %s is not allowed in query", function)
|
||||
}
|
||||
}
|
||||
|
||||
var dimension, aggregationOption string
|
||||
|
||||
switch function {
|
||||
case "count":
|
||||
dimension = "calls"
|
||||
aggregationOption = "count"
|
||||
case "ratePerSec":
|
||||
dimension = "calls"
|
||||
aggregationOption = "rate_per_sec"
|
||||
case "avg":
|
||||
dimension = "duration"
|
||||
aggregationOption = "avg"
|
||||
case "sum":
|
||||
dimension = "duration"
|
||||
aggregationOption = "sum"
|
||||
case "p50":
|
||||
dimension = "duration"
|
||||
aggregationOption = "p50"
|
||||
case "p90":
|
||||
dimension = "duration"
|
||||
aggregationOption = "p90"
|
||||
case "p95":
|
||||
dimension = "duration"
|
||||
aggregationOption = "p95"
|
||||
case "p99":
|
||||
dimension = "duration"
|
||||
aggregationOption = "p99"
|
||||
case "min":
|
||||
dimension = "duration"
|
||||
aggregationOption = "min"
|
||||
case "max":
|
||||
dimension = "duration"
|
||||
aggregationOption = "max"
|
||||
}
|
||||
|
||||
postData.AggregationOption = aggregationOption
|
||||
postData.Dimension = dimension
|
||||
tags, err := extractTagKeys(postData.Tags)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
postData.Tags = tags
|
||||
|
||||
return postData, nil
|
||||
}
|
||||
|
||||
func extractTagKeys(tags []model.TagQueryParam) ([]model.TagQueryParam, error) {
|
||||
newTags := make([]model.TagQueryParam, 0)
|
||||
if len(tags) != 0 {
|
||||
for _, tag := range tags {
|
||||
customStr := strings.Split(tag.Key, ".(")
|
||||
if len(customStr) < 2 {
|
||||
return nil, fmt.Errorf("TagKey param is not valid in query")
|
||||
} else {
|
||||
tag.Key = customStr[0]
|
||||
}
|
||||
if tag.Operator == model.ExistsOperator || tag.Operator == model.NotExistsOperator {
|
||||
if customStr[1] == string(model.TagTypeString)+")" {
|
||||
tag.StringValues = []string{" "}
|
||||
} else if customStr[1] == string(model.TagTypeBool)+")" {
|
||||
tag.BoolValues = []bool{true}
|
||||
} else if customStr[1] == string(model.TagTypeNumber)+")" {
|
||||
tag.NumberValues = []float64{0}
|
||||
} else {
|
||||
return nil, fmt.Errorf("TagKey param is not valid in query")
|
||||
}
|
||||
}
|
||||
newTags = append(newTags, tag)
|
||||
}
|
||||
}
|
||||
return newTags, nil
|
||||
}
|
||||
|
||||
func parseTagFilterRequest(r *http.Request) (*model.TagFilterParams, error) {
|
||||
var postData *model.TagFilterParams
|
||||
err := json.NewDecoder(r.Body).Decode(&postData)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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 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 == (model.TagKey{}) {
|
||||
return nil, fmt.Errorf("TagKey param missing in query")
|
||||
}
|
||||
|
||||
if postData.TagKey.Type != model.TagTypeString && postData.TagKey.Type != model.TagTypeBool && postData.TagKey.Type != model.TagTypeNumber {
|
||||
return nil, fmt.Errorf("tag keys type %s is not supported", postData.TagKey.Type)
|
||||
}
|
||||
|
||||
if postData.Limit == 0 {
|
||||
postData.Limit = 100
|
||||
}
|
||||
|
||||
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 parseListErrorsRequest(r *http.Request) (*model.ListErrorsParams, error) {
|
||||
|
||||
var allowedOrderParams = []string{"exceptionType", "exceptionCount", "firstSeen", "lastSeen", "serviceName"}
|
||||
|
@ -16,7 +16,6 @@ import (
|
||||
type Reader interface {
|
||||
GetInstantQueryMetricsResult(ctx context.Context, query *model.InstantQueryMetricsParams) (*promql.Result, *stats.QueryStats, *model.ApiError)
|
||||
GetQueryRangeResult(ctx context.Context, query *model.QueryRangeParams) (*promql.Result, *stats.QueryStats, *model.ApiError)
|
||||
GetServiceOverview(ctx context.Context, query *model.GetServiceOverviewParams, skipConfig *model.SkipConfig) (*[]model.ServiceOverviewItem, *model.ApiError)
|
||||
GetTopLevelOperations(ctx context.Context, skipConfig *model.SkipConfig, start, end time.Time, services []string) (*map[string][]string, *model.ApiError)
|
||||
GetServices(ctx context.Context, query *model.GetServicesParams, skipConfig *model.SkipConfig) (*[]model.ServiceItem, *model.ApiError)
|
||||
GetTopOperations(ctx context.Context, query *model.GetTopOperationsParams) (*[]model.TopOperationsItem, *model.ApiError)
|
||||
|
Loading…
x
Reference in New Issue
Block a user