From bbf64a7b5244a9bfc5d911a3a2cf6a014502eb2f Mon Sep 17 00:00:00 2001 From: Vikrant Gupta Date: Fri, 31 Jan 2025 15:04:21 +0530 Subject: [PATCH] fix(trace-detail): trace details improvements (#6998) * fix(trace-detail): query service and ux improvements * fix(trace-detail): added query service events * fix(trace-detail): address review comments --- .../SpanDetailsDrawer/Events/Events.tsx | 4 +- .../Success/Success.styles.scss | 7 +- .../TraceWaterfallStates/Success/Success.tsx | 3 +- .../app/clickhouseReader/reader.go | 70 ++++++++++++------- .../app/traces/tracedetail/flamegraph.go | 2 +- .../app/traces/tracedetail/waterfall.go | 2 +- pkg/query-service/model/cacheable.go | 1 + 7 files changed, 53 insertions(+), 36 deletions(-) diff --git a/frontend/src/container/SpanDetailsDrawer/Events/Events.tsx b/frontend/src/container/SpanDetailsDrawer/Events/Events.tsx index e339f3f9a2..4eccd8254c 100644 --- a/frontend/src/container/SpanDetailsDrawer/Events/Events.tsx +++ b/frontend/src/container/SpanDetailsDrawer/Events/Events.tsx @@ -45,7 +45,7 @@ function EventsTable(props: IEventsTableProps): JSX.Element { )} {events .filter((eve) => - eve.name.toLowerCase().includes(fieldSearchInput.toLowerCase()), + eve.name?.toLowerCase().includes(fieldSearchInput.toLowerCase()), ) .map((event) => (
{getYAxisFormattedValue( - `${event.timeUnixNano / 1e6 - startTime}`, + `${(event.timeUnixNano || 0) / 1e6 - startTime}`, 'ms', )} diff --git a/frontend/src/container/TraceWaterfall/TraceWaterfallStates/Success/Success.styles.scss b/frontend/src/container/TraceWaterfall/TraceWaterfallStates/Success/Success.styles.scss index 67091de747..95872a882c 100644 --- a/frontend/src/container/TraceWaterfall/TraceWaterfallStates/Success/Success.styles.scss +++ b/frontend/src/container/TraceWaterfall/TraceWaterfallStates/Success/Success.styles.scss @@ -241,18 +241,19 @@ height: 54px; position: relative; width: 100%; + padding-left: 15px; cursor: pointer; .span-line { - position: absolute; + position: relative; height: 12px; top: 35%; border-radius: 6px; } .span-line-text { - position: absolute; - top: 65%; + position: relative; + top: 40%; font-variant-numeric: lining-nums tabular-nums stacked-fractions slashed-zero; font-feature-settings: 'case' on, 'cpsp' on, 'dlig' on, 'salt' on; diff --git a/frontend/src/container/TraceWaterfall/TraceWaterfallStates/Success/Success.tsx b/frontend/src/container/TraceWaterfall/TraceWaterfallStates/Success/Success.tsx index d87bdf877d..b3a113665f 100644 --- a/frontend/src/container/TraceWaterfall/TraceWaterfallStates/Success/Success.tsx +++ b/frontend/src/container/TraceWaterfall/TraceWaterfallStates/Success/Success.tsx @@ -188,14 +188,13 @@ function SpanDuration({ left: `${leftOffset}%`, width: `${width}%`, backgroundColor: color, - marginLeft: '15px', }} /> {`${toFixed(time, 2)} ${timeUnitName}`}
diff --git a/pkg/query-service/app/clickhouseReader/reader.go b/pkg/query-service/app/clickhouseReader/reader.go index f3769061ef..e98dd0368c 100644 --- a/pkg/query-service/app/clickhouseReader/reader.go +++ b/pkg/query-service/app/clickhouseReader/reader.go @@ -1452,7 +1452,9 @@ func (r *ClickHouseReader) GetWaterfallSpansForTraceWithMetadata(ctx context.Con var traceRoots []*model.Span var serviceNameToTotalDurationMap = map[string]uint64{} var serviceNameIntervalMap = map[string][]tracedetail.Interval{} + var hasMissingSpans bool + userEmail , emailErr := auth.GetEmailFromJwt(ctx) cachedTraceData, err := r.GetWaterfallSpansForTraceWithMetadataCache(ctx, traceID) if err == nil { startTime = cachedTraceData.StartTime @@ -1463,6 +1465,11 @@ func (r *ClickHouseReader) GetWaterfallSpansForTraceWithMetadata(ctx context.Con traceRoots = cachedTraceData.TraceRoots totalSpans = cachedTraceData.TotalSpans totalErrorSpans = cachedTraceData.TotalErrorSpans + hasMissingSpans = cachedTraceData.HasMissingSpans + + if emailErr == nil { + telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_TRACE_DETAIL_API, map[string]interface{}{"traceSize": totalSpans}, userEmail, true, false) + } } if err != nil { @@ -1477,6 +1484,10 @@ func (r *ClickHouseReader) GetWaterfallSpansForTraceWithMetadata(ctx context.Con } totalSpans = uint64(len(searchScanResponses)) + if emailErr == nil { + telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_TRACE_DETAIL_API, map[string]interface{}{"traceSize": totalSpans}, userEmail, true, false) + } + processingBeforeCache := time.Now() for _, item := range searchScanResponses { ref := []model.OtelSpanRef{} @@ -1514,7 +1525,23 @@ func (r *ClickHouseReader) GetWaterfallSpansForTraceWithMetadata(ctx context.Con Children: make([]*model.Span, 0), } - // convert start timestamp to millis + // metadata calculation + startTimeUnixNano := uint64(item.TimeUnixNano.UnixNano()) + if startTime == 0 || startTimeUnixNano < startTime { + startTime = startTimeUnixNano + } + if endTime == 0 || (startTimeUnixNano + jsonItem.DurationNano ) > endTime { + endTime = (startTimeUnixNano + jsonItem.DurationNano ) + } + if durationNano == 0 || jsonItem.DurationNano > durationNano { + durationNano = jsonItem.DurationNano + } + + if jsonItem.HasError { + totalErrorSpans = totalErrorSpans + 1 + } + + // convert start timestamp to millis because right now frontend is expecting it in millis jsonItem.TimeUnixNano = uint64(item.TimeUnixNano.UnixNano() / 1000000) // collect the intervals for service for execution time calculation @@ -1523,20 +1550,6 @@ func (r *ClickHouseReader) GetWaterfallSpansForTraceWithMetadata(ctx context.Con // append to the span node map spanIdToSpanNodeMap[jsonItem.SpanID] = &jsonItem - - // metadata calculation - if startTime == 0 || jsonItem.TimeUnixNano < startTime { - startTime = jsonItem.TimeUnixNano - } - if endTime == 0 || (jsonItem.TimeUnixNano+(jsonItem.DurationNano/1000000)) > endTime { - endTime = jsonItem.TimeUnixNano + (jsonItem.DurationNano / 1000000) - } - if durationNano == 0 || jsonItem.DurationNano > durationNano { - durationNano = jsonItem.DurationNano - } - if jsonItem.HasError { - totalErrorSpans = totalErrorSpans + 1 - } } // traverse through the map and append each node to the children array of the parent node @@ -1568,6 +1581,7 @@ func (r *ClickHouseReader) GetWaterfallSpansForTraceWithMetadata(ctx context.Con missingSpan.Children = append(missingSpan.Children, spanNode) spanIdToSpanNodeMap[missingSpan.SpanID] = &missingSpan traceRoots = append(traceRoots, &missingSpan) + hasMissingSpans = true } } } @@ -1595,6 +1609,7 @@ func (r *ClickHouseReader) GetWaterfallSpansForTraceWithMetadata(ctx context.Con SpanIdToSpanNodeMap: spanIdToSpanNodeMap, ServiceNameToTotalDurationMap: serviceNameToTotalDurationMap, TraceRoots: traceRoots, + HasMissingSpans: hasMissingSpans, } zap.L().Info("getWaterfallSpansForTraceWithMetadata: processing pre cache", zap.Duration("duration", time.Since(processingBeforeCache)), zap.String("traceID", traceID)) @@ -1610,14 +1625,14 @@ func (r *ClickHouseReader) GetWaterfallSpansForTraceWithMetadata(ctx context.Con response.Spans = selectedSpans response.UncollapsedSpans = uncollapsedSpans - response.StartTimestampMillis = startTime - response.EndTimestampMillis = endTime + response.StartTimestampMillis = startTime / 1000000 + response.EndTimestampMillis = endTime / 1000000 response.TotalSpansCount = totalSpans response.TotalErrorSpansCount = totalErrorSpans response.RootServiceName = rootServiceName response.RootServiceEntryPoint = rootServiceEntryPoint response.ServiceNameToTotalDurationMap = serviceNameToTotalDurationMap - response.HasMissingSpans = len(traceRoots) > 1 + response.HasMissingSpans = hasMissingSpans return response, nil } @@ -1692,19 +1707,20 @@ func (r *ClickHouseReader) GetFlamegraphSpansForTrace(ctx context.Context, trace Children: make([]*model.FlamegraphSpan, 0), } - jsonItem.TimeUnixNano = uint64(item.TimeUnixNano.UnixNano() / 1000000) - spanIdToSpanNodeMap[jsonItem.SpanID] = &jsonItem - // metadata calculation - if startTime == 0 || jsonItem.TimeUnixNano < startTime { - startTime = jsonItem.TimeUnixNano + startTimeUnixNano := uint64(item.TimeUnixNano.UnixNano()) + if startTime == 0 || startTimeUnixNano < startTime { + startTime = startTimeUnixNano } - if endTime == 0 || (jsonItem.TimeUnixNano+(jsonItem.DurationNano/1000000)) > endTime { - endTime = jsonItem.TimeUnixNano + (jsonItem.DurationNano / 1000000) + if endTime == 0 || ( startTimeUnixNano + jsonItem.DurationNano ) > endTime { + endTime = (startTimeUnixNano + jsonItem.DurationNano ) } if durationNano == 0 || jsonItem.DurationNano > durationNano { durationNano = jsonItem.DurationNano } + + jsonItem.TimeUnixNano = uint64(item.TimeUnixNano.UnixNano() / 1000000) + spanIdToSpanNodeMap[jsonItem.SpanID] = &jsonItem } // traverse through the map and append each node to the children array of the parent node @@ -1760,8 +1776,8 @@ func (r *ClickHouseReader) GetFlamegraphSpansForTrace(ctx context.Context, trace zap.L().Info("getFlamegraphSpansForTrace: processing post cache", zap.Duration("duration", time.Since(processingPostCache)), zap.String("traceID", traceID)) trace.Spans = selectedSpansForRequest - trace.StartTimestampMillis = startTime - trace.EndTimestampMillis = endTime + trace.StartTimestampMillis = startTime / 1000000 + trace.EndTimestampMillis = endTime / 1000000 return trace, nil } diff --git a/pkg/query-service/app/traces/tracedetail/flamegraph.go b/pkg/query-service/app/traces/tracedetail/flamegraph.go index b2c2c81b52..5cfd7c34e8 100644 --- a/pkg/query-service/app/traces/tracedetail/flamegraph.go +++ b/pkg/query-service/app/traces/tracedetail/flamegraph.go @@ -149,7 +149,7 @@ func getLatencyAndTimestampBucketedSpans(spans []*model.FlamegraphSpan, selected } func GetSelectedSpansForFlamegraphForRequest(selectedSpanID string, selectedSpans [][]*model.FlamegraphSpan, startTime uint64, endTime uint64) [][]*model.FlamegraphSpan { - var selectedSpansForRequest [][]*model.FlamegraphSpan + var selectedSpansForRequest = make([][]*model.FlamegraphSpan, 0) var selectedIndex = 0 if selectedSpanID != "" { diff --git a/pkg/query-service/app/traces/tracedetail/waterfall.go b/pkg/query-service/app/traces/tracedetail/waterfall.go index 36aa88ef4f..dace19ea7e 100644 --- a/pkg/query-service/app/traces/tracedetail/waterfall.go +++ b/pkg/query-service/app/traces/tracedetail/waterfall.go @@ -158,7 +158,7 @@ func CalculateServiceTime(serviceIntervals map[string][]Interval) map[string]uin func GetSelectedSpans(uncollapsedSpans []string, selectedSpanID string, traceRoots []*model.Span, spanIdToSpanNodeMap map[string]*model.Span, isSelectedSpanIDUnCollapsed bool) ([]*model.Span, []string, string, string) { - var preOrderTraversal = []*model.Span{} + var preOrderTraversal = make([]*model.Span, 0) var rootServiceName, rootServiceEntryPoint string updatedUncollapsedSpans := uncollapsedSpans diff --git a/pkg/query-service/model/cacheable.go b/pkg/query-service/model/cacheable.go index b691b2765a..d1de82ab37 100644 --- a/pkg/query-service/model/cacheable.go +++ b/pkg/query-service/model/cacheable.go @@ -11,6 +11,7 @@ type GetWaterfallSpansForTraceWithMetadataCache struct { ServiceNameToTotalDurationMap map[string]uint64 `json:"serviceNameToTotalDurationMap"` SpanIdToSpanNodeMap map[string]*Span `json:"spanIdToSpanNodeMap"` TraceRoots []*Span `json:"traceRoots"` + HasMissingSpans bool `json:"hasMissingSpans"` } func (c *GetWaterfallSpansForTraceWithMetadataCache) MarshalBinary() (data []byte, err error) {