trpc.group/trpc-go/trpc-go@v1.0.3/rpcz/rpcz.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 is a tool that monitors the running state of RPC, recording various things that happen in a rpc,
    15  // such as serialization/deserialization, compression/decompression, and the execution of filter,
    16  // which can be applied to debug and performance optimization.
    17  package rpcz
    18  
    19  import (
    20  	"crypto/rand"
    21  	"encoding/binary"
    22  )
    23  
    24  // GlobalRPCZ to collect span, config by admin module.
    25  // This global variable is unavoidable.
    26  var GlobalRPCZ = NewRPCZ(&Config{Fraction: 0.0, Capacity: 1})
    27  
    28  // RPCZ generates, samples and stores spans.
    29  type RPCZ struct {
    30  	shouldRecord ShouldRecord
    31  	noopSpan
    32  	idGenerator *randomIDGenerator
    33  	sampler     *spanIDRatioSampler
    34  	store       *spanStore
    35  	exporter    SpanExporter
    36  	enabled     bool
    37  }
    38  
    39  var _ recorder = (*RPCZ)(nil)
    40  
    41  // NewRPCZ create a new RPCZ.
    42  func NewRPCZ(cfg *Config) *RPCZ {
    43  	var rngSeed int64
    44  	_ = binary.Read(rand.Reader, binary.LittleEndian, &rngSeed)
    45  	return &RPCZ{
    46  		shouldRecord: cfg.shouldRecord(),
    47  		idGenerator:  newRandomIDGenerator(rngSeed),
    48  		sampler:      newSpanIDRatioSampler(cfg.Fraction),
    49  		store:        newSpanStore(cfg.Capacity),
    50  		exporter:     cfg.Exporter,
    51  		enabled:      cfg.Fraction > 0.0,
    52  	}
    53  }
    54  
    55  // NewChild creates a span, and returns RPCZ itself if rpcz isn't enabled.
    56  // End this span if related operation is completed.
    57  func (r *RPCZ) NewChild(name string) (Span, Ender) {
    58  	if !r.enabled {
    59  		return r, r
    60  	}
    61  
    62  	id := r.idGenerator.newSpanID()
    63  	if !r.sampler.shouldSample(id) {
    64  		s := noopSpan{}
    65  		return s, s
    66  	}
    67  	s := newSpan(name, id, r)
    68  	return s, s
    69  }
    70  
    71  // Query returns a span by ID.
    72  func (r *RPCZ) Query(id SpanID) (*ReadOnlySpan, bool) {
    73  	return r.store.query(id)
    74  }
    75  
    76  // BatchQuery return #num newly inserted span.
    77  func (r *RPCZ) BatchQuery(num int) []*ReadOnlySpan {
    78  	return r.store.batchQuery(num)
    79  }
    80  
    81  func (r *RPCZ) record(s *span) {
    82  	if !r.shouldRecord(s) {
    83  		return
    84  	}
    85  
    86  	if r.exporter != nil {
    87  		r.exporter.Export(s.convertedToReadOnlySpan())
    88  	}
    89  
    90  	r.store.insert(s)
    91  }