github.com/polarismesh/polaris@v1.17.8/plugin/statis/base/apicall.go (about) 1 /** 2 * Tencent is pleased to support the open source community by making Polaris available. 3 * 4 * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 5 * 6 * Licensed under the BSD 3-Clause License (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * https://opensource.org/licenses/BSD-3-Clause 11 * 12 * Unless required by applicable law or agreed to in writing, software distributed 13 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 14 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 15 * specific language governing permissions and limitations under the License. 16 */ 17 18 package base 19 20 import ( 21 "context" 22 "fmt" 23 "math" 24 "sync" 25 "time" 26 27 "github.com/polarismesh/polaris/common/log" 28 "github.com/polarismesh/polaris/common/metrics" 29 ) 30 31 // APICall 接口调用 32 type APICall struct { 33 Api string 34 Code int 35 Duration int64 36 Protocol string 37 Component metrics.CallMetricType 38 } 39 40 // APICallStatisItem 接口调用统计条目 41 type APICallStatisItem struct { 42 API string 43 Code int 44 Count int64 45 AccTime int64 46 MinTime int64 47 MaxTime int64 48 Protocol string 49 ZeroDuration int64 // 没有请求持续的时间,持续时间长超过阈值从 prometheus 中移除掉 50 } 51 52 func (item *APICallStatisItem) String() string { 53 if item.Count == 0 { 54 return "" 55 } 56 return fmt.Sprintf("%-48v|%12v|%12v|%12.3f|%12.3f|%12.3f|\n", 57 item.API, item.Code, item.Count, 58 float64(item.MinTime)/1e6, 59 float64(item.MaxTime)/1e6, 60 float64(item.AccTime)/float64(item.Count)/1e6, 61 ) 62 } 63 64 // ComponentStatics statics components 65 type ComponentStatics struct { 66 t metrics.CallMetricType 67 acc chan *APICall 68 mutex sync.Mutex 69 statis map[string]*APICallStatisItem 70 handler MetricsHandler 71 } 72 73 func NewComponentStatics(ctx context.Context, t metrics.CallMetricType, handler MetricsHandler) *ComponentStatics { 74 c := &ComponentStatics{ 75 t: t, 76 acc: make(chan *APICall, 1024), 77 statis: make(map[string]*APICallStatisItem), 78 handler: handler, 79 } 80 go c.run(ctx) 81 return c 82 } 83 84 // add 添加接口调用数据 85 func (a *ComponentStatics) Add(ac *APICall) { 86 startTime := time.Now() 87 a.acc <- ac 88 passDuration := time.Since(startTime) 89 if passDuration >= MaxAddDuration { 90 log.Warnf("[APICall]add api call cost %s, exceed max %s", passDuration, MaxAddDuration) 91 } 92 } 93 94 // add 添加接口调用数据 95 func (a *ComponentStatics) run(ctx context.Context) { 96 for { 97 select { 98 case <-ctx.Done(): 99 return 100 case item := <-a.acc: 101 a.add(item) 102 } 103 } 104 } 105 106 func (c *ComponentStatics) add(ac *APICall) { 107 c.mutex.Lock() 108 defer c.mutex.Unlock() 109 index := fmt.Sprintf("%v-%v", ac.Api, ac.Code) 110 item, exist := c.statis[index] 111 if exist { 112 item.Count++ 113 114 item.AccTime += ac.Duration 115 if ac.Duration < item.MinTime { 116 item.MinTime = ac.Duration 117 } 118 if ac.Duration > item.MaxTime { 119 item.MaxTime = ac.Duration 120 } 121 } else { 122 c.statis[index] = &APICallStatisItem{ 123 API: ac.Api, 124 Code: ac.Code, 125 Count: 1, 126 AccTime: ac.Duration, 127 MinTime: ac.Duration, 128 MaxTime: ac.Duration, 129 Protocol: ac.Protocol, 130 } 131 } 132 } 133 134 // collect log and print the statics messages 135 func (c *ComponentStatics) deal() { 136 startTime := time.Now() 137 if len(c.statis) == 0 { 138 c.mutex.Lock() 139 defer c.mutex.Unlock() 140 c.handler(c.t, startTime, nil) 141 return 142 } 143 144 c.mutex.Lock() 145 defer func() { 146 c.mutex.Unlock() 147 passDuration := time.Since(startTime) 148 if passDuration >= MaxLogWaitDuration { 149 log.Warnf("[APICall]api static log duration %s, pass max %s", passDuration, MaxLogWaitDuration) 150 } 151 }() 152 153 duplicateStatis := make([]*APICallStatisItem, 0, len(c.statis)) 154 currStatis := c.statis 155 c.statis = make(map[string]*APICallStatisItem) 156 157 for key, item := range currStatis { 158 duplicateStatis = append(duplicateStatis, item) 159 if item.Count == 0 { 160 item.ZeroDuration++ 161 item.MinTime = 0 162 } else { 163 item.ZeroDuration = 0 164 } 165 166 if item.ZeroDuration <= MaxZeroDuration { 167 c.statis[key] = &APICallStatisItem{ 168 API: item.API, 169 Code: item.Code, 170 Count: 0, 171 Protocol: item.Protocol, 172 AccTime: 0, 173 MinTime: math.MaxInt64, 174 MaxTime: 0, 175 ZeroDuration: item.ZeroDuration, 176 } 177 } 178 } 179 180 go func() { 181 c.mutex.Lock() 182 defer c.mutex.Unlock() 183 c.handler(c.t, startTime, duplicateStatis) 184 }() 185 }