mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-14 19:45: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
|
- 8123:8123
|
||||||
volumes:
|
volumes:
|
||||||
- ./clickhouse-config.xml:/etc/clickhouse-server/config.xml
|
- ./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/
|
- ./data/clickhouse/:/var/lib/clickhouse/
|
||||||
|
|
||||||
healthcheck:
|
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")}
|
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) {
|
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")}
|
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/serviceMapDependencies", aH.serviceMapDependencies).Methods(http.MethodGet)
|
||||||
router.HandleFunc("/api/v1/settings/ttl", aH.setTTL).Methods(http.MethodPost)
|
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/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/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)
|
||||||
@ -965,6 +969,70 @@ func (aH *APIHandler) searchSpans(w http.ResponseWriter, r *http.Request) {
|
|||||||
aH.writeJSON(w, r, result)
|
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) {
|
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) {
|
||||||
|
@ -37,6 +37,11 @@ type Reader interface {
|
|||||||
GetServicesList(ctx context.Context) (*[]string, error)
|
GetServicesList(ctx context.Context) (*[]string, error)
|
||||||
GetServiceMapDependencies(ctx context.Context, query *model.GetServicesParams) (*[]model.ServiceMapDependencyResponseItem, error)
|
GetServiceMapDependencies(ctx context.Context, query *model.GetServicesParams) (*[]model.ServiceMapDependencyResponseItem, error)
|
||||||
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)
|
||||||
|
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)
|
GetErrors(ctx context.Context, params *model.GetErrorsParams) (*[]model.Error, *model.ApiError)
|
||||||
GetErrorForId(ctx context.Context, params *model.GetErrorParams) (*model.ErrorWithSpan, *model.ApiError)
|
GetErrorForId(ctx context.Context, params *model.GetErrorParams) (*model.ErrorWithSpan, *model.ApiError)
|
||||||
GetErrorForType(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 allowedDimesions = []string{"calls", "duration"}
|
||||||
|
|
||||||
|
var allowedFunctions = []string{"count", "ratePerSec", "sum", "avg", "min", "max", "p50", "p90", "p95", "p99"}
|
||||||
|
|
||||||
var allowedAggregations = map[string][]string{
|
var allowedAggregations = map[string][]string{
|
||||||
"calls": {"count", "rate_per_sec"},
|
"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) {
|
func parseUser(r *http.Request) (*model.User, error) {
|
||||||
@ -480,6 +482,284 @@ func parseSpanSearchRequest(r *http.Request) (*model.SpanSearchParams, error) {
|
|||||||
return params, nil
|
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) {
|
func parseErrorRequest(r *http.Request) (*model.GetErrorParams, error) {
|
||||||
|
|
||||||
params := &model.GetErrorParams{}
|
params := &model.GetErrorParams{}
|
||||||
@ -502,6 +782,60 @@ func parseErrorRequest(r *http.Request) (*model.GetErrorParams, error) {
|
|||||||
return params, nil
|
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) {
|
func parseErrorsRequest(r *http.Request) (*model.GetErrorsParams, error) {
|
||||||
|
|
||||||
startTime, err := parseTime("start", r)
|
startTime, err := parseTime("start", r)
|
||||||
@ -521,6 +855,19 @@ func parseErrorsRequest(r *http.Request) (*model.GetErrorsParams, error) {
|
|||||||
return params, nil
|
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) {
|
func parseTags(param string, r *http.Request) (*[]model.TagQuery, error) {
|
||||||
|
|
||||||
tags := new([]model.TagQuery)
|
tags := new([]model.TagQuery)
|
||||||
@ -539,6 +886,24 @@ func parseTags(param string, r *http.Request) (*[]model.TagQuery, error) {
|
|||||||
return tags, nil
|
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) {
|
func parseApplicationPercentileRequest(r *http.Request) (*model.ApplicationPercentileParams, error) {
|
||||||
|
|
||||||
startTime, err := parseTime("start", r)
|
startTime, err := parseTime("start", r)
|
||||||
|
@ -78,6 +78,11 @@ type TagQuery struct {
|
|||||||
Operator string
|
Operator string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TagQueryV2 struct {
|
||||||
|
Key string
|
||||||
|
Values []string
|
||||||
|
Operator string
|
||||||
|
}
|
||||||
type SpanSearchAggregatesParams struct {
|
type SpanSearchAggregatesParams struct {
|
||||||
ServiceName string
|
ServiceName string
|
||||||
OperationName string
|
OperationName string
|
||||||
@ -111,6 +116,82 @@ type SpanSearchParams struct {
|
|||||||
Tags []TagQuery
|
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 TTLParams struct {
|
||||||
Type string
|
Type string
|
||||||
Duration string
|
Duration string
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -128,6 +129,22 @@ type SearchSpansResult struct {
|
|||||||
Events [][]interface{} `json:"events"`
|
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 {
|
type TraceResult struct {
|
||||||
Data []interface{} `json:"data" db:"data"`
|
Data []interface{} `json:"data" db:"data"`
|
||||||
Total int `json:"total" db:"total"`
|
Total int `json:"total" db:"total"`
|
||||||
@ -247,6 +264,9 @@ type TagItem struct {
|
|||||||
TagCount int `json:"tagCount" db:"tagCount"`
|
TagCount int `json:"tagCount" db:"tagCount"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TagFilters struct {
|
||||||
|
TagKeys string `json:"tagKeys" db:"tagKeys"`
|
||||||
|
}
|
||||||
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"`
|
||||||
@ -259,6 +279,21 @@ type SpanSearchAggregatesResponseItem struct {
|
|||||||
Value float32 `json:"value,omitempty" db:"value"`
|
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 {
|
type SetTTLResponseItem struct {
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
}
|
}
|
||||||
@ -272,6 +307,71 @@ type GetTTLResponseItem struct {
|
|||||||
TracesTime int `json:"traces_ttl_duration_hrs"`
|
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 {
|
type Error struct {
|
||||||
ExceptionType string `json:"exceptionType" db:"exceptionType"`
|
ExceptionType string `json:"exceptionType" db:"exceptionType"`
|
||||||
ExceptionMsg string `json:"exceptionMessage" db:"exceptionMessage"`
|
ExceptionMsg string `json:"exceptionMessage" db:"exceptionMessage"`
|
||||||
|
Loading…
x
Reference in New Issue
Block a user