assignNestedSetModelBounds calculates and assigns the values Span.NestedSetLeft, Span.NestedSetRight, and Span.ParentID for all spans in a trace. Returns true if the trace tree is a connected graph which is useful for calculating data quality
(trace *Trace)
| 22 | // and Span.ParentID for all spans in a trace. |
| 23 | // Returns true if the trace tree is a connected graph which is useful for calculating data quality |
| 24 | func assignNestedSetModelBounds(trace *Trace) bool { |
| 25 | // count spans in order be able to pre-allocate tree nodes |
| 26 | var spanCount int |
| 27 | for _, rs := range trace.ResourceSpans { |
| 28 | for _, ss := range rs.ScopeSpans { |
| 29 | spanCount += len(ss.Spans) |
| 30 | } |
| 31 | } |
| 32 | |
| 33 | // find root spans and map span IDs to tree nodes |
| 34 | var ( |
| 35 | undoAssignment bool |
| 36 | allNodes = make([]spanNode, 0, spanCount) |
| 37 | nodesByID = make(map[uint64][]*spanNode, spanCount) |
| 38 | rootNodes []*spanNode |
| 39 | ) |
| 40 | |
| 41 | for _, rs := range trace.ResourceSpans { |
| 42 | for _, ss := range rs.ScopeSpans { |
| 43 | for i, s := range ss.Spans { |
| 44 | allNodes = append(allNodes, spanNode{span: &ss.Spans[i]}) |
| 45 | node := &allNodes[len(allNodes)-1] |
| 46 | |
| 47 | if s.IsRoot() { |
| 48 | rootNodes = append(rootNodes, node) |
| 49 | } |
| 50 | |
| 51 | id := util.SpanIDToUint64(s.SpanID) |
| 52 | if nodes, ok := nodesByID[id]; ok { |
| 53 | // zipkin traces may contain client/server spans with the same IDs |
| 54 | nodes = append(nodes, node) |
| 55 | nodesByID[id] = nodes |
| 56 | if len(nodes) > 2 { |
| 57 | undoAssignment = true |
| 58 | } |
| 59 | } else { |
| 60 | nodesByID[id] = []*spanNode{node} |
| 61 | } |
| 62 | } |
| 63 | } |
| 64 | } |
| 65 | |
| 66 | // check preconditions before assignment |
| 67 | if len(rootNodes) == 0 { |
| 68 | return false |
| 69 | } |
| 70 | if undoAssignment { |
| 71 | for _, nodes := range nodesByID { |
| 72 | for _, n := range nodes { |
| 73 | n.span.NestedSetLeft = 0 |
| 74 | n.span.NestedSetRight = 0 |
| 75 | n.span.ParentID = 0 |
| 76 | } |
| 77 | } |
| 78 | // this trace has over 2 spans with the same span id. the data is invalid and therefore we are preferring "false", |
| 79 | // but semantically it's different then detecting a disconnected graph |
| 80 | return false |
| 81 | } |