mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-14 16:55:54 +08:00
New Trace Filter Page API changes (Backend) (#646)
* build: integrate sql migrations for clickhouse * feat: support error/exception attributes for trace * chore: fixing dependencies for docker go client libs * feat: get trace filter api checkpoint * chore: fixing dependencies for go-migrate * feat: add new columns * feat: move mirgate run from docker to code * fix: migration file 404 issue * feat: getSpanFilter API * fix: migrate version naming bug * chore: change url param format to array * feat: add getTagFilter API * feat: add getFilteredSpans API * fix: using OFFSET in sqlx driver * feat: aggregates API on getFilteredSpan, use IN and NOT IN for tag filtering * feat: add more function support to span aggregate API * fix: null component edge case * feat: groupBy support for filteredSpanAggregate * feat: add function param to span aggregate API * feat: add support to return totalSpans in getFilteredSpans API * fix: don't return null string as keys in span filters * chore: remove SQL migrations(moved to otel collector) * fix: null string issue in aggregate API * Merge main * fix: trace API db query param * fix: signoz sql db path * fix: case when both error and ok status are selected Co-authored-by: Ankit Nayan <ankit@signoz.io>
This commit is contained in:
parent
dcb17fb33a
commit
0ab91707e9
@ -11,7 +11,6 @@ services:
|
||||
- 8123:8123
|
||||
volumes:
|
||||
- ./clickhouse-config.xml:/etc/clickhouse-server/config.xml
|
||||
- ./docker-entrypoint-initdb.d/init-db.sql:/docker-entrypoint-initdb.d/init-db.sql
|
||||
- ./data/clickhouse/:/var/lib/clickhouse/
|
||||
|
||||
healthcheck:
|
||||
|
@ -1,31 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS signoz_index (
|
||||
timestamp DateTime64(9) CODEC(Delta, ZSTD(1)),
|
||||
traceID String CODEC(ZSTD(1)),
|
||||
spanID String CODEC(ZSTD(1)),
|
||||
parentSpanID String CODEC(ZSTD(1)),
|
||||
serviceName LowCardinality(String) CODEC(ZSTD(1)),
|
||||
name LowCardinality(String) CODEC(ZSTD(1)),
|
||||
kind Int32 CODEC(ZSTD(1)),
|
||||
durationNano UInt64 CODEC(ZSTD(1)),
|
||||
tags Array(String) CODEC(ZSTD(1)),
|
||||
tagsKeys Array(String) CODEC(ZSTD(1)),
|
||||
tagsValues Array(String) CODEC(ZSTD(1)),
|
||||
statusCode Int64 CODEC(ZSTD(1)),
|
||||
references String CODEC(ZSTD(1)),
|
||||
externalHttpMethod Nullable(String) CODEC(ZSTD(1)),
|
||||
externalHttpUrl Nullable(String) CODEC(ZSTD(1)),
|
||||
component Nullable(String) CODEC(ZSTD(1)),
|
||||
dbSystem Nullable(String) CODEC(ZSTD(1)),
|
||||
dbName Nullable(String) CODEC(ZSTD(1)),
|
||||
dbOperation Nullable(String) CODEC(ZSTD(1)),
|
||||
peerService Nullable(String) CODEC(ZSTD(1)),
|
||||
INDEX idx_traceID traceID TYPE bloom_filter GRANULARITY 4,
|
||||
INDEX idx_service serviceName TYPE bloom_filter GRANULARITY 4,
|
||||
INDEX idx_name name TYPE bloom_filter GRANULARITY 4,
|
||||
INDEX idx_kind kind TYPE minmax GRANULARITY 4,
|
||||
INDEX idx_tagsKeys tagsKeys TYPE bloom_filter(0.01) GRANULARITY 64,
|
||||
INDEX idx_tagsValues tagsValues TYPE bloom_filter(0.01) GRANULARITY 64,
|
||||
INDEX idx_duration durationNano TYPE minmax GRANULARITY 1
|
||||
) ENGINE MergeTree()
|
||||
PARTITION BY toDate(timestamp)
|
||||
ORDER BY (serviceName, -toUnixTimestamp(timestamp))
|
File diff suppressed because it is too large
Load Diff
@ -165,6 +165,22 @@ func (druid *DruidReader) GetTTL(_ context.Context, _ *model.GetTTLParams) (*mod
|
||||
return nil, &model.ApiError{model.ErrorNotImplemented, fmt.Errorf("druid does not support setting ttl configuration")}
|
||||
}
|
||||
|
||||
func (druid *DruidReader) GetSpanFilters(_ context.Context, _ *model.SpanFilterParams) (*model.SpanFiltersResponse, *model.ApiError) {
|
||||
return nil, &model.ApiError{model.ErrorNotImplemented, fmt.Errorf("druid does not support getting spanfilters")}
|
||||
}
|
||||
|
||||
func (druid *DruidReader) GetTagFilters(_ context.Context, _ *model.TagFilterParams) (*[]model.TagFilters, *model.ApiError) {
|
||||
return nil, &model.ApiError{model.ErrorNotImplemented, fmt.Errorf("druid does not support getting tagFilters")}
|
||||
}
|
||||
|
||||
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")}
|
||||
}
|
||||
|
||||
func (druid *DruidReader) GetFilteredSpansAggregates(_ context.Context, _ *model.GetFilteredSpanAggregatesParams) (*model.GetFilteredSpansAggregatesResponse, *model.ApiError) {
|
||||
return nil, &model.ApiError{model.ErrorNotImplemented, fmt.Errorf("druid does not support getting FilteredSpans")}
|
||||
}
|
||||
|
||||
func (druid *DruidReader) GetErrors(_ context.Context, _ *model.GetErrorsParams) (*[]model.Error, *model.ApiError) {
|
||||
return nil, &model.ApiError{model.ErrorNotImplemented, fmt.Errorf("druid does not support get error API")}
|
||||
}
|
||||
|
@ -203,6 +203,10 @@ func (aH *APIHandler) RegisterRoutes(router *mux.Router) {
|
||||
router.HandleFunc("/api/v1/serviceMapDependencies", aH.serviceMapDependencies).Methods(http.MethodGet)
|
||||
router.HandleFunc("/api/v1/settings/ttl", aH.setTTL).Methods(http.MethodPost)
|
||||
router.HandleFunc("/api/v1/settings/ttl", aH.getTTL).Methods(http.MethodGet)
|
||||
router.HandleFunc("/api/v1/getSpanFilters", aH.getSpanFilters).Methods(http.MethodGet)
|
||||
router.HandleFunc("/api/v1/getTagFilters", aH.getTagFilters).Methods(http.MethodGet)
|
||||
router.HandleFunc("/api/v1/getFilteredSpans", aH.getFilteredSpans).Methods(http.MethodGet)
|
||||
router.HandleFunc("/api/v1/getFilteredSpans/aggregates", aH.getFilteredSpanAggregates).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/errorWithType", aH.getErrorForType).Methods(http.MethodGet)
|
||||
@ -965,6 +969,70 @@ func (aH *APIHandler) searchSpans(w http.ResponseWriter, r *http.Request) {
|
||||
aH.writeJSON(w, r, result)
|
||||
}
|
||||
|
||||
func (aH *APIHandler) getSpanFilters(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
query, err := parseSpanFilterRequest(r)
|
||||
if aH.handleError(w, err, http.StatusBadRequest) {
|
||||
return
|
||||
}
|
||||
|
||||
result, apiErr := (*aH.reader).GetSpanFilters(context.Background(), query)
|
||||
|
||||
if apiErr != nil && aH.handleError(w, apiErr.Err, http.StatusInternalServerError) {
|
||||
return
|
||||
}
|
||||
|
||||
aH.writeJSON(w, r, result)
|
||||
}
|
||||
|
||||
func (aH *APIHandler) getFilteredSpans(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
query, err := parseFilteredSpansRequest(r)
|
||||
if aH.handleError(w, err, http.StatusBadRequest) {
|
||||
return
|
||||
}
|
||||
|
||||
result, apiErr := (*aH.reader).GetFilteredSpans(context.Background(), query)
|
||||
|
||||
if apiErr != nil && aH.handleError(w, apiErr.Err, http.StatusInternalServerError) {
|
||||
return
|
||||
}
|
||||
|
||||
aH.writeJSON(w, r, result)
|
||||
}
|
||||
|
||||
func (aH *APIHandler) getFilteredSpanAggregates(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
query, err := parseFilteredSpanAggregatesRequest(r)
|
||||
if aH.handleError(w, err, http.StatusBadRequest) {
|
||||
return
|
||||
}
|
||||
|
||||
result, apiErr := (*aH.reader).GetFilteredSpansAggregates(context.Background(), query)
|
||||
|
||||
if apiErr != nil && aH.handleError(w, apiErr.Err, http.StatusInternalServerError) {
|
||||
return
|
||||
}
|
||||
|
||||
aH.writeJSON(w, r, result)
|
||||
}
|
||||
|
||||
func (aH *APIHandler) getTagFilters(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
query, err := parseTagFilterRequest(r)
|
||||
if aH.handleError(w, err, http.StatusBadRequest) {
|
||||
return
|
||||
}
|
||||
|
||||
result, apiErr := (*aH.reader).GetTagFilters(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) {
|
||||
|
@ -37,6 +37,11 @@ type Reader interface {
|
||||
GetServicesList(ctx context.Context) (*[]string, error)
|
||||
GetServiceMapDependencies(ctx context.Context, query *model.GetServicesParams) (*[]model.ServiceMapDependencyResponseItem, error)
|
||||
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)
|
||||
GetFilteredSpans(ctx context.Context, query *model.GetFilteredSpansParams) (*model.GetFilterSpansResponse, *model.ApiError)
|
||||
GetFilteredSpansAggregates(ctx context.Context, query *model.GetFilteredSpanAggregatesParams) (*model.GetFilteredSpansAggregatesResponse, *model.ApiError)
|
||||
|
||||
GetErrors(ctx context.Context, params *model.GetErrorsParams) (*[]model.Error, *model.ApiError)
|
||||
GetErrorForId(ctx context.Context, params *model.GetErrorParams) (*model.ErrorWithSpan, *model.ApiError)
|
||||
GetErrorForType(ctx context.Context, params *model.GetErrorParams) (*model.ErrorWithSpan, *model.ApiError)
|
||||
|
@ -19,9 +19,11 @@ import (
|
||||
|
||||
var allowedDimesions = []string{"calls", "duration"}
|
||||
|
||||
var allowedFunctions = []string{"count", "ratePerSec", "sum", "avg", "min", "max", "p50", "p90", "p95", "p99"}
|
||||
|
||||
var allowedAggregations = map[string][]string{
|
||||
"calls": {"count", "rate_per_sec"},
|
||||
"duration": {"avg", "p50", "p95", "p99"},
|
||||
"duration": {"avg", "p50", "p95", "p90", "p99", "min", "max", "sum"},
|
||||
}
|
||||
|
||||
func parseUser(r *http.Request) (*model.User, error) {
|
||||
@ -480,6 +482,284 @@ func parseSpanSearchRequest(r *http.Request) (*model.SpanSearchParams, error) {
|
||||
return params, nil
|
||||
}
|
||||
|
||||
func parseSpanFilterRequest(r *http.Request) (*model.SpanFilterParams, error) {
|
||||
|
||||
startTime, err := parseTime("start", r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
endTime, err := parseTimeMinusBuffer("end", r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
params := &model.SpanFilterParams{
|
||||
Start: startTime,
|
||||
End: endTime,
|
||||
ServiceName: []string{},
|
||||
HttpRoute: []string{},
|
||||
HttpCode: []string{},
|
||||
HttpUrl: []string{},
|
||||
HttpHost: []string{},
|
||||
HttpMethod: []string{},
|
||||
Component: []string{},
|
||||
Status: []string{},
|
||||
Operation: []string{},
|
||||
GetFilters: []string{},
|
||||
}
|
||||
|
||||
params.ServiceName = fetchArrayValues("serviceName", r)
|
||||
|
||||
params.Status = fetchArrayValues("status", r)
|
||||
|
||||
params.Operation = fetchArrayValues("operation", r)
|
||||
|
||||
params.HttpCode = fetchArrayValues("httpCode", r)
|
||||
|
||||
params.HttpUrl = fetchArrayValues("httpUrl", r)
|
||||
|
||||
params.HttpHost = fetchArrayValues("httpHost", r)
|
||||
|
||||
params.HttpRoute = fetchArrayValues("httpRoute", r)
|
||||
|
||||
params.HttpMethod = fetchArrayValues("httpMethod", r)
|
||||
|
||||
params.Component = fetchArrayValues("component", r)
|
||||
|
||||
params.GetFilters = fetchArrayValues("getFilters", r)
|
||||
|
||||
minDuration, err := parseTimestamp("minDuration", r)
|
||||
if err == nil {
|
||||
params.MinDuration = *minDuration
|
||||
}
|
||||
maxDuration, err := parseTimestamp("maxDuration", r)
|
||||
if err == nil {
|
||||
params.MaxDuration = *maxDuration
|
||||
}
|
||||
|
||||
return params, nil
|
||||
}
|
||||
|
||||
func parseFilteredSpansRequest(r *http.Request) (*model.GetFilteredSpansParams, error) {
|
||||
|
||||
startTime, err := parseTime("start", r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
endTime, err := parseTimeMinusBuffer("end", r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
params := &model.GetFilteredSpansParams{
|
||||
Start: startTime,
|
||||
End: endTime,
|
||||
ServiceName: []string{},
|
||||
HttpRoute: []string{},
|
||||
HttpCode: []string{},
|
||||
HttpUrl: []string{},
|
||||
HttpHost: []string{},
|
||||
HttpMethod: []string{},
|
||||
Component: []string{},
|
||||
Status: []string{},
|
||||
Operation: []string{},
|
||||
Limit: 100,
|
||||
Order: "descending",
|
||||
}
|
||||
|
||||
params.ServiceName = fetchArrayValues("serviceName", r)
|
||||
|
||||
params.Status = fetchArrayValues("status", r)
|
||||
|
||||
params.Operation = fetchArrayValues("operation", r)
|
||||
|
||||
params.HttpCode = fetchArrayValues("httpCode", r)
|
||||
|
||||
params.HttpUrl = fetchArrayValues("httpUrl", r)
|
||||
|
||||
params.HttpHost = fetchArrayValues("httpHost", r)
|
||||
|
||||
params.HttpRoute = fetchArrayValues("httpRoute", r)
|
||||
|
||||
params.HttpMethod = fetchArrayValues("httpMethod", r)
|
||||
|
||||
params.Component = fetchArrayValues("component", r)
|
||||
|
||||
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 := parseTagsV2("tags", r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(*tags) != 0 {
|
||||
params.Tags = *tags
|
||||
}
|
||||
|
||||
minDuration, err := parseTimestamp("minDuration", r)
|
||||
if err == nil {
|
||||
params.MinDuration = *minDuration
|
||||
}
|
||||
maxDuration, err := parseTimestamp("maxDuration", r)
|
||||
if err == nil {
|
||||
params.MaxDuration = *maxDuration
|
||||
}
|
||||
|
||||
kind := r.URL.Query().Get("kind")
|
||||
if len(kind) != 0 {
|
||||
params.Kind = kind
|
||||
}
|
||||
|
||||
return params, nil
|
||||
}
|
||||
|
||||
func parseFilteredSpanAggregatesRequest(r *http.Request) (*model.GetFilteredSpanAggregatesParams, error) {
|
||||
|
||||
startTime, err := parseTime("start", r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
endTime, err := parseTimeMinusBuffer("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")
|
||||
}
|
||||
|
||||
function := r.URL.Query().Get("function")
|
||||
if len(function) == 0 {
|
||||
return nil, errors.New("function param missing in query")
|
||||
} else {
|
||||
if !DoesExistInSlice(function, allowedFunctions) {
|
||||
return nil, errors.New(fmt.Sprintf("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"
|
||||
}
|
||||
|
||||
params := &model.GetFilteredSpanAggregatesParams{
|
||||
Start: startTime,
|
||||
End: endTime,
|
||||
ServiceName: []string{},
|
||||
HttpRoute: []string{},
|
||||
HttpCode: []string{},
|
||||
HttpUrl: []string{},
|
||||
HttpHost: []string{},
|
||||
HttpMethod: []string{},
|
||||
Component: []string{},
|
||||
Status: []string{},
|
||||
Operation: []string{},
|
||||
StepSeconds: stepInt,
|
||||
Dimension: dimension,
|
||||
AggregationOption: aggregationOption,
|
||||
}
|
||||
|
||||
params.ServiceName = fetchArrayValues("serviceName", r)
|
||||
|
||||
params.Status = fetchArrayValues("status", r)
|
||||
|
||||
params.Operation = fetchArrayValues("operation", r)
|
||||
|
||||
params.HttpCode = fetchArrayValues("httpCode", r)
|
||||
|
||||
params.HttpUrl = fetchArrayValues("httpUrl", r)
|
||||
|
||||
params.HttpHost = fetchArrayValues("httpHost", r)
|
||||
|
||||
params.HttpRoute = fetchArrayValues("httpRoute", r)
|
||||
|
||||
params.HttpMethod = fetchArrayValues("httpMethod", r)
|
||||
|
||||
params.Component = fetchArrayValues("component", r)
|
||||
|
||||
tags, err := parseTagsV2("tags", r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(*tags) != 0 {
|
||||
params.Tags = *tags
|
||||
}
|
||||
|
||||
minDuration, err := parseTimestamp("minDuration", r)
|
||||
if err == nil {
|
||||
params.MinDuration = *minDuration
|
||||
}
|
||||
maxDuration, err := parseTimestamp("maxDuration", r)
|
||||
if err == nil {
|
||||
params.MaxDuration = *maxDuration
|
||||
}
|
||||
|
||||
kind := r.URL.Query().Get("kind")
|
||||
if len(kind) != 0 {
|
||||
params.Kind = kind
|
||||
}
|
||||
groupBy := r.URL.Query().Get("groupBy")
|
||||
if len(groupBy) != 0 {
|
||||
params.GroupBy = groupBy
|
||||
}
|
||||
|
||||
return params, nil
|
||||
}
|
||||
|
||||
func parseErrorRequest(r *http.Request) (*model.GetErrorParams, error) {
|
||||
|
||||
params := &model.GetErrorParams{}
|
||||
@ -502,6 +782,60 @@ func parseErrorRequest(r *http.Request) (*model.GetErrorParams, error) {
|
||||
return params, nil
|
||||
}
|
||||
|
||||
func parseTagFilterRequest(r *http.Request) (*model.TagFilterParams, error) {
|
||||
|
||||
startTime, err := parseTime("start", r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
endTime, err := parseTimeMinusBuffer("end", r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
params := &model.TagFilterParams{
|
||||
Start: startTime,
|
||||
End: endTime,
|
||||
ServiceName: []string{},
|
||||
HttpRoute: []string{},
|
||||
HttpCode: []string{},
|
||||
HttpUrl: []string{},
|
||||
HttpHost: []string{},
|
||||
HttpMethod: []string{},
|
||||
Component: []string{},
|
||||
Status: []string{},
|
||||
Operation: []string{},
|
||||
}
|
||||
|
||||
params.ServiceName = fetchArrayValues("serviceName", r)
|
||||
|
||||
params.Status = fetchArrayValues("status", r)
|
||||
|
||||
params.Operation = fetchArrayValues("operation", r)
|
||||
|
||||
params.HttpCode = fetchArrayValues("httpCode", r)
|
||||
|
||||
params.HttpUrl = fetchArrayValues("httpUrl", r)
|
||||
|
||||
params.HttpHost = fetchArrayValues("httpHost", r)
|
||||
|
||||
params.HttpRoute = fetchArrayValues("httpRoute", r)
|
||||
|
||||
params.HttpMethod = fetchArrayValues("httpMethod", r)
|
||||
|
||||
params.Component = fetchArrayValues("component", r)
|
||||
|
||||
minDuration, err := parseTimestamp("minDuration", r)
|
||||
if err == nil {
|
||||
params.MinDuration = *minDuration
|
||||
}
|
||||
maxDuration, err := parseTimestamp("maxDuration", r)
|
||||
if err == nil {
|
||||
params.MaxDuration = *maxDuration
|
||||
}
|
||||
|
||||
return params, nil
|
||||
}
|
||||
func parseErrorsRequest(r *http.Request) (*model.GetErrorsParams, error) {
|
||||
|
||||
startTime, err := parseTime("start", r)
|
||||
@ -521,6 +855,19 @@ func parseErrorsRequest(r *http.Request) (*model.GetErrorsParams, error) {
|
||||
return params, nil
|
||||
}
|
||||
|
||||
func fetchArrayValues(param string, r *http.Request) []string {
|
||||
valueStr := r.URL.Query().Get(param)
|
||||
var values []string
|
||||
if len(valueStr) == 0 {
|
||||
return values
|
||||
}
|
||||
err := json.Unmarshal([]byte(valueStr), &values)
|
||||
if err != nil {
|
||||
zap.S().Error("Error in parsing service params", zap.Error(err))
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
func parseTags(param string, r *http.Request) (*[]model.TagQuery, error) {
|
||||
|
||||
tags := new([]model.TagQuery)
|
||||
@ -539,6 +886,24 @@ func parseTags(param string, r *http.Request) (*[]model.TagQuery, error) {
|
||||
return tags, nil
|
||||
}
|
||||
|
||||
func parseTagsV2(param string, r *http.Request) (*[]model.TagQueryV2, error) {
|
||||
|
||||
tags := new([]model.TagQueryV2)
|
||||
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)
|
||||
|
@ -78,6 +78,11 @@ type TagQuery struct {
|
||||
Operator string
|
||||
}
|
||||
|
||||
type TagQueryV2 struct {
|
||||
Key string
|
||||
Values []string
|
||||
Operator string
|
||||
}
|
||||
type SpanSearchAggregatesParams struct {
|
||||
ServiceName string
|
||||
OperationName string
|
||||
@ -111,6 +116,82 @@ type SpanSearchParams struct {
|
||||
Tags []TagQuery
|
||||
}
|
||||
|
||||
type GetFilteredSpansParams struct {
|
||||
ServiceName []string
|
||||
Operation []string
|
||||
Kind string
|
||||
Status []string
|
||||
HttpRoute []string
|
||||
HttpCode []string
|
||||
HttpUrl []string
|
||||
HttpHost []string
|
||||
HttpMethod []string
|
||||
Component []string
|
||||
Start *time.Time
|
||||
End *time.Time
|
||||
MinDuration string
|
||||
MaxDuration string
|
||||
Limit int64
|
||||
Order string
|
||||
Offset int64
|
||||
Tags []TagQueryV2
|
||||
}
|
||||
|
||||
type GetFilteredSpanAggregatesParams struct {
|
||||
ServiceName []string
|
||||
Operation []string
|
||||
Kind string
|
||||
Status []string
|
||||
HttpRoute []string
|
||||
HttpCode []string
|
||||
HttpUrl []string
|
||||
HttpHost []string
|
||||
HttpMethod []string
|
||||
Component []string
|
||||
MinDuration string
|
||||
MaxDuration string
|
||||
Tags []TagQueryV2
|
||||
Start *time.Time
|
||||
End *time.Time
|
||||
StepSeconds int
|
||||
Dimension string
|
||||
AggregationOption string
|
||||
GroupBy string
|
||||
Function string
|
||||
}
|
||||
|
||||
type SpanFilterParams struct {
|
||||
Status []string
|
||||
ServiceName []string
|
||||
HttpRoute []string
|
||||
HttpCode []string
|
||||
HttpUrl []string
|
||||
HttpHost []string
|
||||
HttpMethod []string
|
||||
Component []string
|
||||
Operation []string
|
||||
GetFilters []string
|
||||
MinDuration string
|
||||
MaxDuration string
|
||||
Start *time.Time
|
||||
End *time.Time
|
||||
}
|
||||
|
||||
type TagFilterParams struct {
|
||||
Status []string
|
||||
ServiceName []string
|
||||
HttpRoute []string
|
||||
HttpCode []string
|
||||
HttpUrl []string
|
||||
HttpHost []string
|
||||
HttpMethod []string
|
||||
Component []string
|
||||
Operation []string
|
||||
MinDuration string
|
||||
MaxDuration string
|
||||
Start *time.Time
|
||||
End *time.Time
|
||||
}
|
||||
type TTLParams struct {
|
||||
Type string
|
||||
Duration string
|
||||
|
@ -1,6 +1,7 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
@ -128,6 +129,22 @@ type SearchSpansResult struct {
|
||||
Events [][]interface{} `json:"events"`
|
||||
}
|
||||
|
||||
type GetFilterSpansResponseItem struct {
|
||||
Timestamp string `db:"timestamp" json:"timestamp"`
|
||||
SpanID string `db:"spanID" json:"spanID"`
|
||||
TraceID string `db:"traceID" json:"traceID"`
|
||||
ServiceName string `db:"serviceName" json:"serviceName"`
|
||||
Operation string `db:"name" json:"operation"`
|
||||
DurationNano int64 `db:"durationNano" json:"durationNano"`
|
||||
HttpCode string `db:"httpCode" json:"httpCode"`
|
||||
HttpMethod string `db:"httpMethod" json:"httpMethod"`
|
||||
}
|
||||
|
||||
type GetFilterSpansResponse struct {
|
||||
Spans []GetFilterSpansResponseItem `json:"spans"`
|
||||
TotalSpans int `json:"totalSpans"`
|
||||
}
|
||||
|
||||
type TraceResult struct {
|
||||
Data []interface{} `json:"data" db:"data"`
|
||||
Total int `json:"total" db:"total"`
|
||||
@ -247,6 +264,9 @@ type TagItem struct {
|
||||
TagCount int `json:"tagCount" db:"tagCount"`
|
||||
}
|
||||
|
||||
type TagFilters struct {
|
||||
TagKeys string `json:"tagKeys" db:"tagKeys"`
|
||||
}
|
||||
type ServiceMapDependencyResponseItem struct {
|
||||
Parent string `json:"parent,omitempty" db:"parent,omitempty"`
|
||||
Child string `json:"child,omitempty" db:"child,omitempty"`
|
||||
@ -259,6 +279,21 @@ type SpanSearchAggregatesResponseItem struct {
|
||||
Value float32 `json:"value,omitempty" db:"value"`
|
||||
}
|
||||
|
||||
type GetFilteredSpansAggregatesResponse struct {
|
||||
Items map[int64]SpanAggregatesResponseItem `json:"items"`
|
||||
}
|
||||
type SpanAggregatesResponseItem struct {
|
||||
Timestamp int64 `json:"timestamp,omitempty" `
|
||||
Value float32 `json:"value,omitempty"`
|
||||
GroupBy map[string]float32 `json:"groupBy,omitempty"`
|
||||
}
|
||||
type SpanAggregatesDBResponseItem struct {
|
||||
Timestamp int64 `json:"timestamp,omitempty" db:"timestamp" `
|
||||
Time string `json:"time,omitempty" db:"time"`
|
||||
Value float32 `json:"value,omitempty" db:"value"`
|
||||
GroupBy sql.NullString `json:"groupBy,omitempty" db:"groupBy"`
|
||||
}
|
||||
|
||||
type SetTTLResponseItem struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
@ -272,6 +307,71 @@ type GetTTLResponseItem struct {
|
||||
TracesTime int `json:"traces_ttl_duration_hrs"`
|
||||
}
|
||||
|
||||
type DBResponseMinMaxDuration struct {
|
||||
MinDuration int `db:"min(durationNano)"`
|
||||
MaxDuration int `db:"max(durationNano)"`
|
||||
}
|
||||
|
||||
type DBResponseServiceName struct {
|
||||
ServiceName string `db:"serviceName"`
|
||||
Count int `db:"count"`
|
||||
}
|
||||
|
||||
type DBResponseHttpCode struct {
|
||||
HttpCode string `db:"httpCode"`
|
||||
Count int `db:"count"`
|
||||
}
|
||||
|
||||
type DBResponseHttpRoute struct {
|
||||
HttpRoute string `db:"httpRoute"`
|
||||
Count int `db:"count"`
|
||||
}
|
||||
|
||||
type DBResponseHttpUrl struct {
|
||||
HttpUrl string `db:"httpUrl"`
|
||||
Count int `db:"count"`
|
||||
}
|
||||
|
||||
type DBResponseHttpMethod struct {
|
||||
HttpMethod string `db:"httpMethod"`
|
||||
Count int `db:"count"`
|
||||
}
|
||||
|
||||
type DBResponseHttpHost struct {
|
||||
HttpHost string `db:"httpHost"`
|
||||
Count int `db:"count"`
|
||||
}
|
||||
|
||||
type DBResponseOperation struct {
|
||||
Operation string `db:"name"`
|
||||
Count int `db:"count"`
|
||||
}
|
||||
|
||||
type DBResponseComponent struct {
|
||||
Component sql.NullString `db:"component"`
|
||||
Count int `db:"count"`
|
||||
}
|
||||
|
||||
type DBResponseErrors struct {
|
||||
NumErrors int `db:"numErrors"`
|
||||
}
|
||||
|
||||
type DBResponseTotal struct {
|
||||
NumTotal int `db:"numTotal"`
|
||||
}
|
||||
|
||||
type SpanFiltersResponse struct {
|
||||
ServiceName map[string]int `json:"serviceName"`
|
||||
Status map[string]int `json:"status"`
|
||||
Duration map[string]int `json:"duration"`
|
||||
Operation map[string]int `json:"operation"`
|
||||
HttpCode map[string]int `json:"httpCode"`
|
||||
HttpUrl map[string]int `json:"httpUrl"`
|
||||
HttpMethod map[string]int `json:"httpMethod"`
|
||||
HttpRoute map[string]int `json:"httpRoute"`
|
||||
HttpHost map[string]int `json:"httpHost"`
|
||||
Component map[string]int `json:"component"`
|
||||
}
|
||||
type Error struct {
|
||||
ExceptionType string `json:"exceptionType" db:"exceptionType"`
|
||||
ExceptionMsg string `json:"exceptionMessage" db:"exceptionMessage"`
|
||||
|
Loading…
x
Reference in New Issue
Block a user