From 8ada9058656a4df295376603da0ab5e58f943b50 Mon Sep 17 00:00:00 2001 From: sunface Date: Sat, 4 Nov 2023 21:39:10 +0800 Subject: [PATCH] feat: search traces by column, attributes and resources #290 --- .../internal/plugins/builtin/datav/api/api.go | 40 ++++++++++--------- .../plugins/builtin/datav/api/service.go | 27 +++++++++++++ .../plugins/builtin/datav/api/traces.go | 23 +++++++++-- .../plugins/built-in/panel/trace/Trace.tsx | 8 ---- 4 files changed, 67 insertions(+), 31 deletions(-) diff --git a/query/internal/plugins/builtin/datav/api/api.go b/query/internal/plugins/builtin/datav/api/api.go index 3b67dee67..89dd38d8c 100644 --- a/query/internal/plugins/builtin/datav/api/api.go +++ b/query/internal/plugins/builtin/datav/api/api.go @@ -7,26 +7,28 @@ import ( ) const ( - TestDatasourceAPI = "testDatasource" - GetServiceInfoListAPI = "getServiceInfoList" - GetNamespacesAPI = "getNamespaces" - GetServiceNamesAPI = "getServiceNames" - GetServiceOperationsAPI = "getServiceOperations" - GetDependencyGraphAPI = "getDependencyGraph" - GetLogsAPI = "getLogs" - GetTracesAPI = "getTraces" - GetTraceAPI = "getTrace" - GetTraceTagKeysAPI = "getTraceTagKeys" + TestDatasourceAPI = "testDatasource" + GetServiceInfoListAPI = "getServiceInfoList" + GetNamespacesAPI = "getNamespaces" + GetServiceNamesAPI = "getServiceNames" + GetServiceOperationsAPI = "getServiceOperations" + GetServiceRootOperationsAPI = "getServiceRootOperations" + GetDependencyGraphAPI = "getDependencyGraph" + GetLogsAPI = "getLogs" + GetTracesAPI = "getTraces" + GetTraceAPI = "getTrace" + GetTraceTagKeysAPI = "getTraceTagKeys" ) var APIRoutes = map[string]func(c *gin.Context, ds *models.Datasource, conn ch.Conn, params map[string]interface{}) models.PluginResult{ - GetServiceInfoListAPI: GetServiceInfoList, - GetNamespacesAPI: GetNamespaces, - GetServiceNamesAPI: GetServiceNames, - GetServiceOperationsAPI: GetServiceOperations, - GetLogsAPI: GetLogs, - GetDependencyGraphAPI: GetDependencyGraph, - GetTracesAPI: GetTraces, - GetTraceAPI: GetTrace, - GetTraceTagKeysAPI: GetTraceTagKeys, + GetServiceInfoListAPI: GetServiceInfoList, + GetNamespacesAPI: GetNamespaces, + GetServiceNamesAPI: GetServiceNames, + GetServiceOperationsAPI: GetServiceOperations, + GetServiceRootOperationsAPI: GetServiceRootOperations, + GetLogsAPI: GetLogs, + GetDependencyGraphAPI: GetDependencyGraph, + GetTracesAPI: GetTraces, + GetTraceAPI: GetTrace, + GetTraceTagKeysAPI: GetTraceTagKeys, } diff --git a/query/internal/plugins/builtin/datav/api/service.go b/query/internal/plugins/builtin/datav/api/service.go index ac3f20811..2dcea3873 100644 --- a/query/internal/plugins/builtin/datav/api/service.go +++ b/query/internal/plugins/builtin/datav/api/service.go @@ -70,6 +70,33 @@ func GetServiceOperations(c *gin.Context, ds *models.Datasource, conn ch.Conn, p return models.GenPluginResult(models.PluginStatusSuccess, "", res) } +func GetServiceRootOperations(c *gin.Context, ds *models.Datasource, conn ch.Conn, params map[string]interface{}) models.PluginResult { + tenant := models.DefaultTenant + domainQuery := datavutils.BuildBasicDomainQuery(tenant, params) + + service := datavutils.GetValueListFromParams(params, "service") + if service != nil { + domainQuery += fmt.Sprintf(" AND serviceName in ('%s')", strings.Join(service, "','")) + } + + query := fmt.Sprintf("SELECT DISTINCT name FROM %s.%s WHERE %s", config.Data.Observability.DefaultTraceDB, datavmodels.DefaultTopLevelOperationsTable, domainQuery) + rows, err := conn.Query(c.Request.Context(), query) + if err != nil { + logger.Warn("Error Query service operations", "query", query, "error", err) + return models.GenPluginResult(models.PluginStatusError, err.Error(), nil) + } + defer rows.Close() + + logger.Info("Query service operations", "query", query) + + res, err := pluginUtils.ConvertDbRowsToPluginData(rows) + if err != nil { + return models.GenPluginResult(models.PluginStatusError, err.Error(), nil) + } + + return models.GenPluginResult(models.PluginStatusSuccess, "", res) +} + type ServiceInfo struct { ServiceName string P99 float64 diff --git a/query/internal/plugins/builtin/datav/api/traces.go b/query/internal/plugins/builtin/datav/api/traces.go index f0a90ae34..b6069345d 100644 --- a/query/internal/plugins/builtin/datav/api/traces.go +++ b/query/internal/plugins/builtin/datav/api/traces.go @@ -49,7 +49,6 @@ func GetTraces(c *gin.Context, ds *models.Datasource, conn ch.Conn, params map[s domainQuery += fmt.Sprintf(" AND serviceName='%s'", service) var operationNameQuery string - var operationNameQuery1 string if operation == "" || operation == models.VarialbeAllOption { // if min > 0 || max > 0 || rawTags != "" { query := fmt.Sprintf("select name from %s.%s where %s", config.Data.Observability.DefaultTraceDB, datavmodels.DefaultTopLevelOperationsTable, domainQuery) @@ -58,8 +57,8 @@ func GetTraces(c *gin.Context, ds *models.Datasource, conn ch.Conn, params map[s } else { operationNameQuery = fmt.Sprintf(" AND name='%s'", operation) - operationNameQuery1 = operationNameQuery } + domainQuery += operationNameQuery var durationQuery string if min != 0 { @@ -93,6 +92,22 @@ func GetTraces(c *gin.Context, ds *models.Datasource, conn ch.Conn, params map[s } else { domainQuery += fmt.Sprintf(" AND resourcesMap['%s'] = '%s'", realKey, v) } + } else { + if v == models.VarialbeAllOption { + domainQuery += fmt.Sprintf(" AND %s != ''", k) + } else { + switch v.(type) { + case string: + domainQuery += fmt.Sprintf(" AND %s = '%s'", k, v) + case float64: + domainQuery += fmt.Sprintf(" AND %s = %f", k, v) + case bool: + domainQuery += fmt.Sprintf(" AND %s = %t", k, v) + default: + domainQuery += fmt.Sprintf(" AND %s = '%s'", k, v) + } + + } } } @@ -105,7 +120,7 @@ func GetTraces(c *gin.Context, ds *models.Datasource, conn ch.Conn, params map[s if traceIds != "" { query = fmt.Sprintf("SELECT startTime as ts,serviceName,name,traceId, duration as maxDuration FROM %s.%s WHERE traceId in ('%s') AND parentId=''", config.Data.Observability.DefaultTraceDB, datavmodels.DefaultTraceIndexTable, strings.Join(strings.Split(traceIds, ","), "','")) } else if service != "" { - query0 := fmt.Sprintf("SELECT DISTINCT traceId FROM %s.%s WHERE startTime >= %d AND startTime <= %d AND %s ORDER BY startTime DESC limit %d", config.Data.Observability.DefaultTraceDB, datavmodels.DefaultTraceIndexTable, start*1e9, end*1e9, domainQuery+operationNameQuery, limit) + query0 := fmt.Sprintf("SELECT DISTINCT traceId FROM %s.%s WHERE startTime >= %d AND startTime <= %d AND %s ORDER BY startTime DESC limit %d", config.Data.Observability.DefaultTraceDB, datavmodels.DefaultTraceIndexTable, start*1e9, end*1e9, domainQuery, limit) query = fmt.Sprintf("SELECT min(startTime) as ts,serviceName,name,traceId,max(duration) as maxDuration FROM %s.%s WHERE traceId in (%s) AND serviceName='%s' %s %s GROUP BY serviceName,name,traceId", config.Data.Observability.DefaultTraceDB, datavmodels.DefaultTraceIndexTable, query0, service, operationNameQuery, durationQuery) } else { query = fmt.Sprintf("SELECT startTime as ts,serviceName,name,traceId, duration as maxDuration FROM %s.%s WHERE tartTime >= %d AND startTime <= %d AND %s AND parentId='' ORDER BY ts DESC limit %d", config.Data.Observability.DefaultTraceDB, datavmodels.DefaultTraceIndexTable, start*1e9, end*1e9, domainQuery, limit) @@ -272,7 +287,7 @@ func GetTraces(c *gin.Context, ds *models.Datasource, conn ch.Conn, params map[s aggregateQuery = "round(quantile(0.99)(duration) / 1e6,2) as p99" } - metricsQuery := fmt.Sprintf("SELECT toStartOfInterval(fromUnixTimestamp64Nano(startTime), INTERVAL %d SECOND) AS ts_bucket, %s %s from %s.%s where (startTime >= %d AND startTime <= %d AND %s) group by %s order by ts_bucket", step, groupby, aggregateQuery, config.Data.Observability.DefaultTraceDB, datavmodels.DefaultTraceIndexTable, start*1e9, end*1e9, domainQuery+operationNameQuery1, groupBy) + metricsQuery := fmt.Sprintf("SELECT toStartOfInterval(fromUnixTimestamp64Nano(startTime), INTERVAL %d SECOND) AS ts_bucket, %s %s from %s.%s where (startTime >= %d AND startTime <= %d AND %s) group by %s order by ts_bucket", step, groupby, aggregateQuery, config.Data.Observability.DefaultTraceDB, datavmodels.DefaultTraceIndexTable, start*1e9, end*1e9, domainQuery, groupBy) rows, err := conn.Query(c.Request.Context(), metricsQuery) if err != nil { diff --git a/ui/src/views/dashboard/plugins/built-in/panel/trace/Trace.tsx b/ui/src/views/dashboard/plugins/built-in/panel/trace/Trace.tsx index fc160aa9c..95cd5aa1c 100644 --- a/ui/src/views/dashboard/plugins/built-in/panel/trace/Trace.tsx +++ b/ui/src/views/dashboard/plugins/built-in/panel/trace/Trace.tsx @@ -150,13 +150,5 @@ export function convTagsLogfmt(tags) { const data = logfmtParser.parse(tags); - Object.keys(data).forEach(key => { - const value = data[key]; - // make sure all values are strings - // https://github.com/jaegertracing/jaeger/issues/550#issuecomment-352850811 - if (typeof value !== 'string') { - data[key] = String(value); - } - }); return JSON.stringify(data); } \ No newline at end of file