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 }