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
This commit is contained in:
Vikrant Gupta 2025-01-31 15:04:21 +05:30 committed by GitHub
parent 5783f1555f
commit bbf64a7b52
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 53 additions and 36 deletions

View File

@ -45,7 +45,7 @@ function EventsTable(props: IEventsTableProps): JSX.Element {
)} )}
{events {events
.filter((eve) => .filter((eve) =>
eve.name.toLowerCase().includes(fieldSearchInput.toLowerCase()), eve.name?.toLowerCase().includes(fieldSearchInput.toLowerCase()),
) )
.map((event) => ( .map((event) => (
<div <div
@ -76,7 +76,7 @@ function EventsTable(props: IEventsTableProps): JSX.Element {
<div className="timestamp-container"> <div className="timestamp-container">
<Typography.Text className="attribute-value"> <Typography.Text className="attribute-value">
{getYAxisFormattedValue( {getYAxisFormattedValue(
`${event.timeUnixNano / 1e6 - startTime}`, `${(event.timeUnixNano || 0) / 1e6 - startTime}`,
'ms', 'ms',
)} )}
</Typography.Text> </Typography.Text>

View File

@ -241,18 +241,19 @@
height: 54px; height: 54px;
position: relative; position: relative;
width: 100%; width: 100%;
padding-left: 15px;
cursor: pointer; cursor: pointer;
.span-line { .span-line {
position: absolute; position: relative;
height: 12px; height: 12px;
top: 35%; top: 35%;
border-radius: 6px; border-radius: 6px;
} }
.span-line-text { .span-line-text {
position: absolute; position: relative;
top: 65%; top: 40%;
font-variant-numeric: lining-nums tabular-nums stacked-fractions font-variant-numeric: lining-nums tabular-nums stacked-fractions
slashed-zero; slashed-zero;
font-feature-settings: 'case' on, 'cpsp' on, 'dlig' on, 'salt' on; font-feature-settings: 'case' on, 'cpsp' on, 'dlig' on, 'salt' on;

View File

@ -188,14 +188,13 @@ function SpanDuration({
left: `${leftOffset}%`, left: `${leftOffset}%`,
width: `${width}%`, width: `${width}%`,
backgroundColor: color, backgroundColor: color,
marginLeft: '15px',
}} }}
/> />
<Tooltip title={`${toFixed(time, 2)} ${timeUnitName}`}> <Tooltip title={`${toFixed(time, 2)} ${timeUnitName}`}>
<Typography.Text <Typography.Text
className="span-line-text" className="span-line-text"
ellipsis ellipsis
style={{ left: `${leftOffset}%`, color, marginLeft: '15px' }} style={{ left: `${leftOffset}%`, color }}
>{`${toFixed(time, 2)} ${timeUnitName}`}</Typography.Text> >{`${toFixed(time, 2)} ${timeUnitName}`}</Typography.Text>
</Tooltip> </Tooltip>
</div> </div>

View File

@ -1452,7 +1452,9 @@ func (r *ClickHouseReader) GetWaterfallSpansForTraceWithMetadata(ctx context.Con
var traceRoots []*model.Span var traceRoots []*model.Span
var serviceNameToTotalDurationMap = map[string]uint64{} var serviceNameToTotalDurationMap = map[string]uint64{}
var serviceNameIntervalMap = map[string][]tracedetail.Interval{} var serviceNameIntervalMap = map[string][]tracedetail.Interval{}
var hasMissingSpans bool
userEmail , emailErr := auth.GetEmailFromJwt(ctx)
cachedTraceData, err := r.GetWaterfallSpansForTraceWithMetadataCache(ctx, traceID) cachedTraceData, err := r.GetWaterfallSpansForTraceWithMetadataCache(ctx, traceID)
if err == nil { if err == nil {
startTime = cachedTraceData.StartTime startTime = cachedTraceData.StartTime
@ -1463,6 +1465,11 @@ func (r *ClickHouseReader) GetWaterfallSpansForTraceWithMetadata(ctx context.Con
traceRoots = cachedTraceData.TraceRoots traceRoots = cachedTraceData.TraceRoots
totalSpans = cachedTraceData.TotalSpans totalSpans = cachedTraceData.TotalSpans
totalErrorSpans = cachedTraceData.TotalErrorSpans 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 { if err != nil {
@ -1477,6 +1484,10 @@ func (r *ClickHouseReader) GetWaterfallSpansForTraceWithMetadata(ctx context.Con
} }
totalSpans = uint64(len(searchScanResponses)) 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() processingBeforeCache := time.Now()
for _, item := range searchScanResponses { for _, item := range searchScanResponses {
ref := []model.OtelSpanRef{} ref := []model.OtelSpanRef{}
@ -1514,7 +1525,23 @@ func (r *ClickHouseReader) GetWaterfallSpansForTraceWithMetadata(ctx context.Con
Children: make([]*model.Span, 0), 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) jsonItem.TimeUnixNano = uint64(item.TimeUnixNano.UnixNano() / 1000000)
// collect the intervals for service for execution time calculation // 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 // append to the span node map
spanIdToSpanNodeMap[jsonItem.SpanID] = &jsonItem 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 // 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) missingSpan.Children = append(missingSpan.Children, spanNode)
spanIdToSpanNodeMap[missingSpan.SpanID] = &missingSpan spanIdToSpanNodeMap[missingSpan.SpanID] = &missingSpan
traceRoots = append(traceRoots, &missingSpan) traceRoots = append(traceRoots, &missingSpan)
hasMissingSpans = true
} }
} }
} }
@ -1595,6 +1609,7 @@ func (r *ClickHouseReader) GetWaterfallSpansForTraceWithMetadata(ctx context.Con
SpanIdToSpanNodeMap: spanIdToSpanNodeMap, SpanIdToSpanNodeMap: spanIdToSpanNodeMap,
ServiceNameToTotalDurationMap: serviceNameToTotalDurationMap, ServiceNameToTotalDurationMap: serviceNameToTotalDurationMap,
TraceRoots: traceRoots, TraceRoots: traceRoots,
HasMissingSpans: hasMissingSpans,
} }
zap.L().Info("getWaterfallSpansForTraceWithMetadata: processing pre cache", zap.Duration("duration", time.Since(processingBeforeCache)), zap.String("traceID", traceID)) 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.Spans = selectedSpans
response.UncollapsedSpans = uncollapsedSpans response.UncollapsedSpans = uncollapsedSpans
response.StartTimestampMillis = startTime response.StartTimestampMillis = startTime / 1000000
response.EndTimestampMillis = endTime response.EndTimestampMillis = endTime / 1000000
response.TotalSpansCount = totalSpans response.TotalSpansCount = totalSpans
response.TotalErrorSpansCount = totalErrorSpans response.TotalErrorSpansCount = totalErrorSpans
response.RootServiceName = rootServiceName response.RootServiceName = rootServiceName
response.RootServiceEntryPoint = rootServiceEntryPoint response.RootServiceEntryPoint = rootServiceEntryPoint
response.ServiceNameToTotalDurationMap = serviceNameToTotalDurationMap response.ServiceNameToTotalDurationMap = serviceNameToTotalDurationMap
response.HasMissingSpans = len(traceRoots) > 1 response.HasMissingSpans = hasMissingSpans
return response, nil return response, nil
} }
@ -1692,19 +1707,20 @@ func (r *ClickHouseReader) GetFlamegraphSpansForTrace(ctx context.Context, trace
Children: make([]*model.FlamegraphSpan, 0), Children: make([]*model.FlamegraphSpan, 0),
} }
jsonItem.TimeUnixNano = uint64(item.TimeUnixNano.UnixNano() / 1000000)
spanIdToSpanNodeMap[jsonItem.SpanID] = &jsonItem
// metadata calculation // metadata calculation
if startTime == 0 || jsonItem.TimeUnixNano < startTime { startTimeUnixNano := uint64(item.TimeUnixNano.UnixNano())
startTime = jsonItem.TimeUnixNano if startTime == 0 || startTimeUnixNano < startTime {
startTime = startTimeUnixNano
} }
if endTime == 0 || (jsonItem.TimeUnixNano+(jsonItem.DurationNano/1000000)) > endTime { if endTime == 0 || ( startTimeUnixNano + jsonItem.DurationNano ) > endTime {
endTime = jsonItem.TimeUnixNano + (jsonItem.DurationNano / 1000000) endTime = (startTimeUnixNano + jsonItem.DurationNano )
} }
if durationNano == 0 || jsonItem.DurationNano > durationNano { if durationNano == 0 || jsonItem.DurationNano > durationNano {
durationNano = jsonItem.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 // 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)) zap.L().Info("getFlamegraphSpansForTrace: processing post cache", zap.Duration("duration", time.Since(processingPostCache)), zap.String("traceID", traceID))
trace.Spans = selectedSpansForRequest trace.Spans = selectedSpansForRequest
trace.StartTimestampMillis = startTime trace.StartTimestampMillis = startTime / 1000000
trace.EndTimestampMillis = endTime trace.EndTimestampMillis = endTime / 1000000
return trace, nil return trace, nil
} }

View File

@ -149,7 +149,7 @@ func getLatencyAndTimestampBucketedSpans(spans []*model.FlamegraphSpan, selected
} }
func GetSelectedSpansForFlamegraphForRequest(selectedSpanID string, selectedSpans [][]*model.FlamegraphSpan, startTime uint64, endTime uint64) [][]*model.FlamegraphSpan { 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 var selectedIndex = 0
if selectedSpanID != "" { if selectedSpanID != "" {

View File

@ -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) { 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 var rootServiceName, rootServiceEntryPoint string
updatedUncollapsedSpans := uncollapsedSpans updatedUncollapsedSpans := uncollapsedSpans

View File

@ -11,6 +11,7 @@ type GetWaterfallSpansForTraceWithMetadataCache struct {
ServiceNameToTotalDurationMap map[string]uint64 `json:"serviceNameToTotalDurationMap"` ServiceNameToTotalDurationMap map[string]uint64 `json:"serviceNameToTotalDurationMap"`
SpanIdToSpanNodeMap map[string]*Span `json:"spanIdToSpanNodeMap"` SpanIdToSpanNodeMap map[string]*Span `json:"spanIdToSpanNodeMap"`
TraceRoots []*Span `json:"traceRoots"` TraceRoots []*Span `json:"traceRoots"`
HasMissingSpans bool `json:"hasMissingSpans"`
} }
func (c *GetWaterfallSpansForTraceWithMetadataCache) MarshalBinary() (data []byte, err error) { func (c *GetWaterfallSpansForTraceWithMetadataCache) MarshalBinary() (data []byte, err error) {