From 548e5f0c222e184b3f2264d693a2ec4bf61242a5 Mon Sep 17 00:00:00 2001 From: yusufcemalcelebi Date: Thu, 4 Jun 2026 14:34:06 +0300 Subject: [PATCH] fix: return matched spans in Tempo /api/search instead of root span spanSets[].spans[] now contains the spans that satisfied the TraceQL filter (real spanID, name and query-referenced attributes), so Grafana deep-links to the matched span instead of the trace root. matched reports the true count regardless of root-span presence, and serviceStats is included. Matched spans are detected within the existing all-spans scan via a 'format if () "1" as _vt_matched' pipe, so no extra storage query is needed. Signed-off-by: yusufcemalcelebi --- app/vtselect/traces/tempo/query.go | 25 +- app/vtselect/traces/tempo/tempo.go | 201 +++- app/vtselect/traces/tempo/tempo.qtpl | 68 +- app/vtselect/traces/tempo/tempo.qtpl.go | 1156 ++++++++++++-------- app/vtselect/traces/tempo/tempo_test.go | 87 ++ docs/victoriatraces/changelog/CHANGELOG.md | 2 + lib/traceql/filter.go | 6 + lib/traceql/filter_and.go | 8 + lib/traceql/filter_general.go | 28 + lib/traceql/filter_noop.go | 4 + lib/traceql/filter_or.go | 8 + lib/traceql/filter_phase.go | 7 + lib/traceql/filter_trace.go | 4 + lib/traceql/parser.go | 23 + 14 files changed, 1119 insertions(+), 508 deletions(-) diff --git a/app/vtselect/traces/tempo/query.go b/app/vtselect/traces/tempo/query.go index 9edd7665d..6eeb7a40d 100644 --- a/app/vtselect/traces/tempo/query.go +++ b/app/vtselect/traces/tempo/query.go @@ -32,6 +32,15 @@ import ( // To avoid polluting the stable Jaeger API implementation, we have temporarily placed all related queries under the tempo directory. // But they could be ported back to `app/vtselect/traces/query` and unified with queries already there in the future. +// matchedMarkerField is an internal span field set by query 2's 'format if' pipe +// to matchedMarker on spans that satisfy the TraceQL filter. It is read back in +// summarySearchTracesResult to populate spanSets[].spans[], and must not collide +// with any real OTLP span field name. +const ( + matchedMarkerField = "_vt_matched" + matchedMarker = "1" +) + // GetTraceList returns multiple traceIDs and spans of them in []*Row format. // It searches for traceIDs first, and then search for the spans of these traceIDs. // To not miss any spans on the edge, it extends both the start time and end time @@ -41,6 +50,12 @@ import ( // 1. input time range: [00:00, 09:00] // 2. found 20 trace id, and adjust time range to: [08:00, 09:00] // 3. find spans on time range: [08:00-traceMaxDurationWindow, 09:00+traceMaxDurationWindow] +// +// Each returned row carries the matchedMarkerField field when its span satisfied +// the TraceQL filter. This is computed within the same span scan via a 'format if' +// pipe, so the caller can project the matched spans into spanSets[].spans[] +// without an extra query. Non-matching spans are still returned, since trace-level +// metadata (duration, per-service stats) is derived from all spans of the trace. func GetTraceList(ctx context.Context, cp *tracecommon.CommonParams, filterQuery *traceql.Query, start, end time.Time, limit int64) ([]string, []*tracecommon.Row, error) { currentTime := time.Now() @@ -53,8 +68,13 @@ func GetTraceList(ctx context.Context, cp *tracecommon.CommonParams, filterQuery return nil, nil, nil } - // query 2: trace_id:in(traceID, traceID, ...) - qStr := fmt.Sprintf(otelpb.TraceIDField+":in(%s)", strings.Join(traceIDs, ",")) + // query 2: trace_id:in(traceID, traceID, ...) | format if () "1" as + // The 'format if' pipe marks every span that satisfies the TraceQL filter, so the + // matched spans can be projected into the response without a second query. Non-matching + // spans are still returned (carrying no marker), since trace-level metadata is derived + // from all spans of the trace. + qStr := fmt.Sprintf("%s:in(%s) | format if (%s) %q as %s", + otelpb.TraceIDField, strings.Join(traceIDs, ","), filterQuery.Filter(), matchedMarker, matchedMarkerField) q, err := logstorage.ParseQueryAtTimestamp(qStr, currentTime.UnixNano()) if err != nil { return nil, nil, fmt.Errorf("cannot parse query [%s]: %s", qStr, err) @@ -117,6 +137,7 @@ func GetTraceList(ctx context.Context, cp *tracecommon.CommonParams, filterQuery if missingTimeColumn.Load() { return nil, nil, fmt.Errorf("missing _time column in the result for the query [%s]", q) } + return traceIDs, rows, nil } diff --git a/app/vtselect/traces/tempo/tempo.go b/app/vtselect/traces/tempo/tempo.go index 3de51b838..7adeb5aee 100644 --- a/app/vtselect/traces/tempo/tempo.go +++ b/app/vtselect/traces/tempo/tempo.go @@ -193,7 +193,7 @@ func processSearchRequest(ctx context.Context, w http.ResponseWriter, r *http.Re return } - result, err := searchTraces(ctx, cp, params.q, params.start, params.end, params.limit) + result, err := searchTraces(ctx, cp, params.q, params.start, params.end, params.limit, params.spss) if err != nil { httpserver.Errorf(w, r, "cannot get traces list: %s", err) return @@ -496,7 +496,7 @@ func singleFieldQueryHelper(ctx context.Context, q *logstorage.Query, cp *tracec return resultList, nil } -func searchTraces(ctx context.Context, cp *tracecommon.CommonParams, traceQLStr string, start, end time.Time, limit int64) ([]traceSummary, error) { +func searchTraces(ctx context.Context, cp *tracecommon.CommonParams, traceQLStr string, start, end time.Time, limit, spss int64) ([]traceSummary, error) { // transform traceQL into LogsQL as filter. It should contain filter only without any pipe. filterQuery, err := traceql.ParseQuery(traceQLStr) if err != nil { @@ -516,7 +516,7 @@ func searchTraces(ctx context.Context, cp *tracecommon.CommonParams, traceQLStr return nil, err } - result, err := summarySearchTracesResult(ctx, rows, limit) + result, err := summarySearchTracesResult(rows, filterQuery.ReferencedFields(), spss) if err != nil { return nil, err } @@ -524,27 +524,67 @@ func searchTraces(ctx context.Context, cp *tracecommon.CommonParams, traceQLStr return result, nil } +// spanAttr is a single key/value attribute projected onto a matched span in the +// search response. +type spanAttr struct { + key string + value string +} + +// matchedSpan is a span that satisfied the TraceQL filter within a trace. It +// carries the span's own intrinsics plus the attributes referenced by the query, +// which Grafana renders as the spans-table columns and uses to deep-link to the +// matched span. +type matchedSpan struct { + spanID string + name string + startTimeUnixNano int64 + endTimeUnixNano int64 + attributes []spanAttr +} + +// serviceStat holds per-service span and error counts for a trace. +type serviceStat struct { + spanCount int + errorCount int +} + type traceSummary struct { traceID string rootServiceName string rootTraceName string - rootSpanID string startTimeUnixNano int64 endTimeUnixNano int64 - // rootStartTimeUnixNano / rootEndTimeUnixNano are the root span's own bounds, - // used to populate spanSets[0].spans[0].startTimeUnixNano and durationNanos. - // Grafana's Tempo datasource reads durationNanos from the span, not the - // trace-level durationMs, so we must emit it on the synthesized root span. - rootStartTimeUnixNano int64 - rootEndTimeUnixNano int64 + + // matchedSpans are the spans that satisfied the filter, capped at spss. + // matchedCount is the total number of matching spans (independent of the cap), + // reported as spanSet.matched per the Tempo contract. + matchedSpans []matchedSpan + matchedCount int + + // serviceStats are per-service span/error counts across every span of the + // trace (not just the matched spans). + serviceStats map[string]serviceStat } -func summarySearchTracesResult(ctx context.Context, rows []*tracecommon.Row, limit int64) ([]traceSummary, error) { - traceMap := make(map[string]traceSummary) +func summarySearchTracesResult(rows []*tracecommon.Row, referencedFields []string, spss int64) ([]traceSummary, error) { + // Build the VT field name -> response attribute spec once for the referenced + // fields, so each matched span projects only the queried attributes. + attrSpecs := buildAttrSpecs(referencedFields) + nameReferenced := false + for _, f := range referencedFields { + if f == otelpb.NameField { + nameReferenced = true + break + } + } + + traceMap := make(map[string]*traceSummary) for _, row := range rows { - var traceID, serviceName, spanName, spanID, parentSpanID string + var traceID, serviceName, spanName, spanID, parentSpanID, statusCode string var startTimeUnixNano, endTimeUnixNano int64 + var matched bool var err error for _, field := range row.Fields { switch field.Name { @@ -558,6 +598,11 @@ func summarySearchTracesResult(ctx context.Context, rows []*tracecommon.Row, lim spanID = field.Value case otelpb.ParentSpanIDField: parentSpanID = field.Value + case otelpb.StatusCodeField: + statusCode = field.Value + case matchedMarkerField: + // set by query 2's 'format if' pipe on spans that satisfy the filter. + matched = field.Value == matchedMarker case otelpb.StartTimeUnixNanoField: startTimeUnixNano, err = strconv.ParseInt(field.Value, 10, 64) if err != nil { @@ -580,40 +625,141 @@ func summarySearchTracesResult(ctx context.Context, rows []*tracecommon.Row, lim // get the summary for this trace summary, ok := traceMap[traceID] if !ok { - summary = traceSummary{ + summary = &traceSummary{ + traceID: traceID, startTimeUnixNano: math.MaxInt64, rootServiceName: "", + serviceStats: make(map[string]serviceStat), } traceMap[traceID] = summary } - summary.traceID = traceID summary.startTimeUnixNano = min(summary.startTimeUnixNano, startTimeUnixNano) summary.endTimeUnixNano = max(summary.endTimeUnixNano, endTimeUnixNano) - // if it's the root span + + // per-service stats over every span of the trace. + stat := summary.serviceStats[serviceName] + stat.spanCount++ + if statusCode == statusCodeError { + stat.errorCount++ + } + summary.serviceStats[serviceName] = stat + + // trace-level metadata is taken from the root span (parent span id empty). if parentSpanID == "" { summary.rootServiceName = serviceName summary.rootTraceName = spanName - summary.rootSpanID = spanID - summary.rootStartTimeUnixNano = startTimeUnixNano - summary.rootEndTimeUnixNano = endTimeUnixNano } - // summary is not a pointer so it must be put back to the map. - traceMap[traceID] = summary + + // collect the span into spanSets if it satisfied the filter. + if matched { + summary.matchedCount++ + if int64(len(summary.matchedSpans)) < spss { + summary.matchedSpans = append(summary.matchedSpans, matchedSpan{ + spanID: spanID, + name: projectName(spanName, nameReferenced), + startTimeUnixNano: startTimeUnixNano, + endTimeUnixNano: endTimeUnixNano, + attributes: projectAttributes(row, attrSpecs), + }) + } + } } resultList := make([]traceSummary, 0, len(traceMap)) for _, summary := range traceMap { - resultList = append(resultList, summary) + resultList = append(resultList, *summary) } return resultList, nil } +// statusCodeError is the OTEL StatusCode numeric value for error, used to count +// errors in serviceStats. +const statusCodeError = "2" + +// attrSpec maps a stored VT field name to the response attribute key and an +// optional value transform (e.g. kind/status numeric -> name). +type attrSpec struct { + vtField string + key string + transform func(string) string +} + +// buildAttrSpecs resolves the query-referenced TraceQL field names into the +// stored VT field names to read from each matched span, plus the response key +// (with scope prefix stripped) and any value transform. Intrinsics that are not +// rendered as attributes (name, duration, nestedSetParent) are skipped. +func buildAttrSpecs(referencedFields []string) []attrSpec { + specs := make([]attrSpec, 0, len(referencedFields)) + for _, f := range referencedFields { + switch f { + case otelpb.NameField, "duration", "traceDuration", "nestedSetParent": + // name is emitted as the span's top-level field; the others are not + // span attributes. + continue + case "kind": + specs = append(specs, attrSpec{vtField: otelpb.KindField, key: "kind", transform: traceql.KindCodeToName}) + case "status": + specs = append(specs, attrSpec{vtField: otelpb.StatusCodeField, key: "status", transform: traceql.StatusCodeToName}) + default: + specs = append(specs, attrSpec{vtField: traceql.TraceQLFieldToVTField(f), key: attrDisplayKey(f)}) + } + } + return specs +} + +// attrDisplayKey strips the TraceQL scope prefix from a field name to produce the +// response attribute key, mirroring Tempo (e.g. "resource.service.name" -> +// "service.name", "span.server.address" -> "server.address", ".server.address" +// -> "server.address"). +func attrDisplayKey(f string) string { + for _, prefix := range []string{"resource.", "span.", "event.", "link.", "instrumentation."} { + if strings.HasPrefix(f, prefix) { + return f[len(prefix):] + } + } + return strings.TrimPrefix(f, ".") +} + +// projectName returns the span name only when the query referenced it, matching +// Tempo's behavior of including `name` solely when selected/filtered. +func projectName(spanName string, nameReferenced bool) string { + if nameReferenced { + return spanName + } + return "" +} + +// projectAttributes reads the referenced attributes from a span row, applying +// any value transform. Attributes absent from the span are skipped. +func projectAttributes(row *tracecommon.Row, specs []attrSpec) []spanAttr { + if len(specs) == 0 { + return nil + } + attrs := make([]spanAttr, 0, len(specs)) + for _, spec := range specs { + for _, field := range row.Fields { + if field.Name == spec.vtField { + value := field.Value + if spec.transform != nil { + value = spec.transform(value) + } + attrs = append(attrs, spanAttr{key: spec.key, value: value}) + break + } + } + } + return attrs +} + type commonAPIParam struct { q string start time.Time end time.Time limit int64 + // spss is the max number of spans per spanset returned in the search + // response (Tempo's spansPerSpanSet). matched still reports the full count. + spss int64 } // parseTempoAPIParam parse Tempo request. @@ -624,6 +770,7 @@ func parseTempoAPIParam(_ context.Context, r *http.Request, allowDefaultTime boo start: time.Time{}, end: time.Time{}, limit: 100, + spss: 3, // Tempo's default spansPerSpanSet. } if allowDefaultTime { @@ -663,6 +810,16 @@ func parseTempoAPIParam(_ context.Context, r *http.Request, allowDefaultTime boo p.limit = max(0, min(1000, l)) } + spss := q.Get("spss") + if spss != "" { + s, err := strconv.ParseInt(spss, 10, 64) + if err != nil { + return nil, fmt.Errorf("cannot parse spss: %s", spss) + } + // Clamp to [1, 1000] to keep responses bounded. + p.spss = max(1, min(1000, s)) + } + p.q = q.Get("q") return p, nil diff --git a/app/vtselect/traces/tempo/tempo.qtpl b/app/vtselect/traces/tempo/tempo.qtpl index 1eafc1cb2..1c549c6b8 100644 --- a/app/vtselect/traces/tempo/tempo.qtpl +++ b/app/vtselect/traces/tempo/tempo.qtpl @@ -127,29 +127,71 @@ "startTimeUnixNano":{%dl= summary.startTimeUnixNano %}, "durationMs":{% if summary.endTimeUnixNano > 0 && summary.startTimeUnixNano > 0 %}{%dl= (summary.endTimeUnixNano - summary.startTimeUnixNano) / 1e6 %}{% else %}0{% endif %}, "spanSet":{%= spanSetJSON(summary) %}, - "spanSets":[{%= spanSetJSON(summary) %}] + "spanSets":[{%= spanSetJSON(summary) %}], + "serviceStats":{%= serviceStatsJSON(summary.serviceStats) %} } {% endfunc %} {% func spanSetJSON(summary traceSummary) %} { "spans":[ - {% if summary.rootSpanID != "" %} - { - "spanID":{%q= summary.rootSpanID %}, - "startTimeUnixNano":{%q= strconv.FormatInt(summary.rootStartTimeUnixNano, 10) %}, - "durationNanos":{%q= strconv.FormatInt(summary.rootEndTimeUnixNano - summary.rootStartTimeUnixNano, 10) %}, - "attributes":[ - {"key":"service.name","value":{"stringValue":{%q= summary.rootServiceName %}}}, - {"key":"nestedSetParent","value":{"intValue":"-1"}} - ] - } + {% if len(summary.matchedSpans) > 0 %} + {%= matchedSpanJSON(summary.matchedSpans[0]) %} + {% for _, sp := range summary.matchedSpans[1:] %} + ,{%= matchedSpanJSON(sp) %} + {% endfor %} {% endif %} ], - "matched":{% if summary.rootSpanID != "" %}1{% else %}0{% endif %} + "matched":{%d= summary.matchedCount %} +} +{% endfunc %} + +{% func matchedSpanJSON(sp matchedSpan) %} +{ + "spanID":{%q= sp.spanID %}, + {% if sp.name != "" %}"name":{%q= sp.name %},{% endif %} + "startTimeUnixNano":{%q= strconv.FormatInt(sp.startTimeUnixNano, 10) %}, + "durationNanos":{%q= strconv.FormatInt(sp.endTimeUnixNano - sp.startTimeUnixNano, 10) %}, + "attributes":[ + {% if len(sp.attributes) > 0 %} + {%= attrJSON(sp.attributes[0]) %} + {% for _, a := range sp.attributes[1:] %} + ,{%= attrJSON(a) %} + {% endfor %} + {% endif %} + ] } {% endfunc %} +{% func attrJSON(a spanAttr) %} +{"key":{%q= a.key %},"value":{"stringValue":{%q= a.value %}}} +{% endfunc %} + +{% func serviceStatsJSON(stats map[string]serviceStat) %} +{ + {% code + names := make([]string, 0, len(stats)) + for name := range stats { + if name == "" { + continue + } + names = append(names, name) + } + sort.Slice(names, func(i, j int) bool { return names[i] < names[j] }) + %} + {% if len(names) > 0 %} + {%q= names[0] %}:{%= serviceStatJSON(stats[names[0]]) %} + {% for _, name := range names[1:] %} + ,{%q= name %}:{%= serviceStatJSON(stats[name]) %} + {% endfor %} + {% endif %} +} +{% endfunc %} + +{% func serviceStatJSON(stat serviceStat) %} +{"spanCount":{%d= stat.spanCount %}{% if stat.errorCount > 0 %},"errorCount":{%d= stat.errorCount %}{% endif %}} +{% endfunc %} + {% comment %} TraceByIDV1JSON renders the Tempo /api/traces/ (v1) JSON response: the bare Trace message, whose resource spans are nested under the "batches" key. @@ -349,4 +391,4 @@ the TraceByIDResponse wrapper, with resource spans under trace.resourceSpans. ] {% endfunc %} -{% endstripspace %} \ No newline at end of file +{% endstripspace %} diff --git a/app/vtselect/traces/tempo/tempo.qtpl.go b/app/vtselect/traces/tempo/tempo.qtpl.go index 1cabac2f3..f9cfa35ff 100644 --- a/app/vtselect/traces/tempo/tempo.qtpl.go +++ b/app/vtselect/traces/tempo/tempo.qtpl.go @@ -299,982 +299,1196 @@ func streamsummaryJson(qw422016 *qt422016.Writer, summary traceSummary) { //line app/vtselect/traces/tempo/tempo.qtpl:130 streamspanSetJSON(qw422016, summary) //line app/vtselect/traces/tempo/tempo.qtpl:130 - qw422016.N().S(`]}`) -//line app/vtselect/traces/tempo/tempo.qtpl:132 + qw422016.N().S(`],"serviceStats":`) +//line app/vtselect/traces/tempo/tempo.qtpl:131 + streamserviceStatsJSON(qw422016, summary.serviceStats) +//line app/vtselect/traces/tempo/tempo.qtpl:131 + qw422016.N().S(`}`) +//line app/vtselect/traces/tempo/tempo.qtpl:133 } -//line app/vtselect/traces/tempo/tempo.qtpl:132 +//line app/vtselect/traces/tempo/tempo.qtpl:133 func writesummaryJson(qq422016 qtio422016.Writer, summary traceSummary) { -//line app/vtselect/traces/tempo/tempo.qtpl:132 +//line app/vtselect/traces/tempo/tempo.qtpl:133 qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vtselect/traces/tempo/tempo.qtpl:132 +//line app/vtselect/traces/tempo/tempo.qtpl:133 streamsummaryJson(qw422016, summary) -//line app/vtselect/traces/tempo/tempo.qtpl:132 +//line app/vtselect/traces/tempo/tempo.qtpl:133 qt422016.ReleaseWriter(qw422016) -//line app/vtselect/traces/tempo/tempo.qtpl:132 +//line app/vtselect/traces/tempo/tempo.qtpl:133 } -//line app/vtselect/traces/tempo/tempo.qtpl:132 +//line app/vtselect/traces/tempo/tempo.qtpl:133 func summaryJson(summary traceSummary) string { -//line app/vtselect/traces/tempo/tempo.qtpl:132 +//line app/vtselect/traces/tempo/tempo.qtpl:133 qb422016 := qt422016.AcquireByteBuffer() -//line app/vtselect/traces/tempo/tempo.qtpl:132 +//line app/vtselect/traces/tempo/tempo.qtpl:133 writesummaryJson(qb422016, summary) -//line app/vtselect/traces/tempo/tempo.qtpl:132 +//line app/vtselect/traces/tempo/tempo.qtpl:133 qs422016 := string(qb422016.B) -//line app/vtselect/traces/tempo/tempo.qtpl:132 +//line app/vtselect/traces/tempo/tempo.qtpl:133 qt422016.ReleaseByteBuffer(qb422016) -//line app/vtselect/traces/tempo/tempo.qtpl:132 +//line app/vtselect/traces/tempo/tempo.qtpl:133 return qs422016 -//line app/vtselect/traces/tempo/tempo.qtpl:132 +//line app/vtselect/traces/tempo/tempo.qtpl:133 } -//line app/vtselect/traces/tempo/tempo.qtpl:134 +//line app/vtselect/traces/tempo/tempo.qtpl:135 func streamspanSetJSON(qw422016 *qt422016.Writer, summary traceSummary) { -//line app/vtselect/traces/tempo/tempo.qtpl:134 +//line app/vtselect/traces/tempo/tempo.qtpl:135 qw422016.N().S(`{"spans":[`) -//line app/vtselect/traces/tempo/tempo.qtpl:137 - if summary.rootSpanID != "" { -//line app/vtselect/traces/tempo/tempo.qtpl:137 - qw422016.N().S(`{"spanID":`) +//line app/vtselect/traces/tempo/tempo.qtpl:138 + if len(summary.matchedSpans) > 0 { //line app/vtselect/traces/tempo/tempo.qtpl:139 - qw422016.N().Q(summary.rootSpanID) -//line app/vtselect/traces/tempo/tempo.qtpl:139 - qw422016.N().S(`,"startTimeUnixNano":`) + streammatchedSpanJSON(qw422016, summary.matchedSpans[0]) //line app/vtselect/traces/tempo/tempo.qtpl:140 - qw422016.N().Q(strconv.FormatInt(summary.rootStartTimeUnixNano, 10)) + for _, sp := range summary.matchedSpans[1:] { //line app/vtselect/traces/tempo/tempo.qtpl:140 - qw422016.N().S(`,"durationNanos":`) -//line app/vtselect/traces/tempo/tempo.qtpl:141 - qw422016.N().Q(strconv.FormatInt(summary.rootEndTimeUnixNano-summary.rootStartTimeUnixNano, 10)) + qw422016.N().S(`,`) //line app/vtselect/traces/tempo/tempo.qtpl:141 - qw422016.N().S(`,"attributes":[{"key":"service.name","value":{"stringValue":`) -//line app/vtselect/traces/tempo/tempo.qtpl:143 - qw422016.N().Q(summary.rootServiceName) + streammatchedSpanJSON(qw422016, sp) +//line app/vtselect/traces/tempo/tempo.qtpl:142 + } //line app/vtselect/traces/tempo/tempo.qtpl:143 - qw422016.N().S(`}},{"key":"nestedSetParent","value":{"intValue":"-1"}}]}`) -//line app/vtselect/traces/tempo/tempo.qtpl:147 } -//line app/vtselect/traces/tempo/tempo.qtpl:147 +//line app/vtselect/traces/tempo/tempo.qtpl:143 qw422016.N().S(`],"matched":`) -//line app/vtselect/traces/tempo/tempo.qtpl:149 - if summary.rootSpanID != "" { -//line app/vtselect/traces/tempo/tempo.qtpl:149 - qw422016.N().S(`1`) -//line app/vtselect/traces/tempo/tempo.qtpl:149 - } else { -//line app/vtselect/traces/tempo/tempo.qtpl:149 - qw422016.N().S(`0`) -//line app/vtselect/traces/tempo/tempo.qtpl:149 - } -//line app/vtselect/traces/tempo/tempo.qtpl:149 +//line app/vtselect/traces/tempo/tempo.qtpl:145 + qw422016.N().D(summary.matchedCount) +//line app/vtselect/traces/tempo/tempo.qtpl:145 qw422016.N().S(`}`) -//line app/vtselect/traces/tempo/tempo.qtpl:151 +//line app/vtselect/traces/tempo/tempo.qtpl:147 } -//line app/vtselect/traces/tempo/tempo.qtpl:151 +//line app/vtselect/traces/tempo/tempo.qtpl:147 func writespanSetJSON(qq422016 qtio422016.Writer, summary traceSummary) { -//line app/vtselect/traces/tempo/tempo.qtpl:151 +//line app/vtselect/traces/tempo/tempo.qtpl:147 qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vtselect/traces/tempo/tempo.qtpl:151 +//line app/vtselect/traces/tempo/tempo.qtpl:147 streamspanSetJSON(qw422016, summary) -//line app/vtselect/traces/tempo/tempo.qtpl:151 +//line app/vtselect/traces/tempo/tempo.qtpl:147 qt422016.ReleaseWriter(qw422016) -//line app/vtselect/traces/tempo/tempo.qtpl:151 +//line app/vtselect/traces/tempo/tempo.qtpl:147 } -//line app/vtselect/traces/tempo/tempo.qtpl:151 +//line app/vtselect/traces/tempo/tempo.qtpl:147 func spanSetJSON(summary traceSummary) string { -//line app/vtselect/traces/tempo/tempo.qtpl:151 +//line app/vtselect/traces/tempo/tempo.qtpl:147 qb422016 := qt422016.AcquireByteBuffer() -//line app/vtselect/traces/tempo/tempo.qtpl:151 +//line app/vtselect/traces/tempo/tempo.qtpl:147 writespanSetJSON(qb422016, summary) -//line app/vtselect/traces/tempo/tempo.qtpl:151 +//line app/vtselect/traces/tempo/tempo.qtpl:147 qs422016 := string(qb422016.B) -//line app/vtselect/traces/tempo/tempo.qtpl:151 +//line app/vtselect/traces/tempo/tempo.qtpl:147 qt422016.ReleaseByteBuffer(qb422016) -//line app/vtselect/traces/tempo/tempo.qtpl:151 +//line app/vtselect/traces/tempo/tempo.qtpl:147 return qs422016 -//line app/vtselect/traces/tempo/tempo.qtpl:151 +//line app/vtselect/traces/tempo/tempo.qtpl:147 } +//line app/vtselect/traces/tempo/tempo.qtpl:149 +func streammatchedSpanJSON(qw422016 *qt422016.Writer, sp matchedSpan) { +//line app/vtselect/traces/tempo/tempo.qtpl:149 + qw422016.N().S(`{"spanID":`) +//line app/vtselect/traces/tempo/tempo.qtpl:151 + qw422016.N().Q(sp.spanID) +//line app/vtselect/traces/tempo/tempo.qtpl:151 + qw422016.N().S(`,`) +//line app/vtselect/traces/tempo/tempo.qtpl:152 + if sp.name != "" { +//line app/vtselect/traces/tempo/tempo.qtpl:152 + qw422016.N().S(`"name":`) +//line app/vtselect/traces/tempo/tempo.qtpl:152 + qw422016.N().Q(sp.name) +//line app/vtselect/traces/tempo/tempo.qtpl:152 + qw422016.N().S(`,`) +//line app/vtselect/traces/tempo/tempo.qtpl:152 + } +//line app/vtselect/traces/tempo/tempo.qtpl:152 + qw422016.N().S(`"startTimeUnixNano":`) +//line app/vtselect/traces/tempo/tempo.qtpl:153 + qw422016.N().Q(strconv.FormatInt(sp.startTimeUnixNano, 10)) +//line app/vtselect/traces/tempo/tempo.qtpl:153 + qw422016.N().S(`,"durationNanos":`) +//line app/vtselect/traces/tempo/tempo.qtpl:154 + qw422016.N().Q(strconv.FormatInt(sp.endTimeUnixNano-sp.startTimeUnixNano, 10)) +//line app/vtselect/traces/tempo/tempo.qtpl:154 + qw422016.N().S(`,"attributes":[`) +//line app/vtselect/traces/tempo/tempo.qtpl:156 + if len(sp.attributes) > 0 { //line app/vtselect/traces/tempo/tempo.qtpl:157 + streamattrJSON(qw422016, sp.attributes[0]) +//line app/vtselect/traces/tempo/tempo.qtpl:158 + for _, a := range sp.attributes[1:] { +//line app/vtselect/traces/tempo/tempo.qtpl:158 + qw422016.N().S(`,`) +//line app/vtselect/traces/tempo/tempo.qtpl:159 + streamattrJSON(qw422016, a) +//line app/vtselect/traces/tempo/tempo.qtpl:160 + } +//line app/vtselect/traces/tempo/tempo.qtpl:161 + } +//line app/vtselect/traces/tempo/tempo.qtpl:161 + qw422016.N().S(`]}`) +//line app/vtselect/traces/tempo/tempo.qtpl:164 +} + +//line app/vtselect/traces/tempo/tempo.qtpl:164 +func writematchedSpanJSON(qq422016 qtio422016.Writer, sp matchedSpan) { +//line app/vtselect/traces/tempo/tempo.qtpl:164 + qw422016 := qt422016.AcquireWriter(qq422016) +//line app/vtselect/traces/tempo/tempo.qtpl:164 + streammatchedSpanJSON(qw422016, sp) +//line app/vtselect/traces/tempo/tempo.qtpl:164 + qt422016.ReleaseWriter(qw422016) +//line app/vtselect/traces/tempo/tempo.qtpl:164 +} + +//line app/vtselect/traces/tempo/tempo.qtpl:164 +func matchedSpanJSON(sp matchedSpan) string { +//line app/vtselect/traces/tempo/tempo.qtpl:164 + qb422016 := qt422016.AcquireByteBuffer() +//line app/vtselect/traces/tempo/tempo.qtpl:164 + writematchedSpanJSON(qb422016, sp) +//line app/vtselect/traces/tempo/tempo.qtpl:164 + qs422016 := string(qb422016.B) +//line app/vtselect/traces/tempo/tempo.qtpl:164 + qt422016.ReleaseByteBuffer(qb422016) +//line app/vtselect/traces/tempo/tempo.qtpl:164 + return qs422016 +//line app/vtselect/traces/tempo/tempo.qtpl:164 +} + +//line app/vtselect/traces/tempo/tempo.qtpl:166 +func streamattrJSON(qw422016 *qt422016.Writer, a spanAttr) { +//line app/vtselect/traces/tempo/tempo.qtpl:166 + qw422016.N().S(`{"key":`) +//line app/vtselect/traces/tempo/tempo.qtpl:167 + qw422016.N().Q(a.key) +//line app/vtselect/traces/tempo/tempo.qtpl:167 + qw422016.N().S(`,"value":{"stringValue":`) +//line app/vtselect/traces/tempo/tempo.qtpl:167 + qw422016.N().Q(a.value) +//line app/vtselect/traces/tempo/tempo.qtpl:167 + qw422016.N().S(`}}`) +//line app/vtselect/traces/tempo/tempo.qtpl:168 +} + +//line app/vtselect/traces/tempo/tempo.qtpl:168 +func writeattrJSON(qq422016 qtio422016.Writer, a spanAttr) { +//line app/vtselect/traces/tempo/tempo.qtpl:168 + qw422016 := qt422016.AcquireWriter(qq422016) +//line app/vtselect/traces/tempo/tempo.qtpl:168 + streamattrJSON(qw422016, a) +//line app/vtselect/traces/tempo/tempo.qtpl:168 + qt422016.ReleaseWriter(qw422016) +//line app/vtselect/traces/tempo/tempo.qtpl:168 +} + +//line app/vtselect/traces/tempo/tempo.qtpl:168 +func attrJSON(a spanAttr) string { +//line app/vtselect/traces/tempo/tempo.qtpl:168 + qb422016 := qt422016.AcquireByteBuffer() +//line app/vtselect/traces/tempo/tempo.qtpl:168 + writeattrJSON(qb422016, a) +//line app/vtselect/traces/tempo/tempo.qtpl:168 + qs422016 := string(qb422016.B) +//line app/vtselect/traces/tempo/tempo.qtpl:168 + qt422016.ReleaseByteBuffer(qb422016) +//line app/vtselect/traces/tempo/tempo.qtpl:168 + return qs422016 +//line app/vtselect/traces/tempo/tempo.qtpl:168 +} + +//line app/vtselect/traces/tempo/tempo.qtpl:170 +func streamserviceStatsJSON(qw422016 *qt422016.Writer, stats map[string]serviceStat) { +//line app/vtselect/traces/tempo/tempo.qtpl:170 + qw422016.N().S(`{`) +//line app/vtselect/traces/tempo/tempo.qtpl:173 + names := make([]string, 0, len(stats)) + for name := range stats { + if name == "" { + continue + } + names = append(names, name) + } + sort.Slice(names, func(i, j int) bool { return names[i] < names[j] }) + +//line app/vtselect/traces/tempo/tempo.qtpl:182 + if len(names) > 0 { +//line app/vtselect/traces/tempo/tempo.qtpl:183 + qw422016.N().Q(names[0]) +//line app/vtselect/traces/tempo/tempo.qtpl:183 + qw422016.N().S(`:`) +//line app/vtselect/traces/tempo/tempo.qtpl:183 + streamserviceStatJSON(qw422016, stats[names[0]]) +//line app/vtselect/traces/tempo/tempo.qtpl:184 + for _, name := range names[1:] { +//line app/vtselect/traces/tempo/tempo.qtpl:184 + qw422016.N().S(`,`) +//line app/vtselect/traces/tempo/tempo.qtpl:185 + qw422016.N().Q(name) +//line app/vtselect/traces/tempo/tempo.qtpl:185 + qw422016.N().S(`:`) +//line app/vtselect/traces/tempo/tempo.qtpl:185 + streamserviceStatJSON(qw422016, stats[name]) +//line app/vtselect/traces/tempo/tempo.qtpl:186 + } +//line app/vtselect/traces/tempo/tempo.qtpl:187 + } +//line app/vtselect/traces/tempo/tempo.qtpl:187 + qw422016.N().S(`}`) +//line app/vtselect/traces/tempo/tempo.qtpl:189 +} + +//line app/vtselect/traces/tempo/tempo.qtpl:189 +func writeserviceStatsJSON(qq422016 qtio422016.Writer, stats map[string]serviceStat) { +//line app/vtselect/traces/tempo/tempo.qtpl:189 + qw422016 := qt422016.AcquireWriter(qq422016) +//line app/vtselect/traces/tempo/tempo.qtpl:189 + streamserviceStatsJSON(qw422016, stats) +//line app/vtselect/traces/tempo/tempo.qtpl:189 + qt422016.ReleaseWriter(qw422016) +//line app/vtselect/traces/tempo/tempo.qtpl:189 +} + +//line app/vtselect/traces/tempo/tempo.qtpl:189 +func serviceStatsJSON(stats map[string]serviceStat) string { +//line app/vtselect/traces/tempo/tempo.qtpl:189 + qb422016 := qt422016.AcquireByteBuffer() +//line app/vtselect/traces/tempo/tempo.qtpl:189 + writeserviceStatsJSON(qb422016, stats) +//line app/vtselect/traces/tempo/tempo.qtpl:189 + qs422016 := string(qb422016.B) +//line app/vtselect/traces/tempo/tempo.qtpl:189 + qt422016.ReleaseByteBuffer(qb422016) +//line app/vtselect/traces/tempo/tempo.qtpl:189 + return qs422016 +//line app/vtselect/traces/tempo/tempo.qtpl:189 +} + +//line app/vtselect/traces/tempo/tempo.qtpl:191 +func streamserviceStatJSON(qw422016 *qt422016.Writer, stat serviceStat) { +//line app/vtselect/traces/tempo/tempo.qtpl:191 + qw422016.N().S(`{"spanCount":`) +//line app/vtselect/traces/tempo/tempo.qtpl:192 + qw422016.N().D(stat.spanCount) +//line app/vtselect/traces/tempo/tempo.qtpl:192 + if stat.errorCount > 0 { +//line app/vtselect/traces/tempo/tempo.qtpl:192 + qw422016.N().S(`,"errorCount":`) +//line app/vtselect/traces/tempo/tempo.qtpl:192 + qw422016.N().D(stat.errorCount) +//line app/vtselect/traces/tempo/tempo.qtpl:192 + } +//line app/vtselect/traces/tempo/tempo.qtpl:192 + qw422016.N().S(`}`) +//line app/vtselect/traces/tempo/tempo.qtpl:193 +} + +//line app/vtselect/traces/tempo/tempo.qtpl:193 +func writeserviceStatJSON(qq422016 qtio422016.Writer, stat serviceStat) { +//line app/vtselect/traces/tempo/tempo.qtpl:193 + qw422016 := qt422016.AcquireWriter(qq422016) +//line app/vtselect/traces/tempo/tempo.qtpl:193 + streamserviceStatJSON(qw422016, stat) +//line app/vtselect/traces/tempo/tempo.qtpl:193 + qt422016.ReleaseWriter(qw422016) +//line app/vtselect/traces/tempo/tempo.qtpl:193 +} + +//line app/vtselect/traces/tempo/tempo.qtpl:193 +func serviceStatJSON(stat serviceStat) string { +//line app/vtselect/traces/tempo/tempo.qtpl:193 + qb422016 := qt422016.AcquireByteBuffer() +//line app/vtselect/traces/tempo/tempo.qtpl:193 + writeserviceStatJSON(qb422016, stat) +//line app/vtselect/traces/tempo/tempo.qtpl:193 + qs422016 := string(qb422016.B) +//line app/vtselect/traces/tempo/tempo.qtpl:193 + qt422016.ReleaseByteBuffer(qb422016) +//line app/vtselect/traces/tempo/tempo.qtpl:193 + return qs422016 +//line app/vtselect/traces/tempo/tempo.qtpl:193 +} + +//line app/vtselect/traces/tempo/tempo.qtpl:199 func StreamTraceByIDV1JSON(qw422016 *qt422016.Writer, resourceSpans []*otelpb.ResourceSpans) { -//line app/vtselect/traces/tempo/tempo.qtpl:157 +//line app/vtselect/traces/tempo/tempo.qtpl:199 qw422016.N().S(`{"batches":`) -//line app/vtselect/traces/tempo/tempo.qtpl:159 +//line app/vtselect/traces/tempo/tempo.qtpl:201 streamresourceSpansArrayJSON(qw422016, resourceSpans) -//line app/vtselect/traces/tempo/tempo.qtpl:159 +//line app/vtselect/traces/tempo/tempo.qtpl:201 qw422016.N().S(`}`) -//line app/vtselect/traces/tempo/tempo.qtpl:161 +//line app/vtselect/traces/tempo/tempo.qtpl:203 } -//line app/vtselect/traces/tempo/tempo.qtpl:161 +//line app/vtselect/traces/tempo/tempo.qtpl:203 func WriteTraceByIDV1JSON(qq422016 qtio422016.Writer, resourceSpans []*otelpb.ResourceSpans) { -//line app/vtselect/traces/tempo/tempo.qtpl:161 +//line app/vtselect/traces/tempo/tempo.qtpl:203 qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vtselect/traces/tempo/tempo.qtpl:161 +//line app/vtselect/traces/tempo/tempo.qtpl:203 StreamTraceByIDV1JSON(qw422016, resourceSpans) -//line app/vtselect/traces/tempo/tempo.qtpl:161 +//line app/vtselect/traces/tempo/tempo.qtpl:203 qt422016.ReleaseWriter(qw422016) -//line app/vtselect/traces/tempo/tempo.qtpl:161 +//line app/vtselect/traces/tempo/tempo.qtpl:203 } -//line app/vtselect/traces/tempo/tempo.qtpl:161 +//line app/vtselect/traces/tempo/tempo.qtpl:203 func TraceByIDV1JSON(resourceSpans []*otelpb.ResourceSpans) string { -//line app/vtselect/traces/tempo/tempo.qtpl:161 +//line app/vtselect/traces/tempo/tempo.qtpl:203 qb422016 := qt422016.AcquireByteBuffer() -//line app/vtselect/traces/tempo/tempo.qtpl:161 +//line app/vtselect/traces/tempo/tempo.qtpl:203 WriteTraceByIDV1JSON(qb422016, resourceSpans) -//line app/vtselect/traces/tempo/tempo.qtpl:161 +//line app/vtselect/traces/tempo/tempo.qtpl:203 qs422016 := string(qb422016.B) -//line app/vtselect/traces/tempo/tempo.qtpl:161 +//line app/vtselect/traces/tempo/tempo.qtpl:203 qt422016.ReleaseByteBuffer(qb422016) -//line app/vtselect/traces/tempo/tempo.qtpl:161 +//line app/vtselect/traces/tempo/tempo.qtpl:203 return qs422016 -//line app/vtselect/traces/tempo/tempo.qtpl:161 +//line app/vtselect/traces/tempo/tempo.qtpl:203 } -//line app/vtselect/traces/tempo/tempo.qtpl:167 +//line app/vtselect/traces/tempo/tempo.qtpl:209 func StreamTraceByIDV2JSON(qw422016 *qt422016.Writer, resourceSpans []*otelpb.ResourceSpans) { -//line app/vtselect/traces/tempo/tempo.qtpl:167 +//line app/vtselect/traces/tempo/tempo.qtpl:209 qw422016.N().S(`{"trace":{"resourceSpans":`) -//line app/vtselect/traces/tempo/tempo.qtpl:170 +//line app/vtselect/traces/tempo/tempo.qtpl:212 streamresourceSpansArrayJSON(qw422016, resourceSpans) -//line app/vtselect/traces/tempo/tempo.qtpl:170 +//line app/vtselect/traces/tempo/tempo.qtpl:212 qw422016.N().S(`},"metrics":{"inspectedBytes":"0"}}`) -//line app/vtselect/traces/tempo/tempo.qtpl:176 +//line app/vtselect/traces/tempo/tempo.qtpl:218 } -//line app/vtselect/traces/tempo/tempo.qtpl:176 +//line app/vtselect/traces/tempo/tempo.qtpl:218 func WriteTraceByIDV2JSON(qq422016 qtio422016.Writer, resourceSpans []*otelpb.ResourceSpans) { -//line app/vtselect/traces/tempo/tempo.qtpl:176 +//line app/vtselect/traces/tempo/tempo.qtpl:218 qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vtselect/traces/tempo/tempo.qtpl:176 +//line app/vtselect/traces/tempo/tempo.qtpl:218 StreamTraceByIDV2JSON(qw422016, resourceSpans) -//line app/vtselect/traces/tempo/tempo.qtpl:176 +//line app/vtselect/traces/tempo/tempo.qtpl:218 qt422016.ReleaseWriter(qw422016) -//line app/vtselect/traces/tempo/tempo.qtpl:176 +//line app/vtselect/traces/tempo/tempo.qtpl:218 } -//line app/vtselect/traces/tempo/tempo.qtpl:176 +//line app/vtselect/traces/tempo/tempo.qtpl:218 func TraceByIDV2JSON(resourceSpans []*otelpb.ResourceSpans) string { -//line app/vtselect/traces/tempo/tempo.qtpl:176 +//line app/vtselect/traces/tempo/tempo.qtpl:218 qb422016 := qt422016.AcquireByteBuffer() -//line app/vtselect/traces/tempo/tempo.qtpl:176 +//line app/vtselect/traces/tempo/tempo.qtpl:218 WriteTraceByIDV2JSON(qb422016, resourceSpans) -//line app/vtselect/traces/tempo/tempo.qtpl:176 +//line app/vtselect/traces/tempo/tempo.qtpl:218 qs422016 := string(qb422016.B) -//line app/vtselect/traces/tempo/tempo.qtpl:176 +//line app/vtselect/traces/tempo/tempo.qtpl:218 qt422016.ReleaseByteBuffer(qb422016) -//line app/vtselect/traces/tempo/tempo.qtpl:176 +//line app/vtselect/traces/tempo/tempo.qtpl:218 return qs422016 -//line app/vtselect/traces/tempo/tempo.qtpl:176 +//line app/vtselect/traces/tempo/tempo.qtpl:218 } -//line app/vtselect/traces/tempo/tempo.qtpl:178 +//line app/vtselect/traces/tempo/tempo.qtpl:220 func streamresourceSpansArrayJSON(qw422016 *qt422016.Writer, resourceSpans []*otelpb.ResourceSpans) { -//line app/vtselect/traces/tempo/tempo.qtpl:178 +//line app/vtselect/traces/tempo/tempo.qtpl:220 qw422016.N().S(`[`) -//line app/vtselect/traces/tempo/tempo.qtpl:180 +//line app/vtselect/traces/tempo/tempo.qtpl:222 if len(resourceSpans) > 0 { -//line app/vtselect/traces/tempo/tempo.qtpl:181 +//line app/vtselect/traces/tempo/tempo.qtpl:223 streamresourceSpansJSON(qw422016, resourceSpans[0]) -//line app/vtselect/traces/tempo/tempo.qtpl:182 +//line app/vtselect/traces/tempo/tempo.qtpl:224 for _, rs := range resourceSpans[1:] { -//line app/vtselect/traces/tempo/tempo.qtpl:182 +//line app/vtselect/traces/tempo/tempo.qtpl:224 qw422016.N().S(`,`) -//line app/vtselect/traces/tempo/tempo.qtpl:183 +//line app/vtselect/traces/tempo/tempo.qtpl:225 streamresourceSpansJSON(qw422016, rs) -//line app/vtselect/traces/tempo/tempo.qtpl:184 +//line app/vtselect/traces/tempo/tempo.qtpl:226 } -//line app/vtselect/traces/tempo/tempo.qtpl:185 +//line app/vtselect/traces/tempo/tempo.qtpl:227 } -//line app/vtselect/traces/tempo/tempo.qtpl:185 +//line app/vtselect/traces/tempo/tempo.qtpl:227 qw422016.N().S(`]`) -//line app/vtselect/traces/tempo/tempo.qtpl:187 +//line app/vtselect/traces/tempo/tempo.qtpl:229 } -//line app/vtselect/traces/tempo/tempo.qtpl:187 +//line app/vtselect/traces/tempo/tempo.qtpl:229 func writeresourceSpansArrayJSON(qq422016 qtio422016.Writer, resourceSpans []*otelpb.ResourceSpans) { -//line app/vtselect/traces/tempo/tempo.qtpl:187 +//line app/vtselect/traces/tempo/tempo.qtpl:229 qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vtselect/traces/tempo/tempo.qtpl:187 +//line app/vtselect/traces/tempo/tempo.qtpl:229 streamresourceSpansArrayJSON(qw422016, resourceSpans) -//line app/vtselect/traces/tempo/tempo.qtpl:187 +//line app/vtselect/traces/tempo/tempo.qtpl:229 qt422016.ReleaseWriter(qw422016) -//line app/vtselect/traces/tempo/tempo.qtpl:187 +//line app/vtselect/traces/tempo/tempo.qtpl:229 } -//line app/vtselect/traces/tempo/tempo.qtpl:187 +//line app/vtselect/traces/tempo/tempo.qtpl:229 func resourceSpansArrayJSON(resourceSpans []*otelpb.ResourceSpans) string { -//line app/vtselect/traces/tempo/tempo.qtpl:187 +//line app/vtselect/traces/tempo/tempo.qtpl:229 qb422016 := qt422016.AcquireByteBuffer() -//line app/vtselect/traces/tempo/tempo.qtpl:187 +//line app/vtselect/traces/tempo/tempo.qtpl:229 writeresourceSpansArrayJSON(qb422016, resourceSpans) -//line app/vtselect/traces/tempo/tempo.qtpl:187 +//line app/vtselect/traces/tempo/tempo.qtpl:229 qs422016 := string(qb422016.B) -//line app/vtselect/traces/tempo/tempo.qtpl:187 +//line app/vtselect/traces/tempo/tempo.qtpl:229 qt422016.ReleaseByteBuffer(qb422016) -//line app/vtselect/traces/tempo/tempo.qtpl:187 +//line app/vtselect/traces/tempo/tempo.qtpl:229 return qs422016 -//line app/vtselect/traces/tempo/tempo.qtpl:187 +//line app/vtselect/traces/tempo/tempo.qtpl:229 } -//line app/vtselect/traces/tempo/tempo.qtpl:189 +//line app/vtselect/traces/tempo/tempo.qtpl:231 func streamresourceSpansJSON(qw422016 *qt422016.Writer, rs *otelpb.ResourceSpans) { -//line app/vtselect/traces/tempo/tempo.qtpl:189 +//line app/vtselect/traces/tempo/tempo.qtpl:231 qw422016.N().S(`{"resource":{"attributes":`) -//line app/vtselect/traces/tempo/tempo.qtpl:192 +//line app/vtselect/traces/tempo/tempo.qtpl:234 streamkeyValueListJSON(qw422016, rs.Resource.Attributes) -//line app/vtselect/traces/tempo/tempo.qtpl:192 +//line app/vtselect/traces/tempo/tempo.qtpl:234 qw422016.N().S(`},"scopeSpans":`) -//line app/vtselect/traces/tempo/tempo.qtpl:194 +//line app/vtselect/traces/tempo/tempo.qtpl:236 streamscopeSpansArrayJSON(qw422016, rs.ScopeSpans) -//line app/vtselect/traces/tempo/tempo.qtpl:194 +//line app/vtselect/traces/tempo/tempo.qtpl:236 qw422016.N().S(`}`) -//line app/vtselect/traces/tempo/tempo.qtpl:196 +//line app/vtselect/traces/tempo/tempo.qtpl:238 } -//line app/vtselect/traces/tempo/tempo.qtpl:196 +//line app/vtselect/traces/tempo/tempo.qtpl:238 func writeresourceSpansJSON(qq422016 qtio422016.Writer, rs *otelpb.ResourceSpans) { -//line app/vtselect/traces/tempo/tempo.qtpl:196 +//line app/vtselect/traces/tempo/tempo.qtpl:238 qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vtselect/traces/tempo/tempo.qtpl:196 +//line app/vtselect/traces/tempo/tempo.qtpl:238 streamresourceSpansJSON(qw422016, rs) -//line app/vtselect/traces/tempo/tempo.qtpl:196 +//line app/vtselect/traces/tempo/tempo.qtpl:238 qt422016.ReleaseWriter(qw422016) -//line app/vtselect/traces/tempo/tempo.qtpl:196 +//line app/vtselect/traces/tempo/tempo.qtpl:238 } -//line app/vtselect/traces/tempo/tempo.qtpl:196 +//line app/vtselect/traces/tempo/tempo.qtpl:238 func resourceSpansJSON(rs *otelpb.ResourceSpans) string { -//line app/vtselect/traces/tempo/tempo.qtpl:196 +//line app/vtselect/traces/tempo/tempo.qtpl:238 qb422016 := qt422016.AcquireByteBuffer() -//line app/vtselect/traces/tempo/tempo.qtpl:196 +//line app/vtselect/traces/tempo/tempo.qtpl:238 writeresourceSpansJSON(qb422016, rs) -//line app/vtselect/traces/tempo/tempo.qtpl:196 +//line app/vtselect/traces/tempo/tempo.qtpl:238 qs422016 := string(qb422016.B) -//line app/vtselect/traces/tempo/tempo.qtpl:196 +//line app/vtselect/traces/tempo/tempo.qtpl:238 qt422016.ReleaseByteBuffer(qb422016) -//line app/vtselect/traces/tempo/tempo.qtpl:196 +//line app/vtselect/traces/tempo/tempo.qtpl:238 return qs422016 -//line app/vtselect/traces/tempo/tempo.qtpl:196 +//line app/vtselect/traces/tempo/tempo.qtpl:238 } -//line app/vtselect/traces/tempo/tempo.qtpl:198 +//line app/vtselect/traces/tempo/tempo.qtpl:240 func streamscopeSpansArrayJSON(qw422016 *qt422016.Writer, scopeSpans []*otelpb.ScopeSpans) { -//line app/vtselect/traces/tempo/tempo.qtpl:198 +//line app/vtselect/traces/tempo/tempo.qtpl:240 qw422016.N().S(`[`) -//line app/vtselect/traces/tempo/tempo.qtpl:200 +//line app/vtselect/traces/tempo/tempo.qtpl:242 if len(scopeSpans) > 0 { -//line app/vtselect/traces/tempo/tempo.qtpl:201 +//line app/vtselect/traces/tempo/tempo.qtpl:243 streamscopeSpansJSON(qw422016, scopeSpans[0]) -//line app/vtselect/traces/tempo/tempo.qtpl:202 +//line app/vtselect/traces/tempo/tempo.qtpl:244 for _, ss := range scopeSpans[1:] { -//line app/vtselect/traces/tempo/tempo.qtpl:202 +//line app/vtselect/traces/tempo/tempo.qtpl:244 qw422016.N().S(`,`) -//line app/vtselect/traces/tempo/tempo.qtpl:203 +//line app/vtselect/traces/tempo/tempo.qtpl:245 streamscopeSpansJSON(qw422016, ss) -//line app/vtselect/traces/tempo/tempo.qtpl:204 +//line app/vtselect/traces/tempo/tempo.qtpl:246 } -//line app/vtselect/traces/tempo/tempo.qtpl:205 +//line app/vtselect/traces/tempo/tempo.qtpl:247 } -//line app/vtselect/traces/tempo/tempo.qtpl:205 +//line app/vtselect/traces/tempo/tempo.qtpl:247 qw422016.N().S(`]`) -//line app/vtselect/traces/tempo/tempo.qtpl:207 +//line app/vtselect/traces/tempo/tempo.qtpl:249 } -//line app/vtselect/traces/tempo/tempo.qtpl:207 +//line app/vtselect/traces/tempo/tempo.qtpl:249 func writescopeSpansArrayJSON(qq422016 qtio422016.Writer, scopeSpans []*otelpb.ScopeSpans) { -//line app/vtselect/traces/tempo/tempo.qtpl:207 +//line app/vtselect/traces/tempo/tempo.qtpl:249 qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vtselect/traces/tempo/tempo.qtpl:207 +//line app/vtselect/traces/tempo/tempo.qtpl:249 streamscopeSpansArrayJSON(qw422016, scopeSpans) -//line app/vtselect/traces/tempo/tempo.qtpl:207 +//line app/vtselect/traces/tempo/tempo.qtpl:249 qt422016.ReleaseWriter(qw422016) -//line app/vtselect/traces/tempo/tempo.qtpl:207 +//line app/vtselect/traces/tempo/tempo.qtpl:249 } -//line app/vtselect/traces/tempo/tempo.qtpl:207 +//line app/vtselect/traces/tempo/tempo.qtpl:249 func scopeSpansArrayJSON(scopeSpans []*otelpb.ScopeSpans) string { -//line app/vtselect/traces/tempo/tempo.qtpl:207 +//line app/vtselect/traces/tempo/tempo.qtpl:249 qb422016 := qt422016.AcquireByteBuffer() -//line app/vtselect/traces/tempo/tempo.qtpl:207 +//line app/vtselect/traces/tempo/tempo.qtpl:249 writescopeSpansArrayJSON(qb422016, scopeSpans) -//line app/vtselect/traces/tempo/tempo.qtpl:207 +//line app/vtselect/traces/tempo/tempo.qtpl:249 qs422016 := string(qb422016.B) -//line app/vtselect/traces/tempo/tempo.qtpl:207 +//line app/vtselect/traces/tempo/tempo.qtpl:249 qt422016.ReleaseByteBuffer(qb422016) -//line app/vtselect/traces/tempo/tempo.qtpl:207 +//line app/vtselect/traces/tempo/tempo.qtpl:249 return qs422016 -//line app/vtselect/traces/tempo/tempo.qtpl:207 +//line app/vtselect/traces/tempo/tempo.qtpl:249 } -//line app/vtselect/traces/tempo/tempo.qtpl:209 +//line app/vtselect/traces/tempo/tempo.qtpl:251 func streamscopeSpansJSON(qw422016 *qt422016.Writer, ss *otelpb.ScopeSpans) { -//line app/vtselect/traces/tempo/tempo.qtpl:209 +//line app/vtselect/traces/tempo/tempo.qtpl:251 qw422016.N().S(`{"scope":{"name":`) -//line app/vtselect/traces/tempo/tempo.qtpl:212 +//line app/vtselect/traces/tempo/tempo.qtpl:254 qw422016.N().Q(ss.Scope.Name) -//line app/vtselect/traces/tempo/tempo.qtpl:212 +//line app/vtselect/traces/tempo/tempo.qtpl:254 qw422016.N().S(`,"version":`) -//line app/vtselect/traces/tempo/tempo.qtpl:213 +//line app/vtselect/traces/tempo/tempo.qtpl:255 qw422016.N().Q(ss.Scope.Version) -//line app/vtselect/traces/tempo/tempo.qtpl:213 +//line app/vtselect/traces/tempo/tempo.qtpl:255 qw422016.N().S(`,"attributes":`) -//line app/vtselect/traces/tempo/tempo.qtpl:214 +//line app/vtselect/traces/tempo/tempo.qtpl:256 streamkeyValueListJSON(qw422016, ss.Scope.Attributes) -//line app/vtselect/traces/tempo/tempo.qtpl:214 +//line app/vtselect/traces/tempo/tempo.qtpl:256 qw422016.N().S(`},"spans":`) -//line app/vtselect/traces/tempo/tempo.qtpl:216 +//line app/vtselect/traces/tempo/tempo.qtpl:258 streamspansArrayJSON(qw422016, ss.Spans) -//line app/vtselect/traces/tempo/tempo.qtpl:216 +//line app/vtselect/traces/tempo/tempo.qtpl:258 qw422016.N().S(`}`) -//line app/vtselect/traces/tempo/tempo.qtpl:218 +//line app/vtselect/traces/tempo/tempo.qtpl:260 } -//line app/vtselect/traces/tempo/tempo.qtpl:218 +//line app/vtselect/traces/tempo/tempo.qtpl:260 func writescopeSpansJSON(qq422016 qtio422016.Writer, ss *otelpb.ScopeSpans) { -//line app/vtselect/traces/tempo/tempo.qtpl:218 +//line app/vtselect/traces/tempo/tempo.qtpl:260 qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vtselect/traces/tempo/tempo.qtpl:218 +//line app/vtselect/traces/tempo/tempo.qtpl:260 streamscopeSpansJSON(qw422016, ss) -//line app/vtselect/traces/tempo/tempo.qtpl:218 +//line app/vtselect/traces/tempo/tempo.qtpl:260 qt422016.ReleaseWriter(qw422016) -//line app/vtselect/traces/tempo/tempo.qtpl:218 +//line app/vtselect/traces/tempo/tempo.qtpl:260 } -//line app/vtselect/traces/tempo/tempo.qtpl:218 +//line app/vtselect/traces/tempo/tempo.qtpl:260 func scopeSpansJSON(ss *otelpb.ScopeSpans) string { -//line app/vtselect/traces/tempo/tempo.qtpl:218 +//line app/vtselect/traces/tempo/tempo.qtpl:260 qb422016 := qt422016.AcquireByteBuffer() -//line app/vtselect/traces/tempo/tempo.qtpl:218 +//line app/vtselect/traces/tempo/tempo.qtpl:260 writescopeSpansJSON(qb422016, ss) -//line app/vtselect/traces/tempo/tempo.qtpl:218 +//line app/vtselect/traces/tempo/tempo.qtpl:260 qs422016 := string(qb422016.B) -//line app/vtselect/traces/tempo/tempo.qtpl:218 +//line app/vtselect/traces/tempo/tempo.qtpl:260 qt422016.ReleaseByteBuffer(qb422016) -//line app/vtselect/traces/tempo/tempo.qtpl:218 +//line app/vtselect/traces/tempo/tempo.qtpl:260 return qs422016 -//line app/vtselect/traces/tempo/tempo.qtpl:218 +//line app/vtselect/traces/tempo/tempo.qtpl:260 } -//line app/vtselect/traces/tempo/tempo.qtpl:220 +//line app/vtselect/traces/tempo/tempo.qtpl:262 func streamspansArrayJSON(qw422016 *qt422016.Writer, spans []*otelpb.Span) { -//line app/vtselect/traces/tempo/tempo.qtpl:220 +//line app/vtselect/traces/tempo/tempo.qtpl:262 qw422016.N().S(`[`) -//line app/vtselect/traces/tempo/tempo.qtpl:222 +//line app/vtselect/traces/tempo/tempo.qtpl:264 if len(spans) > 0 { -//line app/vtselect/traces/tempo/tempo.qtpl:223 +//line app/vtselect/traces/tempo/tempo.qtpl:265 streamspanJSON(qw422016, spans[0]) -//line app/vtselect/traces/tempo/tempo.qtpl:224 +//line app/vtselect/traces/tempo/tempo.qtpl:266 for _, s := range spans[1:] { -//line app/vtselect/traces/tempo/tempo.qtpl:224 +//line app/vtselect/traces/tempo/tempo.qtpl:266 qw422016.N().S(`,`) -//line app/vtselect/traces/tempo/tempo.qtpl:225 +//line app/vtselect/traces/tempo/tempo.qtpl:267 streamspanJSON(qw422016, s) -//line app/vtselect/traces/tempo/tempo.qtpl:226 +//line app/vtselect/traces/tempo/tempo.qtpl:268 } -//line app/vtselect/traces/tempo/tempo.qtpl:227 +//line app/vtselect/traces/tempo/tempo.qtpl:269 } -//line app/vtselect/traces/tempo/tempo.qtpl:227 +//line app/vtselect/traces/tempo/tempo.qtpl:269 qw422016.N().S(`]`) -//line app/vtselect/traces/tempo/tempo.qtpl:229 +//line app/vtselect/traces/tempo/tempo.qtpl:271 } -//line app/vtselect/traces/tempo/tempo.qtpl:229 +//line app/vtselect/traces/tempo/tempo.qtpl:271 func writespansArrayJSON(qq422016 qtio422016.Writer, spans []*otelpb.Span) { -//line app/vtselect/traces/tempo/tempo.qtpl:229 +//line app/vtselect/traces/tempo/tempo.qtpl:271 qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vtselect/traces/tempo/tempo.qtpl:229 +//line app/vtselect/traces/tempo/tempo.qtpl:271 streamspansArrayJSON(qw422016, spans) -//line app/vtselect/traces/tempo/tempo.qtpl:229 +//line app/vtselect/traces/tempo/tempo.qtpl:271 qt422016.ReleaseWriter(qw422016) -//line app/vtselect/traces/tempo/tempo.qtpl:229 +//line app/vtselect/traces/tempo/tempo.qtpl:271 } -//line app/vtselect/traces/tempo/tempo.qtpl:229 +//line app/vtselect/traces/tempo/tempo.qtpl:271 func spansArrayJSON(spans []*otelpb.Span) string { -//line app/vtselect/traces/tempo/tempo.qtpl:229 +//line app/vtselect/traces/tempo/tempo.qtpl:271 qb422016 := qt422016.AcquireByteBuffer() -//line app/vtselect/traces/tempo/tempo.qtpl:229 +//line app/vtselect/traces/tempo/tempo.qtpl:271 writespansArrayJSON(qb422016, spans) -//line app/vtselect/traces/tempo/tempo.qtpl:229 +//line app/vtselect/traces/tempo/tempo.qtpl:271 qs422016 := string(qb422016.B) -//line app/vtselect/traces/tempo/tempo.qtpl:229 +//line app/vtselect/traces/tempo/tempo.qtpl:271 qt422016.ReleaseByteBuffer(qb422016) -//line app/vtselect/traces/tempo/tempo.qtpl:229 +//line app/vtselect/traces/tempo/tempo.qtpl:271 return qs422016 -//line app/vtselect/traces/tempo/tempo.qtpl:229 +//line app/vtselect/traces/tempo/tempo.qtpl:271 } -//line app/vtselect/traces/tempo/tempo.qtpl:231 +//line app/vtselect/traces/tempo/tempo.qtpl:273 func streamspanJSON(qw422016 *qt422016.Writer, s *otelpb.Span) { -//line app/vtselect/traces/tempo/tempo.qtpl:231 +//line app/vtselect/traces/tempo/tempo.qtpl:273 qw422016.N().S(`{"traceId":`) -//line app/vtselect/traces/tempo/tempo.qtpl:233 +//line app/vtselect/traces/tempo/tempo.qtpl:275 qw422016.N().Q(hexIDToBase64(s.TraceID)) -//line app/vtselect/traces/tempo/tempo.qtpl:233 +//line app/vtselect/traces/tempo/tempo.qtpl:275 qw422016.N().S(`,"spanId":`) -//line app/vtselect/traces/tempo/tempo.qtpl:234 +//line app/vtselect/traces/tempo/tempo.qtpl:276 qw422016.N().Q(hexIDToBase64(s.SpanID)) -//line app/vtselect/traces/tempo/tempo.qtpl:234 +//line app/vtselect/traces/tempo/tempo.qtpl:276 qw422016.N().S(`,`) -//line app/vtselect/traces/tempo/tempo.qtpl:235 +//line app/vtselect/traces/tempo/tempo.qtpl:277 if s.ParentSpanID != "" { -//line app/vtselect/traces/tempo/tempo.qtpl:235 +//line app/vtselect/traces/tempo/tempo.qtpl:277 qw422016.N().S(`"parentSpanId":`) -//line app/vtselect/traces/tempo/tempo.qtpl:236 +//line app/vtselect/traces/tempo/tempo.qtpl:278 qw422016.N().Q(hexIDToBase64(s.ParentSpanID)) -//line app/vtselect/traces/tempo/tempo.qtpl:236 +//line app/vtselect/traces/tempo/tempo.qtpl:278 qw422016.N().S(`,`) -//line app/vtselect/traces/tempo/tempo.qtpl:237 +//line app/vtselect/traces/tempo/tempo.qtpl:279 } -//line app/vtselect/traces/tempo/tempo.qtpl:237 +//line app/vtselect/traces/tempo/tempo.qtpl:279 qw422016.N().S(`"name":`) -//line app/vtselect/traces/tempo/tempo.qtpl:238 +//line app/vtselect/traces/tempo/tempo.qtpl:280 qw422016.N().Q(s.Name) -//line app/vtselect/traces/tempo/tempo.qtpl:238 +//line app/vtselect/traces/tempo/tempo.qtpl:280 qw422016.N().S(`,"kind":`) -//line app/vtselect/traces/tempo/tempo.qtpl:239 +//line app/vtselect/traces/tempo/tempo.qtpl:281 qw422016.N().Q(spanKindName(s.Kind)) -//line app/vtselect/traces/tempo/tempo.qtpl:239 +//line app/vtselect/traces/tempo/tempo.qtpl:281 qw422016.N().S(`,"startTimeUnixNano":`) -//line app/vtselect/traces/tempo/tempo.qtpl:240 +//line app/vtselect/traces/tempo/tempo.qtpl:282 qw422016.N().Q(strconv.FormatUint(s.StartTimeUnixNano, 10)) -//line app/vtselect/traces/tempo/tempo.qtpl:240 +//line app/vtselect/traces/tempo/tempo.qtpl:282 qw422016.N().S(`,"endTimeUnixNano":`) -//line app/vtselect/traces/tempo/tempo.qtpl:241 +//line app/vtselect/traces/tempo/tempo.qtpl:283 qw422016.N().Q(strconv.FormatUint(s.EndTimeUnixNano, 10)) -//line app/vtselect/traces/tempo/tempo.qtpl:241 +//line app/vtselect/traces/tempo/tempo.qtpl:283 qw422016.N().S(`,"attributes":`) -//line app/vtselect/traces/tempo/tempo.qtpl:242 +//line app/vtselect/traces/tempo/tempo.qtpl:284 streamkeyValueListJSON(qw422016, s.Attributes) -//line app/vtselect/traces/tempo/tempo.qtpl:242 +//line app/vtselect/traces/tempo/tempo.qtpl:284 qw422016.N().S(`,"status":`) -//line app/vtselect/traces/tempo/tempo.qtpl:243 +//line app/vtselect/traces/tempo/tempo.qtpl:285 streamstatusJSON(qw422016, s.Status) -//line app/vtselect/traces/tempo/tempo.qtpl:244 +//line app/vtselect/traces/tempo/tempo.qtpl:286 if len(s.Events) > 0 { -//line app/vtselect/traces/tempo/tempo.qtpl:244 +//line app/vtselect/traces/tempo/tempo.qtpl:286 qw422016.N().S(`,"events":`) -//line app/vtselect/traces/tempo/tempo.qtpl:245 +//line app/vtselect/traces/tempo/tempo.qtpl:287 streameventsArrayJSON(qw422016, s.Events) -//line app/vtselect/traces/tempo/tempo.qtpl:246 +//line app/vtselect/traces/tempo/tempo.qtpl:288 } -//line app/vtselect/traces/tempo/tempo.qtpl:247 +//line app/vtselect/traces/tempo/tempo.qtpl:289 if len(s.Links) > 0 { -//line app/vtselect/traces/tempo/tempo.qtpl:247 +//line app/vtselect/traces/tempo/tempo.qtpl:289 qw422016.N().S(`,"links":`) -//line app/vtselect/traces/tempo/tempo.qtpl:248 +//line app/vtselect/traces/tempo/tempo.qtpl:290 streamlinksArrayJSON(qw422016, s.Links) -//line app/vtselect/traces/tempo/tempo.qtpl:249 +//line app/vtselect/traces/tempo/tempo.qtpl:291 } -//line app/vtselect/traces/tempo/tempo.qtpl:249 +//line app/vtselect/traces/tempo/tempo.qtpl:291 qw422016.N().S(`}`) -//line app/vtselect/traces/tempo/tempo.qtpl:251 +//line app/vtselect/traces/tempo/tempo.qtpl:293 } -//line app/vtselect/traces/tempo/tempo.qtpl:251 +//line app/vtselect/traces/tempo/tempo.qtpl:293 func writespanJSON(qq422016 qtio422016.Writer, s *otelpb.Span) { -//line app/vtselect/traces/tempo/tempo.qtpl:251 +//line app/vtselect/traces/tempo/tempo.qtpl:293 qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vtselect/traces/tempo/tempo.qtpl:251 +//line app/vtselect/traces/tempo/tempo.qtpl:293 streamspanJSON(qw422016, s) -//line app/vtselect/traces/tempo/tempo.qtpl:251 +//line app/vtselect/traces/tempo/tempo.qtpl:293 qt422016.ReleaseWriter(qw422016) -//line app/vtselect/traces/tempo/tempo.qtpl:251 +//line app/vtselect/traces/tempo/tempo.qtpl:293 } -//line app/vtselect/traces/tempo/tempo.qtpl:251 +//line app/vtselect/traces/tempo/tempo.qtpl:293 func spanJSON(s *otelpb.Span) string { -//line app/vtselect/traces/tempo/tempo.qtpl:251 +//line app/vtselect/traces/tempo/tempo.qtpl:293 qb422016 := qt422016.AcquireByteBuffer() -//line app/vtselect/traces/tempo/tempo.qtpl:251 +//line app/vtselect/traces/tempo/tempo.qtpl:293 writespanJSON(qb422016, s) -//line app/vtselect/traces/tempo/tempo.qtpl:251 +//line app/vtselect/traces/tempo/tempo.qtpl:293 qs422016 := string(qb422016.B) -//line app/vtselect/traces/tempo/tempo.qtpl:251 +//line app/vtselect/traces/tempo/tempo.qtpl:293 qt422016.ReleaseByteBuffer(qb422016) -//line app/vtselect/traces/tempo/tempo.qtpl:251 +//line app/vtselect/traces/tempo/tempo.qtpl:293 return qs422016 -//line app/vtselect/traces/tempo/tempo.qtpl:251 +//line app/vtselect/traces/tempo/tempo.qtpl:293 } -//line app/vtselect/traces/tempo/tempo.qtpl:253 +//line app/vtselect/traces/tempo/tempo.qtpl:295 func streamstatusJSON(qw422016 *qt422016.Writer, st otelpb.Status) { -//line app/vtselect/traces/tempo/tempo.qtpl:253 +//line app/vtselect/traces/tempo/tempo.qtpl:295 qw422016.N().S(`{`) -//line app/vtselect/traces/tempo/tempo.qtpl:255 +//line app/vtselect/traces/tempo/tempo.qtpl:297 if st.Message != "" { -//line app/vtselect/traces/tempo/tempo.qtpl:255 +//line app/vtselect/traces/tempo/tempo.qtpl:297 qw422016.N().S(`"message":`) -//line app/vtselect/traces/tempo/tempo.qtpl:256 +//line app/vtselect/traces/tempo/tempo.qtpl:298 qw422016.N().Q(st.Message) -//line app/vtselect/traces/tempo/tempo.qtpl:256 +//line app/vtselect/traces/tempo/tempo.qtpl:298 if st.Code != 0 { -//line app/vtselect/traces/tempo/tempo.qtpl:256 +//line app/vtselect/traces/tempo/tempo.qtpl:298 qw422016.N().S(`,`) -//line app/vtselect/traces/tempo/tempo.qtpl:256 +//line app/vtselect/traces/tempo/tempo.qtpl:298 } -//line app/vtselect/traces/tempo/tempo.qtpl:257 +//line app/vtselect/traces/tempo/tempo.qtpl:299 } -//line app/vtselect/traces/tempo/tempo.qtpl:258 +//line app/vtselect/traces/tempo/tempo.qtpl:300 if st.Code != 0 { -//line app/vtselect/traces/tempo/tempo.qtpl:258 +//line app/vtselect/traces/tempo/tempo.qtpl:300 qw422016.N().S(`"code":`) -//line app/vtselect/traces/tempo/tempo.qtpl:259 +//line app/vtselect/traces/tempo/tempo.qtpl:301 qw422016.N().Q(statusCodeName(st.Code)) -//line app/vtselect/traces/tempo/tempo.qtpl:260 +//line app/vtselect/traces/tempo/tempo.qtpl:302 } -//line app/vtselect/traces/tempo/tempo.qtpl:260 +//line app/vtselect/traces/tempo/tempo.qtpl:302 qw422016.N().S(`}`) -//line app/vtselect/traces/tempo/tempo.qtpl:262 +//line app/vtselect/traces/tempo/tempo.qtpl:304 } -//line app/vtselect/traces/tempo/tempo.qtpl:262 +//line app/vtselect/traces/tempo/tempo.qtpl:304 func writestatusJSON(qq422016 qtio422016.Writer, st otelpb.Status) { -//line app/vtselect/traces/tempo/tempo.qtpl:262 +//line app/vtselect/traces/tempo/tempo.qtpl:304 qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vtselect/traces/tempo/tempo.qtpl:262 +//line app/vtselect/traces/tempo/tempo.qtpl:304 streamstatusJSON(qw422016, st) -//line app/vtselect/traces/tempo/tempo.qtpl:262 +//line app/vtselect/traces/tempo/tempo.qtpl:304 qt422016.ReleaseWriter(qw422016) -//line app/vtselect/traces/tempo/tempo.qtpl:262 +//line app/vtselect/traces/tempo/tempo.qtpl:304 } -//line app/vtselect/traces/tempo/tempo.qtpl:262 +//line app/vtselect/traces/tempo/tempo.qtpl:304 func statusJSON(st otelpb.Status) string { -//line app/vtselect/traces/tempo/tempo.qtpl:262 +//line app/vtselect/traces/tempo/tempo.qtpl:304 qb422016 := qt422016.AcquireByteBuffer() -//line app/vtselect/traces/tempo/tempo.qtpl:262 +//line app/vtselect/traces/tempo/tempo.qtpl:304 writestatusJSON(qb422016, st) -//line app/vtselect/traces/tempo/tempo.qtpl:262 +//line app/vtselect/traces/tempo/tempo.qtpl:304 qs422016 := string(qb422016.B) -//line app/vtselect/traces/tempo/tempo.qtpl:262 +//line app/vtselect/traces/tempo/tempo.qtpl:304 qt422016.ReleaseByteBuffer(qb422016) -//line app/vtselect/traces/tempo/tempo.qtpl:262 +//line app/vtselect/traces/tempo/tempo.qtpl:304 return qs422016 -//line app/vtselect/traces/tempo/tempo.qtpl:262 +//line app/vtselect/traces/tempo/tempo.qtpl:304 } -//line app/vtselect/traces/tempo/tempo.qtpl:264 +//line app/vtselect/traces/tempo/tempo.qtpl:306 func streameventsArrayJSON(qw422016 *qt422016.Writer, events []*otelpb.SpanEvent) { -//line app/vtselect/traces/tempo/tempo.qtpl:264 +//line app/vtselect/traces/tempo/tempo.qtpl:306 qw422016.N().S(`[`) -//line app/vtselect/traces/tempo/tempo.qtpl:266 +//line app/vtselect/traces/tempo/tempo.qtpl:308 if len(events) > 0 { -//line app/vtselect/traces/tempo/tempo.qtpl:267 +//line app/vtselect/traces/tempo/tempo.qtpl:309 streameventJSON(qw422016, events[0]) -//line app/vtselect/traces/tempo/tempo.qtpl:268 +//line app/vtselect/traces/tempo/tempo.qtpl:310 for _, e := range events[1:] { -//line app/vtselect/traces/tempo/tempo.qtpl:268 +//line app/vtselect/traces/tempo/tempo.qtpl:310 qw422016.N().S(`,`) -//line app/vtselect/traces/tempo/tempo.qtpl:269 +//line app/vtselect/traces/tempo/tempo.qtpl:311 streameventJSON(qw422016, e) -//line app/vtselect/traces/tempo/tempo.qtpl:270 +//line app/vtselect/traces/tempo/tempo.qtpl:312 } -//line app/vtselect/traces/tempo/tempo.qtpl:271 +//line app/vtselect/traces/tempo/tempo.qtpl:313 } -//line app/vtselect/traces/tempo/tempo.qtpl:271 +//line app/vtselect/traces/tempo/tempo.qtpl:313 qw422016.N().S(`]`) -//line app/vtselect/traces/tempo/tempo.qtpl:273 +//line app/vtselect/traces/tempo/tempo.qtpl:315 } -//line app/vtselect/traces/tempo/tempo.qtpl:273 +//line app/vtselect/traces/tempo/tempo.qtpl:315 func writeeventsArrayJSON(qq422016 qtio422016.Writer, events []*otelpb.SpanEvent) { -//line app/vtselect/traces/tempo/tempo.qtpl:273 +//line app/vtselect/traces/tempo/tempo.qtpl:315 qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vtselect/traces/tempo/tempo.qtpl:273 +//line app/vtselect/traces/tempo/tempo.qtpl:315 streameventsArrayJSON(qw422016, events) -//line app/vtselect/traces/tempo/tempo.qtpl:273 +//line app/vtselect/traces/tempo/tempo.qtpl:315 qt422016.ReleaseWriter(qw422016) -//line app/vtselect/traces/tempo/tempo.qtpl:273 +//line app/vtselect/traces/tempo/tempo.qtpl:315 } -//line app/vtselect/traces/tempo/tempo.qtpl:273 +//line app/vtselect/traces/tempo/tempo.qtpl:315 func eventsArrayJSON(events []*otelpb.SpanEvent) string { -//line app/vtselect/traces/tempo/tempo.qtpl:273 +//line app/vtselect/traces/tempo/tempo.qtpl:315 qb422016 := qt422016.AcquireByteBuffer() -//line app/vtselect/traces/tempo/tempo.qtpl:273 +//line app/vtselect/traces/tempo/tempo.qtpl:315 writeeventsArrayJSON(qb422016, events) -//line app/vtselect/traces/tempo/tempo.qtpl:273 +//line app/vtselect/traces/tempo/tempo.qtpl:315 qs422016 := string(qb422016.B) -//line app/vtselect/traces/tempo/tempo.qtpl:273 +//line app/vtselect/traces/tempo/tempo.qtpl:315 qt422016.ReleaseByteBuffer(qb422016) -//line app/vtselect/traces/tempo/tempo.qtpl:273 +//line app/vtselect/traces/tempo/tempo.qtpl:315 return qs422016 -//line app/vtselect/traces/tempo/tempo.qtpl:273 +//line app/vtselect/traces/tempo/tempo.qtpl:315 } -//line app/vtselect/traces/tempo/tempo.qtpl:275 +//line app/vtselect/traces/tempo/tempo.qtpl:317 func streameventJSON(qw422016 *qt422016.Writer, e *otelpb.SpanEvent) { -//line app/vtselect/traces/tempo/tempo.qtpl:275 +//line app/vtselect/traces/tempo/tempo.qtpl:317 qw422016.N().S(`{"timeUnixNano":`) -//line app/vtselect/traces/tempo/tempo.qtpl:277 +//line app/vtselect/traces/tempo/tempo.qtpl:319 qw422016.N().Q(strconv.FormatUint(e.TimeUnixNano, 10)) -//line app/vtselect/traces/tempo/tempo.qtpl:277 +//line app/vtselect/traces/tempo/tempo.qtpl:319 qw422016.N().S(`,"name":`) -//line app/vtselect/traces/tempo/tempo.qtpl:278 +//line app/vtselect/traces/tempo/tempo.qtpl:320 qw422016.N().Q(e.Name) -//line app/vtselect/traces/tempo/tempo.qtpl:278 +//line app/vtselect/traces/tempo/tempo.qtpl:320 qw422016.N().S(`,"attributes":`) -//line app/vtselect/traces/tempo/tempo.qtpl:279 +//line app/vtselect/traces/tempo/tempo.qtpl:321 streamkeyValueListJSON(qw422016, e.Attributes) -//line app/vtselect/traces/tempo/tempo.qtpl:279 +//line app/vtselect/traces/tempo/tempo.qtpl:321 qw422016.N().S(`}`) -//line app/vtselect/traces/tempo/tempo.qtpl:281 +//line app/vtselect/traces/tempo/tempo.qtpl:323 } -//line app/vtselect/traces/tempo/tempo.qtpl:281 +//line app/vtselect/traces/tempo/tempo.qtpl:323 func writeeventJSON(qq422016 qtio422016.Writer, e *otelpb.SpanEvent) { -//line app/vtselect/traces/tempo/tempo.qtpl:281 +//line app/vtselect/traces/tempo/tempo.qtpl:323 qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vtselect/traces/tempo/tempo.qtpl:281 +//line app/vtselect/traces/tempo/tempo.qtpl:323 streameventJSON(qw422016, e) -//line app/vtselect/traces/tempo/tempo.qtpl:281 +//line app/vtselect/traces/tempo/tempo.qtpl:323 qt422016.ReleaseWriter(qw422016) -//line app/vtselect/traces/tempo/tempo.qtpl:281 +//line app/vtselect/traces/tempo/tempo.qtpl:323 } -//line app/vtselect/traces/tempo/tempo.qtpl:281 +//line app/vtselect/traces/tempo/tempo.qtpl:323 func eventJSON(e *otelpb.SpanEvent) string { -//line app/vtselect/traces/tempo/tempo.qtpl:281 +//line app/vtselect/traces/tempo/tempo.qtpl:323 qb422016 := qt422016.AcquireByteBuffer() -//line app/vtselect/traces/tempo/tempo.qtpl:281 +//line app/vtselect/traces/tempo/tempo.qtpl:323 writeeventJSON(qb422016, e) -//line app/vtselect/traces/tempo/tempo.qtpl:281 +//line app/vtselect/traces/tempo/tempo.qtpl:323 qs422016 := string(qb422016.B) -//line app/vtselect/traces/tempo/tempo.qtpl:281 +//line app/vtselect/traces/tempo/tempo.qtpl:323 qt422016.ReleaseByteBuffer(qb422016) -//line app/vtselect/traces/tempo/tempo.qtpl:281 +//line app/vtselect/traces/tempo/tempo.qtpl:323 return qs422016 -//line app/vtselect/traces/tempo/tempo.qtpl:281 +//line app/vtselect/traces/tempo/tempo.qtpl:323 } -//line app/vtselect/traces/tempo/tempo.qtpl:283 +//line app/vtselect/traces/tempo/tempo.qtpl:325 func streamlinksArrayJSON(qw422016 *qt422016.Writer, links []*otelpb.SpanLink) { -//line app/vtselect/traces/tempo/tempo.qtpl:283 +//line app/vtselect/traces/tempo/tempo.qtpl:325 qw422016.N().S(`[`) -//line app/vtselect/traces/tempo/tempo.qtpl:285 +//line app/vtselect/traces/tempo/tempo.qtpl:327 if len(links) > 0 { -//line app/vtselect/traces/tempo/tempo.qtpl:286 +//line app/vtselect/traces/tempo/tempo.qtpl:328 streamlinkJSON(qw422016, links[0]) -//line app/vtselect/traces/tempo/tempo.qtpl:287 +//line app/vtselect/traces/tempo/tempo.qtpl:329 for _, l := range links[1:] { -//line app/vtselect/traces/tempo/tempo.qtpl:287 +//line app/vtselect/traces/tempo/tempo.qtpl:329 qw422016.N().S(`,`) -//line app/vtselect/traces/tempo/tempo.qtpl:288 +//line app/vtselect/traces/tempo/tempo.qtpl:330 streamlinkJSON(qw422016, l) -//line app/vtselect/traces/tempo/tempo.qtpl:289 +//line app/vtselect/traces/tempo/tempo.qtpl:331 } -//line app/vtselect/traces/tempo/tempo.qtpl:290 +//line app/vtselect/traces/tempo/tempo.qtpl:332 } -//line app/vtselect/traces/tempo/tempo.qtpl:290 +//line app/vtselect/traces/tempo/tempo.qtpl:332 qw422016.N().S(`]`) -//line app/vtselect/traces/tempo/tempo.qtpl:292 +//line app/vtselect/traces/tempo/tempo.qtpl:334 } -//line app/vtselect/traces/tempo/tempo.qtpl:292 +//line app/vtselect/traces/tempo/tempo.qtpl:334 func writelinksArrayJSON(qq422016 qtio422016.Writer, links []*otelpb.SpanLink) { -//line app/vtselect/traces/tempo/tempo.qtpl:292 +//line app/vtselect/traces/tempo/tempo.qtpl:334 qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vtselect/traces/tempo/tempo.qtpl:292 +//line app/vtselect/traces/tempo/tempo.qtpl:334 streamlinksArrayJSON(qw422016, links) -//line app/vtselect/traces/tempo/tempo.qtpl:292 +//line app/vtselect/traces/tempo/tempo.qtpl:334 qt422016.ReleaseWriter(qw422016) -//line app/vtselect/traces/tempo/tempo.qtpl:292 +//line app/vtselect/traces/tempo/tempo.qtpl:334 } -//line app/vtselect/traces/tempo/tempo.qtpl:292 +//line app/vtselect/traces/tempo/tempo.qtpl:334 func linksArrayJSON(links []*otelpb.SpanLink) string { -//line app/vtselect/traces/tempo/tempo.qtpl:292 +//line app/vtselect/traces/tempo/tempo.qtpl:334 qb422016 := qt422016.AcquireByteBuffer() -//line app/vtselect/traces/tempo/tempo.qtpl:292 +//line app/vtselect/traces/tempo/tempo.qtpl:334 writelinksArrayJSON(qb422016, links) -//line app/vtselect/traces/tempo/tempo.qtpl:292 +//line app/vtselect/traces/tempo/tempo.qtpl:334 qs422016 := string(qb422016.B) -//line app/vtselect/traces/tempo/tempo.qtpl:292 +//line app/vtselect/traces/tempo/tempo.qtpl:334 qt422016.ReleaseByteBuffer(qb422016) -//line app/vtselect/traces/tempo/tempo.qtpl:292 +//line app/vtselect/traces/tempo/tempo.qtpl:334 return qs422016 -//line app/vtselect/traces/tempo/tempo.qtpl:292 +//line app/vtselect/traces/tempo/tempo.qtpl:334 } -//line app/vtselect/traces/tempo/tempo.qtpl:294 +//line app/vtselect/traces/tempo/tempo.qtpl:336 func streamlinkJSON(qw422016 *qt422016.Writer, l *otelpb.SpanLink) { -//line app/vtselect/traces/tempo/tempo.qtpl:294 +//line app/vtselect/traces/tempo/tempo.qtpl:336 qw422016.N().S(`{"traceId":`) -//line app/vtselect/traces/tempo/tempo.qtpl:296 +//line app/vtselect/traces/tempo/tempo.qtpl:338 qw422016.N().Q(hexIDToBase64(l.TraceID)) -//line app/vtselect/traces/tempo/tempo.qtpl:296 +//line app/vtselect/traces/tempo/tempo.qtpl:338 qw422016.N().S(`,"spanId":`) -//line app/vtselect/traces/tempo/tempo.qtpl:297 +//line app/vtselect/traces/tempo/tempo.qtpl:339 qw422016.N().Q(hexIDToBase64(l.SpanID)) -//line app/vtselect/traces/tempo/tempo.qtpl:297 +//line app/vtselect/traces/tempo/tempo.qtpl:339 qw422016.N().S(`,"attributes":`) -//line app/vtselect/traces/tempo/tempo.qtpl:298 +//line app/vtselect/traces/tempo/tempo.qtpl:340 streamkeyValueListJSON(qw422016, l.Attributes) -//line app/vtselect/traces/tempo/tempo.qtpl:298 +//line app/vtselect/traces/tempo/tempo.qtpl:340 qw422016.N().S(`}`) -//line app/vtselect/traces/tempo/tempo.qtpl:300 +//line app/vtselect/traces/tempo/tempo.qtpl:342 } -//line app/vtselect/traces/tempo/tempo.qtpl:300 +//line app/vtselect/traces/tempo/tempo.qtpl:342 func writelinkJSON(qq422016 qtio422016.Writer, l *otelpb.SpanLink) { -//line app/vtselect/traces/tempo/tempo.qtpl:300 +//line app/vtselect/traces/tempo/tempo.qtpl:342 qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vtselect/traces/tempo/tempo.qtpl:300 +//line app/vtselect/traces/tempo/tempo.qtpl:342 streamlinkJSON(qw422016, l) -//line app/vtselect/traces/tempo/tempo.qtpl:300 +//line app/vtselect/traces/tempo/tempo.qtpl:342 qt422016.ReleaseWriter(qw422016) -//line app/vtselect/traces/tempo/tempo.qtpl:300 +//line app/vtselect/traces/tempo/tempo.qtpl:342 } -//line app/vtselect/traces/tempo/tempo.qtpl:300 +//line app/vtselect/traces/tempo/tempo.qtpl:342 func linkJSON(l *otelpb.SpanLink) string { -//line app/vtselect/traces/tempo/tempo.qtpl:300 +//line app/vtselect/traces/tempo/tempo.qtpl:342 qb422016 := qt422016.AcquireByteBuffer() -//line app/vtselect/traces/tempo/tempo.qtpl:300 +//line app/vtselect/traces/tempo/tempo.qtpl:342 writelinkJSON(qb422016, l) -//line app/vtselect/traces/tempo/tempo.qtpl:300 +//line app/vtselect/traces/tempo/tempo.qtpl:342 qs422016 := string(qb422016.B) -//line app/vtselect/traces/tempo/tempo.qtpl:300 +//line app/vtselect/traces/tempo/tempo.qtpl:342 qt422016.ReleaseByteBuffer(qb422016) -//line app/vtselect/traces/tempo/tempo.qtpl:300 +//line app/vtselect/traces/tempo/tempo.qtpl:342 return qs422016 -//line app/vtselect/traces/tempo/tempo.qtpl:300 +//line app/vtselect/traces/tempo/tempo.qtpl:342 } -//line app/vtselect/traces/tempo/tempo.qtpl:302 +//line app/vtselect/traces/tempo/tempo.qtpl:344 func streamkeyValueListJSON(qw422016 *qt422016.Writer, kvs []*otelpb.KeyValue) { -//line app/vtselect/traces/tempo/tempo.qtpl:302 +//line app/vtselect/traces/tempo/tempo.qtpl:344 qw422016.N().S(`[`) -//line app/vtselect/traces/tempo/tempo.qtpl:304 +//line app/vtselect/traces/tempo/tempo.qtpl:346 if len(kvs) > 0 { -//line app/vtselect/traces/tempo/tempo.qtpl:305 +//line app/vtselect/traces/tempo/tempo.qtpl:347 streamkeyValueJSON(qw422016, kvs[0]) -//line app/vtselect/traces/tempo/tempo.qtpl:306 +//line app/vtselect/traces/tempo/tempo.qtpl:348 for _, kv := range kvs[1:] { -//line app/vtselect/traces/tempo/tempo.qtpl:306 +//line app/vtselect/traces/tempo/tempo.qtpl:348 qw422016.N().S(`,`) -//line app/vtselect/traces/tempo/tempo.qtpl:307 +//line app/vtselect/traces/tempo/tempo.qtpl:349 streamkeyValueJSON(qw422016, kv) -//line app/vtselect/traces/tempo/tempo.qtpl:308 +//line app/vtselect/traces/tempo/tempo.qtpl:350 } -//line app/vtselect/traces/tempo/tempo.qtpl:309 +//line app/vtselect/traces/tempo/tempo.qtpl:351 } -//line app/vtselect/traces/tempo/tempo.qtpl:309 +//line app/vtselect/traces/tempo/tempo.qtpl:351 qw422016.N().S(`]`) -//line app/vtselect/traces/tempo/tempo.qtpl:311 +//line app/vtselect/traces/tempo/tempo.qtpl:353 } -//line app/vtselect/traces/tempo/tempo.qtpl:311 +//line app/vtselect/traces/tempo/tempo.qtpl:353 func writekeyValueListJSON(qq422016 qtio422016.Writer, kvs []*otelpb.KeyValue) { -//line app/vtselect/traces/tempo/tempo.qtpl:311 +//line app/vtselect/traces/tempo/tempo.qtpl:353 qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vtselect/traces/tempo/tempo.qtpl:311 +//line app/vtselect/traces/tempo/tempo.qtpl:353 streamkeyValueListJSON(qw422016, kvs) -//line app/vtselect/traces/tempo/tempo.qtpl:311 +//line app/vtselect/traces/tempo/tempo.qtpl:353 qt422016.ReleaseWriter(qw422016) -//line app/vtselect/traces/tempo/tempo.qtpl:311 +//line app/vtselect/traces/tempo/tempo.qtpl:353 } -//line app/vtselect/traces/tempo/tempo.qtpl:311 +//line app/vtselect/traces/tempo/tempo.qtpl:353 func keyValueListJSON(kvs []*otelpb.KeyValue) string { -//line app/vtselect/traces/tempo/tempo.qtpl:311 +//line app/vtselect/traces/tempo/tempo.qtpl:353 qb422016 := qt422016.AcquireByteBuffer() -//line app/vtselect/traces/tempo/tempo.qtpl:311 +//line app/vtselect/traces/tempo/tempo.qtpl:353 writekeyValueListJSON(qb422016, kvs) -//line app/vtselect/traces/tempo/tempo.qtpl:311 +//line app/vtselect/traces/tempo/tempo.qtpl:353 qs422016 := string(qb422016.B) -//line app/vtselect/traces/tempo/tempo.qtpl:311 +//line app/vtselect/traces/tempo/tempo.qtpl:353 qt422016.ReleaseByteBuffer(qb422016) -//line app/vtselect/traces/tempo/tempo.qtpl:311 +//line app/vtselect/traces/tempo/tempo.qtpl:353 return qs422016 -//line app/vtselect/traces/tempo/tempo.qtpl:311 +//line app/vtselect/traces/tempo/tempo.qtpl:353 } -//line app/vtselect/traces/tempo/tempo.qtpl:313 +//line app/vtselect/traces/tempo/tempo.qtpl:355 func streamkeyValueJSON(qw422016 *qt422016.Writer, kv *otelpb.KeyValue) { -//line app/vtselect/traces/tempo/tempo.qtpl:313 +//line app/vtselect/traces/tempo/tempo.qtpl:355 qw422016.N().S(`{"key":`) -//line app/vtselect/traces/tempo/tempo.qtpl:315 +//line app/vtselect/traces/tempo/tempo.qtpl:357 qw422016.N().Q(kv.Key) -//line app/vtselect/traces/tempo/tempo.qtpl:315 +//line app/vtselect/traces/tempo/tempo.qtpl:357 qw422016.N().S(`,"value":`) -//line app/vtselect/traces/tempo/tempo.qtpl:316 +//line app/vtselect/traces/tempo/tempo.qtpl:358 streamanyValueJSON(qw422016, kv.Value) -//line app/vtselect/traces/tempo/tempo.qtpl:316 +//line app/vtselect/traces/tempo/tempo.qtpl:358 qw422016.N().S(`}`) -//line app/vtselect/traces/tempo/tempo.qtpl:318 +//line app/vtselect/traces/tempo/tempo.qtpl:360 } -//line app/vtselect/traces/tempo/tempo.qtpl:318 +//line app/vtselect/traces/tempo/tempo.qtpl:360 func writekeyValueJSON(qq422016 qtio422016.Writer, kv *otelpb.KeyValue) { -//line app/vtselect/traces/tempo/tempo.qtpl:318 +//line app/vtselect/traces/tempo/tempo.qtpl:360 qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vtselect/traces/tempo/tempo.qtpl:318 +//line app/vtselect/traces/tempo/tempo.qtpl:360 streamkeyValueJSON(qw422016, kv) -//line app/vtselect/traces/tempo/tempo.qtpl:318 +//line app/vtselect/traces/tempo/tempo.qtpl:360 qt422016.ReleaseWriter(qw422016) -//line app/vtselect/traces/tempo/tempo.qtpl:318 +//line app/vtselect/traces/tempo/tempo.qtpl:360 } -//line app/vtselect/traces/tempo/tempo.qtpl:318 +//line app/vtselect/traces/tempo/tempo.qtpl:360 func keyValueJSON(kv *otelpb.KeyValue) string { -//line app/vtselect/traces/tempo/tempo.qtpl:318 +//line app/vtselect/traces/tempo/tempo.qtpl:360 qb422016 := qt422016.AcquireByteBuffer() -//line app/vtselect/traces/tempo/tempo.qtpl:318 +//line app/vtselect/traces/tempo/tempo.qtpl:360 writekeyValueJSON(qb422016, kv) -//line app/vtselect/traces/tempo/tempo.qtpl:318 +//line app/vtselect/traces/tempo/tempo.qtpl:360 qs422016 := string(qb422016.B) -//line app/vtselect/traces/tempo/tempo.qtpl:318 +//line app/vtselect/traces/tempo/tempo.qtpl:360 qt422016.ReleaseByteBuffer(qb422016) -//line app/vtselect/traces/tempo/tempo.qtpl:318 +//line app/vtselect/traces/tempo/tempo.qtpl:360 return qs422016 -//line app/vtselect/traces/tempo/tempo.qtpl:318 +//line app/vtselect/traces/tempo/tempo.qtpl:360 } -//line app/vtselect/traces/tempo/tempo.qtpl:320 +//line app/vtselect/traces/tempo/tempo.qtpl:362 func streamanyValueJSON(qw422016 *qt422016.Writer, v *otelpb.AnyValue) { -//line app/vtselect/traces/tempo/tempo.qtpl:320 +//line app/vtselect/traces/tempo/tempo.qtpl:362 qw422016.N().S(`{`) -//line app/vtselect/traces/tempo/tempo.qtpl:322 +//line app/vtselect/traces/tempo/tempo.qtpl:364 if v == nil { -//line app/vtselect/traces/tempo/tempo.qtpl:323 +//line app/vtselect/traces/tempo/tempo.qtpl:365 } else if v.StringValue != nil { -//line app/vtselect/traces/tempo/tempo.qtpl:323 +//line app/vtselect/traces/tempo/tempo.qtpl:365 qw422016.N().S(`"stringValue":`) -//line app/vtselect/traces/tempo/tempo.qtpl:324 +//line app/vtselect/traces/tempo/tempo.qtpl:366 qw422016.N().Q(*v.StringValue) -//line app/vtselect/traces/tempo/tempo.qtpl:325 +//line app/vtselect/traces/tempo/tempo.qtpl:367 } else if v.BoolValue != nil { -//line app/vtselect/traces/tempo/tempo.qtpl:325 +//line app/vtselect/traces/tempo/tempo.qtpl:367 qw422016.N().S(`"boolValue":`) -//line app/vtselect/traces/tempo/tempo.qtpl:326 +//line app/vtselect/traces/tempo/tempo.qtpl:368 if *v.BoolValue { -//line app/vtselect/traces/tempo/tempo.qtpl:326 +//line app/vtselect/traces/tempo/tempo.qtpl:368 qw422016.N().S(`true`) -//line app/vtselect/traces/tempo/tempo.qtpl:326 +//line app/vtselect/traces/tempo/tempo.qtpl:368 } else { -//line app/vtselect/traces/tempo/tempo.qtpl:326 +//line app/vtselect/traces/tempo/tempo.qtpl:368 qw422016.N().S(`false`) -//line app/vtselect/traces/tempo/tempo.qtpl:326 +//line app/vtselect/traces/tempo/tempo.qtpl:368 } -//line app/vtselect/traces/tempo/tempo.qtpl:327 +//line app/vtselect/traces/tempo/tempo.qtpl:369 } else if v.IntValue != nil { -//line app/vtselect/traces/tempo/tempo.qtpl:327 +//line app/vtselect/traces/tempo/tempo.qtpl:369 qw422016.N().S(`"intValue":`) -//line app/vtselect/traces/tempo/tempo.qtpl:328 +//line app/vtselect/traces/tempo/tempo.qtpl:370 qw422016.N().Q(strconv.FormatInt(*v.IntValue, 10)) -//line app/vtselect/traces/tempo/tempo.qtpl:329 +//line app/vtselect/traces/tempo/tempo.qtpl:371 } else if v.DoubleValue != nil { -//line app/vtselect/traces/tempo/tempo.qtpl:329 +//line app/vtselect/traces/tempo/tempo.qtpl:371 qw422016.N().S(`"doubleValue":`) -//line app/vtselect/traces/tempo/tempo.qtpl:330 +//line app/vtselect/traces/tempo/tempo.qtpl:372 qw422016.N().F(*v.DoubleValue) -//line app/vtselect/traces/tempo/tempo.qtpl:331 +//line app/vtselect/traces/tempo/tempo.qtpl:373 } else if v.BytesValue != nil { -//line app/vtselect/traces/tempo/tempo.qtpl:331 +//line app/vtselect/traces/tempo/tempo.qtpl:373 qw422016.N().S(`"bytesValue":`) -//line app/vtselect/traces/tempo/tempo.qtpl:332 +//line app/vtselect/traces/tempo/tempo.qtpl:374 qw422016.N().Q(bytesToBase64(*v.BytesValue)) -//line app/vtselect/traces/tempo/tempo.qtpl:333 +//line app/vtselect/traces/tempo/tempo.qtpl:375 } else if v.ArrayValue != nil { -//line app/vtselect/traces/tempo/tempo.qtpl:333 +//line app/vtselect/traces/tempo/tempo.qtpl:375 qw422016.N().S(`"arrayValue":{"values":`) -//line app/vtselect/traces/tempo/tempo.qtpl:334 +//line app/vtselect/traces/tempo/tempo.qtpl:376 streamanyValueArrayJSON(qw422016, v.ArrayValue.Values) -//line app/vtselect/traces/tempo/tempo.qtpl:334 +//line app/vtselect/traces/tempo/tempo.qtpl:376 qw422016.N().S(`}`) -//line app/vtselect/traces/tempo/tempo.qtpl:335 +//line app/vtselect/traces/tempo/tempo.qtpl:377 } else if v.KeyValueList != nil { -//line app/vtselect/traces/tempo/tempo.qtpl:335 +//line app/vtselect/traces/tempo/tempo.qtpl:377 qw422016.N().S(`"kvlistValue":{"values":`) -//line app/vtselect/traces/tempo/tempo.qtpl:336 +//line app/vtselect/traces/tempo/tempo.qtpl:378 streamkeyValueListJSON(qw422016, v.KeyValueList.Values) -//line app/vtselect/traces/tempo/tempo.qtpl:336 +//line app/vtselect/traces/tempo/tempo.qtpl:378 qw422016.N().S(`}`) -//line app/vtselect/traces/tempo/tempo.qtpl:337 +//line app/vtselect/traces/tempo/tempo.qtpl:379 } -//line app/vtselect/traces/tempo/tempo.qtpl:337 +//line app/vtselect/traces/tempo/tempo.qtpl:379 qw422016.N().S(`}`) -//line app/vtselect/traces/tempo/tempo.qtpl:339 +//line app/vtselect/traces/tempo/tempo.qtpl:381 } -//line app/vtselect/traces/tempo/tempo.qtpl:339 +//line app/vtselect/traces/tempo/tempo.qtpl:381 func writeanyValueJSON(qq422016 qtio422016.Writer, v *otelpb.AnyValue) { -//line app/vtselect/traces/tempo/tempo.qtpl:339 +//line app/vtselect/traces/tempo/tempo.qtpl:381 qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vtselect/traces/tempo/tempo.qtpl:339 +//line app/vtselect/traces/tempo/tempo.qtpl:381 streamanyValueJSON(qw422016, v) -//line app/vtselect/traces/tempo/tempo.qtpl:339 +//line app/vtselect/traces/tempo/tempo.qtpl:381 qt422016.ReleaseWriter(qw422016) -//line app/vtselect/traces/tempo/tempo.qtpl:339 +//line app/vtselect/traces/tempo/tempo.qtpl:381 } -//line app/vtselect/traces/tempo/tempo.qtpl:339 +//line app/vtselect/traces/tempo/tempo.qtpl:381 func anyValueJSON(v *otelpb.AnyValue) string { -//line app/vtselect/traces/tempo/tempo.qtpl:339 +//line app/vtselect/traces/tempo/tempo.qtpl:381 qb422016 := qt422016.AcquireByteBuffer() -//line app/vtselect/traces/tempo/tempo.qtpl:339 +//line app/vtselect/traces/tempo/tempo.qtpl:381 writeanyValueJSON(qb422016, v) -//line app/vtselect/traces/tempo/tempo.qtpl:339 +//line app/vtselect/traces/tempo/tempo.qtpl:381 qs422016 := string(qb422016.B) -//line app/vtselect/traces/tempo/tempo.qtpl:339 +//line app/vtselect/traces/tempo/tempo.qtpl:381 qt422016.ReleaseByteBuffer(qb422016) -//line app/vtselect/traces/tempo/tempo.qtpl:339 +//line app/vtselect/traces/tempo/tempo.qtpl:381 return qs422016 -//line app/vtselect/traces/tempo/tempo.qtpl:339 +//line app/vtselect/traces/tempo/tempo.qtpl:381 } -//line app/vtselect/traces/tempo/tempo.qtpl:341 +//line app/vtselect/traces/tempo/tempo.qtpl:383 func streamanyValueArrayJSON(qw422016 *qt422016.Writer, values []*otelpb.AnyValue) { -//line app/vtselect/traces/tempo/tempo.qtpl:341 +//line app/vtselect/traces/tempo/tempo.qtpl:383 qw422016.N().S(`[`) -//line app/vtselect/traces/tempo/tempo.qtpl:343 +//line app/vtselect/traces/tempo/tempo.qtpl:385 if len(values) > 0 { -//line app/vtselect/traces/tempo/tempo.qtpl:344 +//line app/vtselect/traces/tempo/tempo.qtpl:386 streamanyValueJSON(qw422016, values[0]) -//line app/vtselect/traces/tempo/tempo.qtpl:345 +//line app/vtselect/traces/tempo/tempo.qtpl:387 for _, v := range values[1:] { -//line app/vtselect/traces/tempo/tempo.qtpl:345 +//line app/vtselect/traces/tempo/tempo.qtpl:387 qw422016.N().S(`,`) -//line app/vtselect/traces/tempo/tempo.qtpl:346 +//line app/vtselect/traces/tempo/tempo.qtpl:388 streamanyValueJSON(qw422016, v) -//line app/vtselect/traces/tempo/tempo.qtpl:347 +//line app/vtselect/traces/tempo/tempo.qtpl:389 } -//line app/vtselect/traces/tempo/tempo.qtpl:348 +//line app/vtselect/traces/tempo/tempo.qtpl:390 } -//line app/vtselect/traces/tempo/tempo.qtpl:348 +//line app/vtselect/traces/tempo/tempo.qtpl:390 qw422016.N().S(`]`) -//line app/vtselect/traces/tempo/tempo.qtpl:350 +//line app/vtselect/traces/tempo/tempo.qtpl:392 } -//line app/vtselect/traces/tempo/tempo.qtpl:350 +//line app/vtselect/traces/tempo/tempo.qtpl:392 func writeanyValueArrayJSON(qq422016 qtio422016.Writer, values []*otelpb.AnyValue) { -//line app/vtselect/traces/tempo/tempo.qtpl:350 +//line app/vtselect/traces/tempo/tempo.qtpl:392 qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vtselect/traces/tempo/tempo.qtpl:350 +//line app/vtselect/traces/tempo/tempo.qtpl:392 streamanyValueArrayJSON(qw422016, values) -//line app/vtselect/traces/tempo/tempo.qtpl:350 +//line app/vtselect/traces/tempo/tempo.qtpl:392 qt422016.ReleaseWriter(qw422016) -//line app/vtselect/traces/tempo/tempo.qtpl:350 +//line app/vtselect/traces/tempo/tempo.qtpl:392 } -//line app/vtselect/traces/tempo/tempo.qtpl:350 +//line app/vtselect/traces/tempo/tempo.qtpl:392 func anyValueArrayJSON(values []*otelpb.AnyValue) string { -//line app/vtselect/traces/tempo/tempo.qtpl:350 +//line app/vtselect/traces/tempo/tempo.qtpl:392 qb422016 := qt422016.AcquireByteBuffer() -//line app/vtselect/traces/tempo/tempo.qtpl:350 +//line app/vtselect/traces/tempo/tempo.qtpl:392 writeanyValueArrayJSON(qb422016, values) -//line app/vtselect/traces/tempo/tempo.qtpl:350 +//line app/vtselect/traces/tempo/tempo.qtpl:392 qs422016 := string(qb422016.B) -//line app/vtselect/traces/tempo/tempo.qtpl:350 +//line app/vtselect/traces/tempo/tempo.qtpl:392 qt422016.ReleaseByteBuffer(qb422016) -//line app/vtselect/traces/tempo/tempo.qtpl:350 +//line app/vtselect/traces/tempo/tempo.qtpl:392 return qs422016 -//line app/vtselect/traces/tempo/tempo.qtpl:350 +//line app/vtselect/traces/tempo/tempo.qtpl:392 } diff --git a/app/vtselect/traces/tempo/tempo_test.go b/app/vtselect/traces/tempo/tempo_test.go index 38c47e7ae..efb8e909c 100644 --- a/app/vtselect/traces/tempo/tempo_test.go +++ b/app/vtselect/traces/tempo/tempo_test.go @@ -5,9 +5,96 @@ import ( "encoding/json" "testing" + "github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage" + + "github.com/VictoriaMetrics/VictoriaTraces/app/vtselect/traces/tracecommon" otelpb "github.com/VictoriaMetrics/VictoriaTraces/lib/protoparser/opentelemetry/pb" ) +// spanRow builds a *tracecommon.Row from the given field name/value pairs. +func spanRow(fields map[string]string) *tracecommon.Row { + r := &tracecommon.Row{} + for name, value := range fields { + r.Fields = append(r.Fields, logstorage.Field{Name: name, Value: value}) + } + return r +} + +// TestSummarySearchTracesResult verifies that the search response is populated +// with the spans that satisfied the filter (not the trace root span), and that +// the matched count is independent of whether the root span is present. +func TestSummarySearchTracesResult(t *testing.T) { + const ( + traceID = "0123456789abcdef" + rootSpanID = "1111111111111111" + matchSpanID = "2222222222222222" + ) + + // A root span that does NOT satisfy the filter. + rootRow := spanRow(map[string]string{ + otelpb.TraceIDField: traceID, + otelpb.SpanIDField: rootSpanID, + otelpb.ParentSpanIDField: "", + otelpb.NameField: "root-span", + otelpb.ResourceAttrServiceName: "service-a", + otelpb.StartTimeUnixNanoField: "1000", + otelpb.EndTimeUnixNanoField: "5000", + }) + // A child span that satisfies the filter. The matchedMarkerField is set by + // query 2's 'format if' pipe on spans that match the filter. + matchRow := spanRow(map[string]string{ + otelpb.TraceIDField: traceID, + otelpb.SpanIDField: matchSpanID, + otelpb.ParentSpanIDField: rootSpanID, + otelpb.NameField: "match-span", + otelpb.ResourceAttrServiceName: "service-b", + otelpb.SpanAttrPrefixField + "test_attr": "test_value", + otelpb.StartTimeUnixNanoField: "2000", + otelpb.EndTimeUnixNanoField: "4500", + matchedMarkerField: matchedMarker, + }) + + referenced := []string{otelpb.NameField, "span.test_attr"} + + // f asserts the returned matched span has the expected id/name and that the + // matched count equals wantCount for the given rows. + f := func(name string, rows []*tracecommon.Row, wantSpanID string, wantCount int, wantRootService string) { + t.Helper() + res, err := summarySearchTracesResult(rows, referenced, 3) + if err != nil { + t.Fatalf("%s: unexpected error: %s", name, err) + } + if len(res) != 1 { + t.Fatalf("%s: got %d summaries; want 1", name, len(res)) + } + s := res[0] + if s.matchedCount != wantCount { + t.Fatalf("%s: matchedCount=%d; want %d", name, s.matchedCount, wantCount) + } + if len(s.matchedSpans) != 1 { + t.Fatalf("%s: len(matchedSpans)=%d; want 1", name, len(s.matchedSpans)) + } + ms := s.matchedSpans[0] + if ms.spanID != wantSpanID { + t.Fatalf("%s: matched spanID=%q; want %q (root substituted?)", name, ms.spanID, wantSpanID) + } + if ms.name != "match-span" { + t.Fatalf("%s: matched span name=%q; want %q", name, ms.name, "match-span") + } + if s.rootServiceName != wantRootService { + t.Fatalf("%s: rootServiceName=%q; want %q", name, s.rootServiceName, wantRootService) + } + } + + // Decisive case: the root span exists and does not match; the matched child + // span must be returned, and trace metadata still comes from the root span. + f("root present but non-matching", []*tracecommon.Row{rootRow, matchRow}, matchSpanID, 1, "service-a") + + // Root span not yet ingested: the matched child span and its count must still + // be reported, independent of root-span presence. + f("root span absent", []*tracecommon.Row{matchRow}, matchSpanID, 1, "") +} + // TestTraceByIDV1JSON verifies the bare Trace JSON shape of the Tempo // /api/traces/ (v1) API: resource spans nested under "batches", base64 // IDs, enum-name kind, string-encoded nanos, omitted root parentSpanId. diff --git a/docs/victoriatraces/changelog/CHANGELOG.md b/docs/victoriatraces/changelog/CHANGELOG.md index 274012a56..2fca0dcde 100644 --- a/docs/victoriatraces/changelog/CHANGELOG.md +++ b/docs/victoriatraces/changelog/CHANGELOG.md @@ -18,6 +18,8 @@ The following `tip` changes can be tested by building VictoriaTraces components * FEATURE: [Single-node VictoriaTraces](https://docs.victoriametrics.com/victoriatraces/) and vtstorage in [VictoriaTraces cluster](https://docs.victoriametrics.com/victoriatraces/cluster/): expose filesystem type for storage paths via the `vm_fs_info` metric. This helps identify filesystem-specific issues during troubleshooting. See [#164](https://github.com/VictoriaMetrics/VictoriaTraces/issues/164) for details. +* BUGFIX: [Single-node VictoriaTraces](https://docs.victoriametrics.com/victoriatraces/) and vtselect in [VictoriaTraces cluster](https://docs.victoriametrics.com/victoriatraces/cluster/): populate `spanSets[].spans[]` in the Tempo `/api/search` response with the spans that matched the TraceQL filter (with their real `spanID`, `name`, and query-referenced attributes) instead of the trace root span, so Grafana deep-links to the matched span. Also report the true `matched` count and a `serviceStats` block. See [the pull request #174](https://github.com/VictoriaMetrics/VictoriaTraces/pull/174). + * BUGFIX: [Single-node VictoriaTraces](https://docs.victoriametrics.com/victoriatraces/) and vtinsert in [VictoriaTraces cluster](https://docs.victoriametrics.com/victoriatraces/cluster/): response empty partial success correctly when error message for OTLP ingestion is empty. Thank @immanuwell for [the pull request #170](https://github.com/VictoriaMetrics/VictoriaTraces/pull/170). ## [v0.9.2](https://github.com/VictoriaMetrics/VictoriaTraces/releases/tag/v0.9.2) diff --git a/lib/traceql/filter.go b/lib/traceql/filter.go index 6d9384bd1..a7c898a35 100644 --- a/lib/traceql/filter.go +++ b/lib/traceql/filter.go @@ -29,4 +29,10 @@ type filter interface { // ToLogsQLFilter() logsql GetTraceDurationFilters() []*filterCommon + + // GetReferencedFields must return the field names referenced by the filter + // (in TraceQL form, e.g. "resource.service.name", "kind"). It is used to + // project only the queried attributes onto matched spans in the search + // response, mirroring Tempo's behavior. + GetReferencedFields() []string } diff --git a/lib/traceql/filter_and.go b/lib/traceql/filter_and.go index 215ab5d66..145982380 100644 --- a/lib/traceql/filter_and.go +++ b/lib/traceql/filter_and.go @@ -31,3 +31,11 @@ func (fa *filterAnd) GetTraceDurationFilters() []*filterCommon { } return result } + +func (fa *filterAnd) GetReferencedFields() []string { + var result []string + for _, f := range fa.filters { + result = append(result, f.GetReferencedFields()...) + } + return result +} diff --git a/lib/traceql/filter_general.go b/lib/traceql/filter_general.go index 62ebe5ad3..8e8d4ce41 100644 --- a/lib/traceql/filter_general.go +++ b/lib/traceql/filter_general.go @@ -56,6 +56,27 @@ func StatusCodeToName(code string) string { return code } +// kindCodeMap maps numeric OTEL SpanKind values to their TraceQL names. +var kindCodeMap = map[string]string{ + "0": "unspecified", + "1": "internal", + "2": "server", + "3": "client", + "4": "producer", + "5": "consumer", +} + +// KindCodeToName converts a numeric OTEL SpanKind ("2") to its TraceQL name ("server"). +// Returns the input unchanged if not a known span kind. It is the output-side +// counterpart used when projecting the `kind` attribute into search responses, +// so Grafana displays "server" instead of the raw "2". +func KindCodeToName(code string) string { + if name, ok := kindCodeMap[code]; ok { + return name + } + return code +} + func (fc *filterCommon) String() string { // traceDuration must be treated as pipe if fc.fieldName == "traceDuration" { @@ -183,3 +204,10 @@ func (fc *filterCommon) GetTraceDurationFilters() []*filterCommon { } return nil } + +func (fc *filterCommon) GetReferencedFields() []string { + if fc.fieldName == "" { + return nil + } + return []string{fc.fieldName} +} diff --git a/lib/traceql/filter_noop.go b/lib/traceql/filter_noop.go index c974cad38..cf4d4d985 100644 --- a/lib/traceql/filter_noop.go +++ b/lib/traceql/filter_noop.go @@ -11,3 +11,7 @@ func (fn *filterNoop) String() string { func (fn *filterNoop) GetTraceDurationFilters() []*filterCommon { return nil } + +func (fn *filterNoop) GetReferencedFields() []string { + return nil +} diff --git a/lib/traceql/filter_or.go b/lib/traceql/filter_or.go index e0e297f86..fef7718f1 100644 --- a/lib/traceql/filter_or.go +++ b/lib/traceql/filter_or.go @@ -28,3 +28,11 @@ func (fo *filterOr) GetTraceDurationFilters() []*filterCommon { } return result } + +func (fo *filterOr) GetReferencedFields() []string { + var result []string + for _, f := range fo.filters { + result = append(result, f.GetReferencedFields()...) + } + return result +} diff --git a/lib/traceql/filter_phase.go b/lib/traceql/filter_phase.go index 622a2fc27..90c41dea9 100644 --- a/lib/traceql/filter_phase.go +++ b/lib/traceql/filter_phase.go @@ -18,3 +18,10 @@ func (fp *filterPhrase) String() string { func (fp *filterPhrase) GetTraceDurationFilters() []*filterCommon { return nil } + +func (fp *filterPhrase) GetReferencedFields() []string { + if fp.fieldName == "" { + return nil + } + return []string{fp.fieldName} +} diff --git a/lib/traceql/filter_trace.go b/lib/traceql/filter_trace.go index fa28d7da3..b9bf6e8ff 100644 --- a/lib/traceql/filter_trace.go +++ b/lib/traceql/filter_trace.go @@ -15,3 +15,7 @@ func (f *filterTrace) String() string { func (f *filterTrace) GetTraceDurationFilters() []*filterCommon { return f.andFilter.GetTraceDurationFilters() } + +func (f *filterTrace) GetReferencedFields() []string { + return f.andFilter.GetReferencedFields() +} diff --git a/lib/traceql/parser.go b/lib/traceql/parser.go index 64569e523..7f44faf0b 100644 --- a/lib/traceql/parser.go +++ b/lib/traceql/parser.go @@ -173,6 +173,29 @@ func (q *Query) Filter() string { return q.f.String() } +// ReferencedFields returns the de-duplicated list of field names referenced by +// the query's filter, in TraceQL form (e.g. "resource.service.name", "kind"). +// +// It is used to project only the queried attributes onto matched spans in the +// Tempo search response, mirroring Tempo's behavior of returning the attributes +// named in the query (which Grafana renders as the spans-table columns). +func (q *Query) ReferencedFields() []string { + names := q.f.GetReferencedFields() + seen := make(map[string]struct{}, len(names)) + result := make([]string, 0, len(names)) + for _, n := range names { + if n == "" { + continue + } + if _, ok := seen[n]; ok { + continue + } + seen[n] = struct{}{} + result = append(result, n) + } + return result +} + // ParseQuery parses s. func ParseQuery(s string) (*Query, error) { timestamp := time.Now().UnixNano()