github.com/pinpoint-apm/pinpoint-go-agent@v1.4.1-0.20240110120318-a50c2eb18c8c/url_stat.go (about) 1 package pinpoint 2 3 import ( 4 "sync" 5 "time" 6 ) 7 8 const ( 9 urlStatusSuccess = 1 10 urlStatusFail = 2 11 urlStatBucketVersion = 0 12 urlStatBucketSize = 8 13 urlStatCollectInterval = 30 * time.Second 14 ) 15 16 var ( 17 clock tickClock 18 urlSnapshot *urlStatSnapshot 19 urlSnapshotLock sync.Mutex 20 ) 21 22 func (agent *agent) initUrlStat() { 23 clock = newTickClock(urlStatCollectInterval) 24 urlSnapshot = agent.newUrlStatSnapshot() 25 } 26 27 type urlStat struct { 28 entry *UrlStatEntry 29 endTime time.Time 30 elapsed int64 31 } 32 33 type urlStatSnapshot struct { 34 urlMap map[urlKey]*eachUrlStat 35 config *Config 36 count int 37 } 38 39 type urlKey struct { 40 url string 41 tick time.Time 42 } 43 44 type eachUrlStat struct { 45 url string 46 totalHistogram *urlStatHistogram 47 failedHistogram *urlStatHistogram 48 tickTime time.Time 49 } 50 51 type urlStatHistogram struct { 52 total int64 53 max int64 54 histogram []int32 55 } 56 57 type tickClock struct { 58 interval time.Duration 59 } 60 61 func (agent *agent) newUrlStatSnapshot() *urlStatSnapshot { 62 return &urlStatSnapshot{ 63 urlMap: make(map[urlKey]*eachUrlStat, 0), 64 config: agent.config, 65 } 66 } 67 68 func (agent *agent) currentUrlStatSnapshot() *urlStatSnapshot { 69 urlSnapshotLock.Lock() 70 defer urlSnapshotLock.Unlock() 71 return urlSnapshot 72 } 73 74 func (agent *agent) takeUrlStatSnapshot() *urlStatSnapshot { 75 urlSnapshotLock.Lock() 76 defer urlSnapshotLock.Unlock() 77 78 oldSnapshot := urlSnapshot 79 urlSnapshot = agent.newUrlStatSnapshot() 80 return oldSnapshot 81 } 82 83 func (snapshot *urlStatSnapshot) add(us *urlStat) { 84 var url string 85 if snapshot.config.urlStatWithMethod && us.entry.Method != "" { 86 url = us.entry.Method + " " + us.entry.Url 87 } else { 88 url = us.entry.Url 89 } 90 91 key := urlKey{url, clock.tick(us.endTime)} 92 93 e, ok := snapshot.urlMap[key] 94 if !ok { 95 if snapshot.count >= snapshot.config.urlStatLimitSize { 96 return 97 } 98 e = newEachUrlStat(url, key.tick) 99 snapshot.urlMap[key] = e 100 snapshot.count++ 101 } 102 103 e.totalHistogram.add(us.elapsed) 104 if urlStatStatus(us.entry.Status) == urlStatusFail { 105 e.failedHistogram.add(us.elapsed) 106 } 107 } 108 109 func newEachUrlStat(url string, tick time.Time) *eachUrlStat { 110 return &eachUrlStat{ 111 url: url, 112 totalHistogram: newStatHistogram(), 113 failedHistogram: newStatHistogram(), 114 tickTime: tick, 115 } 116 } 117 118 func newStatHistogram() *urlStatHistogram { 119 return &urlStatHistogram{ 120 histogram: make([]int32, urlStatBucketSize), 121 } 122 } 123 124 func (hg *urlStatHistogram) add(elapsed int64) { 125 hg.total += elapsed 126 if hg.max < elapsed { 127 hg.max = elapsed 128 } 129 hg.histogram[getBucket(elapsed)]++ 130 } 131 132 func getBucket(elapsed int64) int { 133 if elapsed < 100 { 134 return 0 135 } else if elapsed < 300 { 136 return 1 137 } else if elapsed < 500 { 138 return 2 139 } else if elapsed < 1000 { 140 return 3 141 } else if elapsed < 3000 { 142 return 4 143 } else if elapsed < 5000 { 144 return 5 145 } else if elapsed < 8000 { 146 return 6 147 } else { 148 return 7 149 } 150 } 151 152 func newTickClock(interval time.Duration) tickClock { 153 return tickClock{interval} 154 } 155 156 func (t tickClock) tick(tm time.Time) time.Time { 157 return tm.Truncate(t.interval) 158 } 159 160 func urlStatStatus(status int) int { 161 if status/100 < 4 { 162 return urlStatusSuccess 163 } else { 164 return urlStatusFail 165 } 166 }