mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-06-04 11:25:52 +08:00
477 lines
12 KiB
Go
477 lines
12 KiB
Go
package app
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"strconv"
|
|
"time"
|
|
|
|
"go.signoz.io/query-service/model"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
var allowedDimesions = []string{"calls", "duration"}
|
|
|
|
var allowedAggregations = map[string][]string{
|
|
"calls": []string{"count", "rate_per_sec"},
|
|
"duration": []string{"avg", "p50", "p95", "p99"},
|
|
}
|
|
|
|
func parseGetTopEndpointsRequest(r *http.Request) (*model.GetTopEndpointsParams, error) {
|
|
startTime, err := parseTime("start", r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
endTime, err := parseTime("end", r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
serviceName := r.URL.Query().Get("service")
|
|
if len(serviceName) == 0 {
|
|
return nil, errors.New("serviceName param missing in query")
|
|
}
|
|
|
|
getTopEndpointsParams := model.GetTopEndpointsParams{
|
|
StartTime: startTime.Format(time.RFC3339Nano),
|
|
EndTime: endTime.Format(time.RFC3339Nano),
|
|
ServiceName: serviceName,
|
|
Start: startTime,
|
|
End: endTime,
|
|
}
|
|
|
|
return &getTopEndpointsParams, nil
|
|
|
|
}
|
|
|
|
func parseGetUsageRequest(r *http.Request) (*model.GetUsageParams, error) {
|
|
startTime, err := parseTime("start", r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
endTime, err := parseTime("end", r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
stepStr := r.URL.Query().Get("step")
|
|
if len(stepStr) == 0 {
|
|
return nil, errors.New("step param missing in query")
|
|
}
|
|
stepInt, err := strconv.Atoi(stepStr)
|
|
if err != nil {
|
|
return nil, errors.New("step param is not in correct format")
|
|
}
|
|
|
|
serviceName := r.URL.Query().Get("service")
|
|
stepHour := stepInt / 3600
|
|
|
|
getUsageParams := model.GetUsageParams{
|
|
StartTime: startTime.Format(time.RFC3339Nano),
|
|
EndTime: endTime.Format(time.RFC3339Nano),
|
|
Start: startTime,
|
|
End: endTime,
|
|
ServiceName: serviceName,
|
|
Period: fmt.Sprintf("PT%dH", stepHour),
|
|
StepHour: stepHour,
|
|
}
|
|
|
|
return &getUsageParams, nil
|
|
|
|
}
|
|
|
|
func parseGetServiceExternalRequest(r *http.Request) (*model.GetServiceOverviewParams, error) {
|
|
startTime, err := parseTime("start", r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
endTime, err := parseTime("end", r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
stepStr := r.URL.Query().Get("step")
|
|
if len(stepStr) == 0 {
|
|
return nil, errors.New("step param missing in query")
|
|
}
|
|
stepInt, err := strconv.Atoi(stepStr)
|
|
if err != nil {
|
|
return nil, errors.New("step param is not in correct format")
|
|
}
|
|
|
|
serviceName := r.URL.Query().Get("service")
|
|
if len(serviceName) == 0 {
|
|
return nil, errors.New("serviceName param missing in query")
|
|
}
|
|
|
|
getServiceOverviewParams := model.GetServiceOverviewParams{
|
|
Start: startTime,
|
|
StartTime: startTime.Format(time.RFC3339Nano),
|
|
End: endTime,
|
|
EndTime: endTime.Format(time.RFC3339Nano),
|
|
ServiceName: serviceName,
|
|
Period: fmt.Sprintf("PT%dM", stepInt/60),
|
|
StepSeconds: stepInt,
|
|
}
|
|
|
|
return &getServiceOverviewParams, nil
|
|
|
|
}
|
|
|
|
func parseGetServiceOverviewRequest(r *http.Request) (*model.GetServiceOverviewParams, error) {
|
|
startTime, err := parseTime("start", r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
endTime, err := parseTime("end", r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
stepStr := r.URL.Query().Get("step")
|
|
if len(stepStr) == 0 {
|
|
return nil, errors.New("step param missing in query")
|
|
}
|
|
stepInt, err := strconv.Atoi(stepStr)
|
|
if err != nil {
|
|
return nil, errors.New("step param is not in correct format")
|
|
}
|
|
|
|
serviceName := r.URL.Query().Get("service")
|
|
if len(serviceName) == 0 {
|
|
return nil, errors.New("serviceName param missing in query")
|
|
}
|
|
|
|
getServiceOverviewParams := model.GetServiceOverviewParams{
|
|
Start: startTime,
|
|
StartTime: startTime.Format(time.RFC3339Nano),
|
|
End: endTime,
|
|
EndTime: endTime.Format(time.RFC3339Nano),
|
|
ServiceName: serviceName,
|
|
Period: fmt.Sprintf("PT%dM", stepInt/60),
|
|
StepSeconds: stepInt,
|
|
}
|
|
|
|
return &getServiceOverviewParams, nil
|
|
|
|
}
|
|
|
|
func parseGetServicesRequest(r *http.Request) (*model.GetServicesParams, error) {
|
|
|
|
startTime, err := parseTime("start", r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
endTime, err := parseTime("end", r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
getServicesParams := model.GetServicesParams{
|
|
Start: startTime,
|
|
StartTime: startTime.Format(time.RFC3339Nano),
|
|
End: endTime,
|
|
EndTime: endTime.Format(time.RFC3339Nano),
|
|
Period: int(endTime.Unix() - startTime.Unix()),
|
|
}
|
|
return &getServicesParams, nil
|
|
|
|
}
|
|
|
|
func DoesExistInSlice(item string, list []string) bool {
|
|
for _, element := range list {
|
|
if item == element {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func parseSearchSpanAggregatesRequest(r *http.Request) (*model.SpanSearchAggregatesParams, error) {
|
|
|
|
startTime, err := parseTime("start", r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
endTime, err := parseTime("end", r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
startTimeStr := startTime.Format(time.RFC3339Nano)
|
|
endTimeStr := endTime.Format(time.RFC3339Nano)
|
|
// fmt.Println(startTimeStr)
|
|
|
|
stepStr := r.URL.Query().Get("step")
|
|
if len(stepStr) == 0 {
|
|
return nil, errors.New("step param missing in query")
|
|
}
|
|
|
|
stepInt, err := strconv.Atoi(stepStr)
|
|
if err != nil {
|
|
return nil, errors.New("step param is not in correct format")
|
|
}
|
|
|
|
granPeriod := fmt.Sprintf("PT%dM", stepInt/60)
|
|
dimension := r.URL.Query().Get("dimension")
|
|
if len(dimension) == 0 {
|
|
return nil, errors.New("dimension param missing in query")
|
|
} else {
|
|
if !DoesExistInSlice(dimension, allowedDimesions) {
|
|
return nil, errors.New(fmt.Sprintf("given dimension: %s is not allowed in query", dimension))
|
|
}
|
|
}
|
|
|
|
aggregationOption := r.URL.Query().Get("aggregation_option")
|
|
if len(aggregationOption) == 0 {
|
|
return nil, errors.New("Aggregation Option missing in query params")
|
|
} else {
|
|
if !DoesExistInSlice(aggregationOption, allowedAggregations[dimension]) {
|
|
return nil, errors.New(fmt.Sprintf("given aggregation option: %s is not allowed with dimension: %s", aggregationOption, dimension))
|
|
}
|
|
}
|
|
|
|
params := &model.SpanSearchAggregatesParams{
|
|
Start: startTime,
|
|
End: endTime,
|
|
Intervals: fmt.Sprintf("%s/%s", startTimeStr, endTimeStr),
|
|
GranOrigin: startTimeStr,
|
|
GranPeriod: granPeriod,
|
|
StepSeconds: stepInt,
|
|
Dimension: dimension,
|
|
AggregationOption: aggregationOption,
|
|
}
|
|
|
|
serviceName := r.URL.Query().Get("service")
|
|
if len(serviceName) != 0 {
|
|
// return nil, errors.New("serviceName param missing in query")
|
|
params.ServiceName = serviceName
|
|
}
|
|
operationName := r.URL.Query().Get("operation")
|
|
if len(operationName) != 0 {
|
|
params.OperationName = operationName
|
|
zap.S().Debug("Operation Name: ", operationName)
|
|
}
|
|
|
|
kind := r.URL.Query().Get("kind")
|
|
if len(kind) != 0 {
|
|
params.Kind = kind
|
|
zap.S().Debug("Kind: ", kind)
|
|
}
|
|
|
|
minDuration, err := parseTimestamp("minDuration", r)
|
|
if err == nil {
|
|
params.MinDuration = *minDuration
|
|
}
|
|
maxDuration, err := parseTimestamp("maxDuration", r)
|
|
if err == nil {
|
|
params.MaxDuration = *maxDuration
|
|
}
|
|
|
|
tags, err := parseTags("tags", r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(*tags) != 0 {
|
|
params.Tags = *tags
|
|
}
|
|
|
|
return params, nil
|
|
}
|
|
|
|
func parseSpanSearchRequest(r *http.Request) (*model.SpanSearchParams, error) {
|
|
|
|
startTime, err := parseTime("start", r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
endTime, err := parseTimeMinusBuffer("end", r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
startTimeStr := startTime.Format(time.RFC3339Nano)
|
|
endTimeStr := endTime.Format(time.RFC3339Nano)
|
|
// fmt.Println(startTimeStr)
|
|
params := &model.SpanSearchParams{
|
|
Intervals: fmt.Sprintf("%s/%s", startTimeStr, endTimeStr),
|
|
Start: startTime,
|
|
End: endTime,
|
|
Limit: 100,
|
|
Order: "descending",
|
|
}
|
|
|
|
serviceName := r.URL.Query().Get("service")
|
|
if len(serviceName) != 0 {
|
|
// return nil, errors.New("serviceName param missing in query")
|
|
params.ServiceName = serviceName
|
|
}
|
|
operationName := r.URL.Query().Get("operation")
|
|
if len(operationName) != 0 {
|
|
params.OperationName = operationName
|
|
zap.S().Debug("Operation Name: ", operationName)
|
|
}
|
|
|
|
kind := r.URL.Query().Get("kind")
|
|
if len(kind) != 0 {
|
|
params.Kind = kind
|
|
zap.S().Debug("Kind: ", kind)
|
|
}
|
|
|
|
minDuration, err := parseTimestamp("minDuration", r)
|
|
if err == nil {
|
|
params.MinDuration = *minDuration
|
|
}
|
|
maxDuration, err := parseTimestamp("maxDuration", r)
|
|
if err == nil {
|
|
params.MaxDuration = *maxDuration
|
|
}
|
|
|
|
limitStr := r.URL.Query().Get("limit")
|
|
if len(limitStr) != 0 {
|
|
limit, err := strconv.ParseInt(limitStr, 10, 64)
|
|
if err != nil {
|
|
return nil, errors.New("Limit param is not in correct format")
|
|
}
|
|
params.Limit = limit
|
|
} else {
|
|
params.Limit = 100
|
|
}
|
|
|
|
offsetStr := r.URL.Query().Get("offset")
|
|
if len(offsetStr) != 0 {
|
|
offset, err := strconv.ParseInt(offsetStr, 10, 64)
|
|
if err != nil {
|
|
return nil, errors.New("Offset param is not in correct format")
|
|
}
|
|
params.Offset = offset
|
|
}
|
|
|
|
tags, err := parseTags("tags", r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(*tags) != 0 {
|
|
params.Tags = *tags
|
|
}
|
|
|
|
return params, nil
|
|
}
|
|
|
|
func parseTags(param string, r *http.Request) (*[]model.TagQuery, error) {
|
|
|
|
tags := new([]model.TagQuery)
|
|
tagsStr := r.URL.Query().Get(param)
|
|
|
|
if len(tagsStr) == 0 {
|
|
return tags, nil
|
|
}
|
|
err := json.Unmarshal([]byte(tagsStr), tags)
|
|
if err != nil {
|
|
zap.S().Error("Error in parsig tags", zap.Error(err))
|
|
return nil, fmt.Errorf("error in parsing %s ", param)
|
|
}
|
|
// zap.S().Info("Tags: ", *tags)
|
|
|
|
return tags, nil
|
|
}
|
|
|
|
func parseApplicationPercentileRequest(r *http.Request) (*model.ApplicationPercentileParams, error) {
|
|
|
|
startTime, err := parseTime("start", r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
endTime, err := parseTime("end", r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
stepStr := r.URL.Query().Get("step")
|
|
if len(stepStr) == 0 {
|
|
return nil, errors.New("step param missing in query")
|
|
}
|
|
|
|
serviceName := r.URL.Query().Get("service")
|
|
if len(serviceName) == 0 {
|
|
return nil, errors.New("serviceName param missing in query")
|
|
}
|
|
|
|
startTimeStr := startTime.Format(time.RFC3339Nano)
|
|
endTimeStr := endTime.Format(time.RFC3339Nano)
|
|
|
|
params := &model.ApplicationPercentileParams{
|
|
ServiceName: serviceName,
|
|
GranOrigin: startTimeStr,
|
|
Intervals: fmt.Sprintf("%s/%s", startTimeStr, endTimeStr),
|
|
}
|
|
|
|
stepInt, err := strconv.Atoi(stepStr)
|
|
if err != nil {
|
|
return nil, errors.New("step param is not in correct format")
|
|
}
|
|
|
|
params.SetGranPeriod(stepInt)
|
|
|
|
return params, nil
|
|
|
|
}
|
|
|
|
func parseTime(param string, r *http.Request) (*time.Time, error) {
|
|
|
|
timeStr := r.URL.Query().Get(param)
|
|
if len(timeStr) == 0 {
|
|
return nil, fmt.Errorf("%s param missing in query", param)
|
|
}
|
|
|
|
timeUnix, err := strconv.ParseInt(timeStr, 10, 64)
|
|
if err != nil || len(timeStr) == 0 {
|
|
return nil, fmt.Errorf("%s param is not in correct timestamp format", param)
|
|
}
|
|
|
|
timeFmt := time.Unix(0, timeUnix)
|
|
|
|
return &timeFmt, nil
|
|
|
|
}
|
|
|
|
func parseTimeMinusBuffer(param string, r *http.Request) (*time.Time, error) {
|
|
|
|
timeStr := r.URL.Query().Get(param)
|
|
if len(timeStr) == 0 {
|
|
return nil, fmt.Errorf("%s param missing in query", param)
|
|
}
|
|
|
|
timeUnix, err := strconv.ParseInt(timeStr, 10, 64)
|
|
if err != nil || len(timeStr) == 0 {
|
|
return nil, fmt.Errorf("%s param is not in correct timestamp format", param)
|
|
}
|
|
|
|
timeUnixNow := time.Now().UnixNano()
|
|
if timeUnix > timeUnixNow-30000000000 {
|
|
timeUnix = timeUnix - 30000000000
|
|
}
|
|
|
|
timeFmt := time.Unix(0, timeUnix)
|
|
|
|
return &timeFmt, nil
|
|
|
|
}
|
|
|
|
func parseTimestamp(param string, r *http.Request) (*string, error) {
|
|
timeStr := r.URL.Query().Get(param)
|
|
if len(timeStr) == 0 {
|
|
return nil, fmt.Errorf("%s param missing in query", param)
|
|
}
|
|
|
|
// timeUnix, err := strconv.ParseInt(timeStr, 10, 64)
|
|
// if err != nil || len(timeStr) == 0 {
|
|
// return nil, fmt.Errorf("%s param is not in correct timestamp format", param)
|
|
// }
|
|
|
|
return &timeStr, nil
|
|
|
|
}
|