trpc.group/trpc-go/trpc-go@v1.0.3/rpcz/readonlyspan.go (about) 1 // 2 // 3 // Tencent is pleased to support the open source community by making tRPC available. 4 // 5 // Copyright (C) 2023 THL A29 Limited, a Tencent company. 6 // All rights reserved. 7 // 8 // If you have downloaded a copy of the tRPC source code from Tencent, 9 // please note that tRPC source code is licensed under the Apache 2.0 License, 10 // A copy of the Apache 2.0 License is included in this file. 11 // 12 // 13 14 package rpcz 15 16 import ( 17 "fmt" 18 "strings" 19 "time" 20 ) 21 22 // ReadOnlySpan is exported from writable span to achieve concurrency safety. 23 type ReadOnlySpan struct { 24 ID SpanID 25 Name string 26 27 // StartTime is the time at which this span was started. 28 StartTime time.Time 29 30 // EndTime is the time at which this span was ended. It contains the zero 31 // value of time.Time until the span is ended. 32 EndTime time.Time 33 34 // used at route server when client send request. 35 ChildSpans []*ReadOnlySpan 36 37 // track event, used at codec and kinds of filter. 38 Events []Event 39 40 // Attributes records attributes of span. 41 Attributes []Attribute 42 } 43 44 // PrintSketch prints sketched description of span. 45 func (s *ReadOnlySpan) PrintSketch(indentation string) string { 46 return s.printSketch(nil, indentation) 47 } 48 49 // PrintDetail prints detailed description of span. 50 func (s *ReadOnlySpan) PrintDetail(indentation string) string { 51 return s.printDetail(nil, indentation) 52 } 53 54 func (s *ReadOnlySpan) printSketch(parent *ReadOnlySpan, indentation string) string { 55 content := fmt.Sprintf("%sspan: (%s, %d)\n", indentation, s.Name, s.ID) 56 indentation += " " 57 content += fmt.Sprintf("%stime: (%s, %s)\n", indentation, s.StartTime.Format(time.StampMicro), s.printEndTime()) 58 content += fmt.Sprintf( 59 "%sduration: (%s, %s, %s)\n", 60 indentation, 61 s.printPrevDuration(parent), 62 s.printDuration(), 63 s.printPostDuration(parent), 64 ) 65 if attributes := s.printAttributes(); len(attributes) != 0 { 66 content += fmt.Sprintf("%sattributes: %s\n", indentation, attributes) 67 } 68 return content 69 } 70 71 func (s *ReadOnlySpan) printDetail(parent *ReadOnlySpan, indentation string) string { 72 content := s.printSketch(parent, indentation) 73 content += s.printChildSpansAndEvents(indentation + " ") 74 return content 75 } 76 77 // printChildSpansAndEvents prints ChildSpans and Events in order of StartTime alternatively. 78 func (s *ReadOnlySpan) printChildSpansAndEvents(indentation string) string { 79 var ( 80 content string 81 i, j int 82 ) 83 for i < len(s.Events) && j < len(s.ChildSpans) { 84 if s.Events[i].Time.Before(s.ChildSpans[j].StartTime) { 85 content += fmt.Sprintf("%sevent: %s\n", indentation, printEvent(s.Events[i])) 86 i++ 87 } else { 88 content += s.ChildSpans[j].printDetail(s, indentation) 89 j++ 90 } 91 } 92 for ; i < len(s.Events); i++ { 93 content += fmt.Sprintf("%sevent: %s\n", indentation, printEvent(s.Events[i])) 94 } 95 for ; j < len(s.ChildSpans); j++ { 96 content += s.ChildSpans[j].printDetail(s, indentation) 97 } 98 return content 99 } 100 101 func printEvent(e Event) string { 102 return fmt.Sprintf("(%s, %v)", e.Name, e.Time.Format(time.StampMicro)) 103 } 104 105 func (s *ReadOnlySpan) printAttributes() string { 106 var content []string 107 for _, a := range s.Attributes { 108 if a.Name == TRPCAttributeFilterNames { 109 continue 110 } 111 content = append(content, fmt.Sprintf("(%s, %v)", parsedTRPCAttribute(a.Name), a.Value)) 112 } 113 return strings.Join(content, ",") 114 } 115 116 const ( 117 unknownEnd = "unknown" 118 zeroDuration = "0" 119 ) 120 121 func (s *ReadOnlySpan) printPrevDuration(parent *ReadOnlySpan) string { 122 if parent == nil { 123 return zeroDuration 124 } 125 return fmt.Sprint(s.StartTime.Sub(parent.StartTime)) 126 } 127 128 func (s *ReadOnlySpan) printDuration() string { 129 if s.EndTime.IsZero() { 130 return unknownEnd 131 } 132 return fmt.Sprint(s.EndTime.Sub(s.StartTime)) 133 } 134 135 func (s *ReadOnlySpan) printEndTime() string { 136 if s.EndTime.IsZero() { 137 return unknownEnd 138 } 139 return fmt.Sprint(s.EndTime.Format(time.StampMicro)) 140 } 141 142 func (s *ReadOnlySpan) printPostDuration(parent *ReadOnlySpan) string { 143 if parent == nil { 144 return zeroDuration 145 } 146 if parent.EndTime.IsZero() || s.EndTime.IsZero() { 147 return unknownEnd 148 } 149 return fmt.Sprint(parent.EndTime.Sub(s.EndTime)) 150 }