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  }