├── .gitignore ├── LICENSE ├── README.md ├── README_zh.md ├── bloom └── bloom.go ├── ginmetrics ├── metric.go ├── middleware.go └── types.go ├── go.mod ├── go.sum └── grafana ├── README.md ├── grafana.json └── grafana.png /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Pelin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gin-metrics 2 | gin-gonic/gin metrics exporter for Prometheus. 3 | 4 | [中文](README_zh.md) 5 | 6 | - [Introduction](#Introduction) 7 | - [Grafana](#Grafana) 8 | - [Installation](#Installation) 9 | - [Usage](#Usage) 10 | - [Custom Metric](#Custom-Metric) 11 | - [Metric with separate port](#Metric-with-separate-port) 12 | - [Contributing](#Contributing) 13 | 14 | ## Introduction 15 | 16 | `gin-metrics` defines some metrics for gin http-server. There have easy way to use it. 17 | 18 | Below is the detailed description for every metric. 19 | 20 | | Metric | Type | Description | 21 | | ----------------------- | --------- | --------------------------------------------------- | 22 | | gin_request_total | Counter | all the server received request num. | 23 | | gin_request_uv | Counter | all the server received ip num. | 24 | | gin_uri_request_total | Counter | all the server received request num with every uri. | 25 | | gin_request_body_total | Counter | the server received request body size, unit byte. | 26 | | gin_response_body_total | Counter | the server send response body size, unit byte. | 27 | | gin_request_duration | Histogram | the time server took to handle the request. | 28 | | gin_slow_request_total | Counter | the server handled slow requests counter, t=%d. | 29 | 30 | 31 | ## Grafana 32 | 33 | 34 | Set the `grafana` directory for details. 35 | 36 | ![grafana](./grafana/grafana.png) 37 | 38 | 39 | ## Installation 40 | 41 | ```bash 42 | $ go get github.com/penglongli/gin-metrics 43 | ``` 44 | 45 | ## Usage 46 | 47 | Your can see some metrics across `http://localhost:8080/metrics` 48 | 49 | ```go 50 | package main 51 | 52 | import ( 53 | "github.com/gin-gonic/gin" 54 | 55 | "github.com/penglongli/gin-metrics/ginmetrics" 56 | ) 57 | 58 | func main() { 59 | r := gin.Default() 60 | 61 | // get global Monitor object 62 | m := ginmetrics.GetMonitor() 63 | 64 | // +optional set metric path, default /debug/metrics 65 | m.SetMetricPath("/metrics") 66 | // +optional set slow time, default 5s 67 | m.SetSlowTime(10) 68 | // +optional set request duration, default {0.1, 0.3, 1.2, 5, 10} 69 | // used to p95, p99 70 | m.SetDuration([]float64{0.1, 0.3, 1.2, 5, 10}) 71 | 72 | // set middleware for gin 73 | m.Use(r) 74 | 75 | r.GET("/product/:id", func(ctx *gin.Context) { 76 | ctx.JSON(200, map[string]string{ 77 | "productId": ctx.Param("id"), 78 | }) 79 | }) 80 | 81 | _ = r.Run() 82 | } 83 | ``` 84 | 85 | ## Custom Metric 86 | 87 | `gin-metric` provides ways to custom your own metric. 88 | 89 | ### Gauge 90 | 91 | With `Gauge` type metric, you can use three functions to change it's value. 92 | 93 | And you should define a `Gauge` Metric first, 94 | 95 | ```go 96 | gaugeMetric := &ginmetrics.Metric{ 97 | Type: ginmetrics.Gauge, 98 | Name: "example_gauge_metric", 99 | Description: "an example of gauge type metric", 100 | Labels: []string{"label1"}, 101 | } 102 | 103 | // Add metric to global monitor object 104 | _ = ginmetrics.GetMonitor().AddMetric(gaugeMetric) 105 | ``` 106 | 107 | **SetGaugeValue** 108 | 109 | `SetGaugeValue` will setting metric value directly。 110 | 111 | ```go 112 | _ = ginmetrics.GetMonitor().GetMetric("example_gauge_metric").SetGaugeValue([]string{"label_value1"}, 0.1) 113 | ``` 114 | 115 | **Inc** 116 | 117 | `Inc` will increase 1 to metric value 118 | 119 | ```go 120 | _ = ginmetrics.GetMonitor().GetMetric("example_gauge_metric").Inc([]string{"label_value1"}) 121 | ``` 122 | 123 | **Add** 124 | 125 | `Add` will add float64 num to metric value 126 | 127 | ```go 128 | _ = ginmetrics.GetMonitor().GetMetric("example_gauge_metric").Add([]string{"label_value1"}, 0.2) 129 | ``` 130 | 131 | ### Counter 132 | 133 | With `Counter` type metric, you can use `Inc` and `Add` function, don't use `SetGaugeValue`. 134 | 135 | 136 | ### Histogram and Summary 137 | 138 | For `Histogram` and `Summary` type metric, should use `Observe` function. 139 | 140 | ## Metric with separate port 141 | 142 | For some users, they don't want to merge the port of the metric with the port of the application. 143 | 144 | So we provide a way to separate the metric port. Here is the example. 145 | 146 | ```go 147 | func main() { 148 | appRouter := gin.Default() 149 | metricRouter := gin.Default() 150 | 151 | m := ginmetrics.GetMonitor() 152 | // use metric middleware without expose metric path 153 | m.UseWithoutExposingEndpoint(appRouter) 154 | // set metric path expose to metric router 155 | m.Expose(metricRouter) 156 | 157 | appRouter.GET("/product/:id", func(ctx *gin.Context) { 158 | ctx.JSON(200, map[string]string{ 159 | "productId": ctx.Param("id"), 160 | }) 161 | }) 162 | go func() { 163 | _ = metricRouter.Run(":8081") 164 | }() 165 | _ = appRouter.Run(":8080") 166 | } 167 | ``` 168 | 169 | ## Contributing 170 | 171 | If someone has a problem or suggestions, you can submit [new issues](https://github.com/penglongli/gin-metrics/issues/new) 172 | or [new pull requests](https://github.com/penglongli/gin-metrics/pulls). 173 | 174 | -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 | # gin-metrics 2 | gin-gonic/gin metrics exporter for Prometheus. 3 | 4 | 5 | ## Introduction 6 | 7 | `gin-metrics` 为 gin HTTP 服务定义了一些监控指标,开箱即用。下边是默认监控指标的详细描述: 8 | 9 | 10 | | Metric | Type | Description | 11 | | ----------------------- | --------- | --------------------------------------------------- | 12 | | gin_request_total | Counter | 服务接收到的请求总数 | 13 | | gin_request_uv | Counter | 服务接收到的 IP 总数 | 14 | | gin_uri_request_total | Counter | 每个 URI 接收到的服务请求数 | 15 | | gin_request_body_total | Counter | 服务接收到的请求量,单位: 字节 | 16 | | gin_response_body_total | Counter | 服务返回的请求量,单位: 字节 | 17 | | gin_request_duration | Histogram | 服务处理请求使用的时间 | 18 | | gin_slow_request_total | Counter | 服务接收到的慢请求计数 | 19 | 20 | 21 | ## Installation 22 | 23 | ```bash 24 | $ go get github.com/penglongli/gin-metrics 25 | ``` 26 | 27 | ## Usage 28 | 29 | 使用如下代码运行,访问:`http://localhost:8080/metrics` 即可看到暴露出来的监控指标 30 | 31 | ```go 32 | package main 33 | 34 | import ( 35 | "github.com/gin-gonic/gin" 36 | 37 | "github.com/penglongli/gin-metrics/ginmetrics" 38 | ) 39 | 40 | func main() { 41 | r := gin.Default() 42 | 43 | // get global Monitor object 44 | m := ginmetrics.GetMonitor() 45 | 46 | // +optional set metric path, default /debug/metrics 47 | m.SetMetricPath("/metrics") 48 | // +optional set slow time, default 5s 49 | m.SetSlowTime(10) 50 | // +optional set request duration, default {0.1, 0.3, 1.2, 5, 10} 51 | // used to p95, p99 52 | m.SetDuration([]float64{0.1, 0.3, 1.2, 5, 10}) 53 | 54 | // set middleware for gin 55 | m.Use(r) 56 | 57 | r.GET("/product/:id", func(ctx *gin.Context) { 58 | ctx.JSON(200, map[string]string{ 59 | "productId": ctx.Param("id"), 60 | }) 61 | }) 62 | 63 | _ = r.Run() 64 | } 65 | ``` 66 | 67 | ## Custom Metric 68 | 69 | `gin-metric` 提供了自定义监控指标的使用方式 70 | 71 | ### Gauge 72 | 73 | 使用 `Gauge` 类型监控指标,可以通过 3 种方法来修改监控值:`SetGaugeValue`、`Inc`、`Add` 74 | 75 | 首先,需要定义一个 `Gauge` 类型的监控指标: 76 | 77 | ```go 78 | gaugeMetric := &ginmetrics.Metric{ 79 | Type: ginmetrics.Gauge, 80 | Name: "example_gauge_metric", 81 | Description: "an example of gauge type metric", 82 | Labels: []string{"label1"}, 83 | } 84 | 85 | // Add metric to global monitor object 86 | _ = ginmetrics.GetMonitor().AddMetric(gaugeMetric) 87 | ``` 88 | 89 | **SetGaugeValue** 90 | 91 | `SetGaugeValue` 方法会直接设置监控指标的值 92 | 93 | ```go 94 | _ = ginmetrics.GetMonitor().GetMetric("example_gauge_metric").SetGaugeValue([]string{"label_value1"}, 0.1) 95 | ``` 96 | 97 | **Inc** 98 | 99 | `Inc` 方法会在监控指标值的基础上增加 1 100 | 101 | ```go 102 | _ = ginmetrics.GetMonitor().GetMetric("example_gauge_metric").Inc([]string{"label_value1"}) 103 | ``` 104 | 105 | **Add** 106 | 107 | `Add` 方法会为监控指标增加传入的值 108 | 109 | ```go 110 | _ = ginmetrics.GetMonitor().GetMetric("example_gauge_metric").Add([]string{"label_value1"}, 0.2) 111 | ``` 112 | 113 | ### Counter 114 | 115 | `Counter` 类型的监控指标,可以使用 `Inc` 和 `Add` 方法,但是不能使用 `SetGaugeValue` 方法 116 | 117 | 118 | ### Histogram and Summary 119 | 120 | 对于 `Histogram` 和 `Summary` 类型的监控指标,需要用 `Observe` 方法来设置监控值。 121 | 122 | ## Contributing 123 | 124 | 如果有遇见什么问题,或者需要修改,可以 [新建 ISSUE](https://github.com/penglongli/gin-metrics/issues/new) 125 | 或者 [新建 PullRequest](https://github.com/penglongli/gin-metrics/pulls). 126 | 127 | -------------------------------------------------------------------------------- /bloom/bloom.go: -------------------------------------------------------------------------------- 1 | package bloom 2 | 3 | import ( 4 | "github.com/bits-and-blooms/bitset" 5 | ) 6 | 7 | const defaultSize = 2 << 24 8 | 9 | var seeds = []uint{7, 11, 13, 31, 37, 61} 10 | 11 | type BloomFilter struct { 12 | Set *bitset.BitSet 13 | Funcs [6]simpleHash 14 | } 15 | 16 | func NewBloomFilter() *BloomFilter { 17 | bf := new(BloomFilter) 18 | for i := 0; i < len(bf.Funcs); i++ { 19 | bf.Funcs[i] = simpleHash{defaultSize, seeds[i]} 20 | } 21 | bf.Set = bitset.New(defaultSize) 22 | return bf 23 | } 24 | 25 | func (bf *BloomFilter) Add(value string) { 26 | for _, f := range bf.Funcs { 27 | bf.Set.Set(f.hash(value)) 28 | } 29 | } 30 | 31 | func (bf *BloomFilter) Contains(value string) bool { 32 | if value == "" { 33 | return false 34 | } 35 | ret := true 36 | for _, f := range bf.Funcs { 37 | ret = ret && bf.Set.Test(f.hash(value)) 38 | } 39 | return ret 40 | } 41 | 42 | type simpleHash struct { 43 | Cap uint 44 | Seed uint 45 | } 46 | 47 | func (s *simpleHash) hash(value string) uint { 48 | var result uint = 0 49 | for i := 0; i < len(value); i++ { 50 | result = result*s.Seed + uint(value[i]) 51 | } 52 | return (s.Cap - 1) & result 53 | } 54 | -------------------------------------------------------------------------------- /ginmetrics/metric.go: -------------------------------------------------------------------------------- 1 | package ginmetrics 2 | 3 | import ( 4 | "github.com/pkg/errors" 5 | "github.com/prometheus/client_golang/prometheus" 6 | ) 7 | 8 | // Metric defines a metric object. Users can use it to save 9 | // metric data. Every metric should be globally unique by name. 10 | type Metric struct { 11 | Type MetricType 12 | Name string 13 | Description string 14 | Labels []string 15 | Buckets []float64 16 | Objectives map[float64]float64 17 | 18 | vec prometheus.Collector 19 | } 20 | 21 | // SetGaugeValue set data for Gauge type Metric. 22 | func (m *Metric) SetGaugeValue(labelValues []string, value float64) error { 23 | if m.Type == None { 24 | return errors.Errorf("metric '%s' not existed.", m.Name) 25 | } 26 | 27 | if m.Type != Gauge { 28 | return errors.Errorf("metric '%s' not Gauge type", m.Name) 29 | } 30 | m.vec.(*prometheus.GaugeVec).WithLabelValues(labelValues...).Set(value) 31 | return nil 32 | } 33 | 34 | // Inc increases value for Counter/Gauge type metric, increments 35 | // the counter by 1 36 | func (m *Metric) Inc(labelValues []string) error { 37 | if m.Type == None { 38 | return errors.Errorf("metric '%s' not existed.", m.Name) 39 | } 40 | 41 | if m.Type != Gauge && m.Type != Counter { 42 | return errors.Errorf("metric '%s' not Gauge or Counter type", m.Name) 43 | } 44 | switch m.Type { 45 | case Counter: 46 | m.vec.(*prometheus.CounterVec).WithLabelValues(labelValues...).Inc() 47 | break 48 | case Gauge: 49 | m.vec.(*prometheus.GaugeVec).WithLabelValues(labelValues...).Inc() 50 | break 51 | } 52 | return nil 53 | } 54 | 55 | // Add adds the given value to the Metric object. Only 56 | // for Counter/Gauge type metric. 57 | func (m *Metric) Add(labelValues []string, value float64) error { 58 | if m.Type == None { 59 | return errors.Errorf("metric '%s' not existed.", m.Name) 60 | } 61 | 62 | if m.Type != Gauge && m.Type != Counter { 63 | return errors.Errorf("metric '%s' not Gauge or Counter type", m.Name) 64 | } 65 | switch m.Type { 66 | case Counter: 67 | m.vec.(*prometheus.CounterVec).WithLabelValues(labelValues...).Add(value) 68 | break 69 | case Gauge: 70 | m.vec.(*prometheus.GaugeVec).WithLabelValues(labelValues...).Add(value) 71 | break 72 | } 73 | return nil 74 | } 75 | 76 | // Observe is used by Histogram and Summary type metric to 77 | // add observations. 78 | func (m *Metric) Observe(labelValues []string, value float64) error { 79 | if m.Type == 0 { 80 | return errors.Errorf("metric '%s' not existed.", m.Name) 81 | } 82 | if m.Type != Histogram && m.Type != Summary { 83 | return errors.Errorf("metric '%s' not Histogram or Summary type", m.Name) 84 | } 85 | switch m.Type { 86 | case Histogram: 87 | m.vec.(*prometheus.HistogramVec).WithLabelValues(labelValues...).Observe(value) 88 | break 89 | case Summary: 90 | m.vec.(*prometheus.SummaryVec).WithLabelValues(labelValues...).Observe(value) 91 | break 92 | } 93 | return nil 94 | } 95 | -------------------------------------------------------------------------------- /ginmetrics/middleware.go: -------------------------------------------------------------------------------- 1 | package ginmetrics 2 | 3 | import ( 4 | "fmt" 5 | "slices" 6 | "strconv" 7 | "time" 8 | 9 | "github.com/gin-gonic/gin" 10 | "github.com/prometheus/client_golang/prometheus/promhttp" 11 | 12 | "github.com/penglongli/gin-metrics/bloom" 13 | ) 14 | 15 | var ( 16 | metricRequestTotal = "gin_request_total" 17 | metricRequestUVTotal = "gin_request_uv_total" 18 | metricURIRequestTotal = "gin_uri_request_total" 19 | metricRequestBody = "gin_request_body_total" 20 | metricResponseBody = "gin_response_body_total" 21 | metricRequestDuration = "gin_request_duration" 22 | metricSlowRequest = "gin_slow_request_total" 23 | 24 | bloomFilter *bloom.BloomFilter 25 | ) 26 | 27 | // Use set gin metrics middleware 28 | func (m *Monitor) Use(r gin.IRoutes) { 29 | m.initGinMetrics() 30 | 31 | r.Use(m.monitorInterceptor) 32 | r.GET(m.metricPath, func(ctx *gin.Context) { 33 | promhttp.Handler().ServeHTTP(ctx.Writer, ctx.Request) 34 | }) 35 | } 36 | 37 | // UseWithoutExposingEndpoint is used to add monitor interceptor to gin router 38 | // It can be called multiple times to intercept from multiple gin.IRoutes 39 | // http path is not set, to do that use Expose function 40 | func (m *Monitor) UseWithoutExposingEndpoint(r gin.IRoutes) { 41 | m.initGinMetrics() 42 | r.Use(m.monitorInterceptor) 43 | } 44 | 45 | // Expose adds metric path to a given router. 46 | // The router can be different with the one passed to UseWithoutExposingEndpoint. 47 | // This allows to expose metrics on different port. 48 | func (m *Monitor) Expose(r gin.IRoutes) { 49 | r.GET(m.metricPath, func(ctx *gin.Context) { 50 | promhttp.Handler().ServeHTTP(ctx.Writer, ctx.Request) 51 | }) 52 | } 53 | 54 | // initGinMetrics used to init gin metrics 55 | func (m *Monitor) initGinMetrics() { 56 | bloomFilter = bloom.NewBloomFilter() 57 | 58 | _ = monitor.AddMetric(&Metric{ 59 | Type: Counter, 60 | Name: metricRequestTotal, 61 | Description: "all the server received request num.", 62 | Labels: m.getMetricLabelsIncludingMetadata(metricRequestTotal), 63 | }) 64 | _ = monitor.AddMetric(&Metric{ 65 | Type: Counter, 66 | Name: metricRequestUVTotal, 67 | Description: "all the server received ip num.", 68 | Labels: m.getMetricLabelsIncludingMetadata(metricRequestUVTotal), 69 | }) 70 | _ = monitor.AddMetric(&Metric{ 71 | Type: Counter, 72 | Name: metricURIRequestTotal, 73 | Description: "all the server received request num with every uri.", 74 | Labels: m.getMetricLabelsIncludingMetadata(metricURIRequestTotal), 75 | }) 76 | _ = monitor.AddMetric(&Metric{ 77 | Type: Counter, 78 | Name: metricRequestBody, 79 | Description: "the server received request body size, unit byte", 80 | Labels: m.getMetricLabelsIncludingMetadata(metricRequestBody), 81 | }) 82 | _ = monitor.AddMetric(&Metric{ 83 | Type: Counter, 84 | Name: metricResponseBody, 85 | Description: "the server send response body size, unit byte", 86 | Labels: m.getMetricLabelsIncludingMetadata(metricResponseBody), 87 | }) 88 | _ = monitor.AddMetric(&Metric{ 89 | Type: Histogram, 90 | Name: metricRequestDuration, 91 | Description: "the time server took to handle the request.", 92 | Labels: m.getMetricLabelsIncludingMetadata(metricRequestDuration), 93 | Buckets: m.reqDuration, 94 | }) 95 | _ = monitor.AddMetric(&Metric{ 96 | Type: Counter, 97 | Name: metricSlowRequest, 98 | Description: fmt.Sprintf("the server handled slow requests counter, t=%d.", m.slowTime), 99 | Labels: m.getMetricLabelsIncludingMetadata(metricSlowRequest), 100 | }) 101 | } 102 | 103 | func (m *Monitor) includesMetadata() bool { 104 | return len(m.metadata) > 0 105 | } 106 | 107 | func (m *Monitor) getMetadata() ([]string, []string) { 108 | metadata_labels := []string{} 109 | metadata_values := []string{} 110 | 111 | for v := range m.metadata { 112 | metadata_labels = append(metadata_labels, v) 113 | metadata_values = append(metadata_values, m.metadata[v]) 114 | } 115 | 116 | return metadata_labels, metadata_values 117 | } 118 | 119 | func (m *Monitor) getMetricLabelsIncludingMetadata(metricName string) []string { 120 | includes_metadata := m.includesMetadata() 121 | metadata_labels, _ := m.getMetadata() 122 | 123 | switch metricName { 124 | case metricRequestDuration: 125 | metric_labels := []string{"uri"} 126 | if includes_metadata { 127 | metric_labels = append(metric_labels, metadata_labels...) 128 | } 129 | return metric_labels 130 | 131 | case metricURIRequestTotal: 132 | metric_labels := []string{"uri", "method", "code"} 133 | if includes_metadata { 134 | metric_labels = append(metric_labels, metadata_labels...) 135 | } 136 | return metric_labels 137 | 138 | case metricSlowRequest: 139 | metric_labels := []string{"uri", "method", "code"} 140 | if includes_metadata { 141 | metric_labels = append(metric_labels, metadata_labels...) 142 | } 143 | return metric_labels 144 | 145 | default: 146 | var metric_labels []string = nil 147 | if includes_metadata { 148 | metric_labels = metadata_labels 149 | } 150 | return metric_labels 151 | } 152 | } 153 | 154 | // monitorInterceptor as gin monitor middleware. 155 | func (m *Monitor) monitorInterceptor(ctx *gin.Context) { 156 | // some paths should not be reported 157 | if ctx.Request.URL.Path == m.metricPath || 158 | slices.Contains(m.excludePaths, ctx.Request.URL.Path) { 159 | ctx.Next() 160 | return 161 | } 162 | startTime := time.Now() 163 | 164 | // execute normal process. 165 | ctx.Next() 166 | 167 | // after request 168 | m.ginMetricHandle(ctx, startTime) 169 | } 170 | 171 | func (m *Monitor) ginMetricHandle(ctx *gin.Context, start time.Time) { 172 | r := ctx.Request 173 | w := ctx.Writer 174 | 175 | // set request total 176 | var metric_values []string = nil 177 | _ = m.GetMetric(metricRequestTotal).Inc(m.getMetricValues(metric_values)) 178 | 179 | // set uv 180 | if clientIP := ctx.ClientIP(); !bloomFilter.Contains(clientIP) { 181 | bloomFilter.Add(clientIP) 182 | metric_values = nil 183 | _ = m.GetMetric(metricRequestUVTotal).Inc(m.getMetricValues(metric_values)) 184 | } 185 | 186 | // set uri request total 187 | metric_values = []string{ctx.FullPath(), r.Method, strconv.Itoa(w.Status())} 188 | _ = m.GetMetric(metricURIRequestTotal).Inc(m.getMetricValues(metric_values)) 189 | 190 | // set request body size 191 | // since r.ContentLength can be negative (in some occasions) guard the operation 192 | if r.ContentLength >= 0 { 193 | metric_values = nil 194 | _ = m.GetMetric(metricRequestBody).Add(m.getMetricValues(metric_values), float64(r.ContentLength)) 195 | } 196 | 197 | // set slow request 198 | latency := time.Since(start) 199 | if int32(latency.Seconds()) > m.slowTime { 200 | metric_values = []string{ctx.FullPath(), r.Method, strconv.Itoa(w.Status())} 201 | _ = m.GetMetric(metricSlowRequest).Inc(m.getMetricValues(metric_values)) 202 | } 203 | 204 | // set request duration 205 | metric_values = []string{ctx.FullPath()} 206 | _ = m.GetMetric(metricRequestDuration).Observe(m.getMetricValues(metric_values), latency.Seconds()) 207 | 208 | // set response size 209 | if w.Size() > 0 { 210 | metric_values = nil 211 | _ = m.GetMetric(metricResponseBody).Add(m.getMetricValues(metric_values), float64(w.Size())) 212 | } 213 | } 214 | 215 | func (m *Monitor) getMetricValues(metric_values []string) []string { 216 | includes_metadata := m.includesMetadata() 217 | _, metadata_values := m.getMetadata() 218 | if includes_metadata { 219 | metric_values = append(metric_values, metadata_values...) 220 | } 221 | return metric_values 222 | } 223 | -------------------------------------------------------------------------------- /ginmetrics/types.go: -------------------------------------------------------------------------------- 1 | package ginmetrics 2 | 3 | import ( 4 | "github.com/pkg/errors" 5 | "github.com/prometheus/client_golang/prometheus" 6 | ) 7 | 8 | type MetricType int 9 | 10 | const ( 11 | None MetricType = iota 12 | Counter 13 | Gauge 14 | Histogram 15 | Summary 16 | 17 | defaultMetricPath = "/debug/metrics" 18 | defaultSlowTime = int32(5) 19 | ) 20 | 21 | var ( 22 | defaultExcludePaths = []string{} 23 | defaultDuration = []float64{0.1, 0.3, 1.2, 5, 10} 24 | monitor *Monitor 25 | 26 | promTypeHandler = map[MetricType]func(metric *Metric) error{ 27 | Counter: counterHandler, 28 | Gauge: gaugeHandler, 29 | Histogram: histogramHandler, 30 | Summary: summaryHandler, 31 | } 32 | ) 33 | 34 | // Monitor is an object that uses to set gin server monitor. 35 | type Monitor struct { 36 | slowTime int32 37 | metricPath string 38 | excludePaths []string 39 | reqDuration []float64 40 | metrics map[string]*Metric 41 | metadata map[string]string 42 | } 43 | 44 | // GetMonitor used to get global Monitor object, 45 | // this function returns a singleton object. 46 | func GetMonitor() *Monitor { 47 | if monitor == nil { 48 | monitor = &Monitor{ 49 | metricPath: defaultMetricPath, 50 | slowTime: defaultSlowTime, 51 | excludePaths: defaultExcludePaths, 52 | reqDuration: defaultDuration, 53 | metrics: make(map[string]*Metric), 54 | metadata: make(map[string]string), 55 | } 56 | } 57 | return monitor 58 | } 59 | 60 | // GetMetric used to get metric object by metric_name. 61 | func (m *Monitor) GetMetric(name string) *Metric { 62 | if metric, ok := m.metrics[name]; ok { 63 | return metric 64 | } 65 | return &Metric{} 66 | } 67 | 68 | // SetMetricPath set metricPath property. metricPath is used for Prometheus 69 | // to get gin server monitoring data. 70 | func (m *Monitor) SetMetricPath(path string) { 71 | m.metricPath = path 72 | } 73 | 74 | // SetExcludePaths set exclude paths which should not be reported (e.g. /ping /healthz...) 75 | func (m *Monitor) SetExcludePaths(paths []string) { 76 | m.excludePaths = paths 77 | } 78 | 79 | // SetSlowTime set slowTime property. slowTime is used to determine whether 80 | // the request is slow. For "gin_slow_request_total" metric. 81 | func (m *Monitor) SetSlowTime(slowTime int32) { 82 | m.slowTime = slowTime 83 | } 84 | 85 | // SetDuration set reqDuration property. reqDuration is used to ginRequestDuration 86 | // metric buckets. 87 | func (m *Monitor) SetDuration(duration []float64) { 88 | m.reqDuration = duration 89 | } 90 | 91 | func (m *Monitor) SetMetricPrefix(prefix string) { 92 | metricRequestTotal = prefix + metricRequestTotal 93 | metricRequestUVTotal = prefix + metricRequestUVTotal 94 | metricURIRequestTotal = prefix + metricURIRequestTotal 95 | metricRequestBody = prefix + metricRequestBody 96 | metricResponseBody = prefix + metricResponseBody 97 | metricRequestDuration = prefix + metricRequestDuration 98 | metricSlowRequest = prefix + metricSlowRequest 99 | } 100 | 101 | func (m *Monitor) SetMetricSuffix(suffix string) { 102 | metricRequestTotal += suffix 103 | metricRequestUVTotal += suffix 104 | metricURIRequestTotal += suffix 105 | metricRequestBody += suffix 106 | metricResponseBody += suffix 107 | metricRequestDuration += suffix 108 | metricSlowRequest += suffix 109 | } 110 | 111 | // AddMetric add custom monitor metric. 112 | func (m *Monitor) AddMetric(metric *Metric) error { 113 | if _, ok := m.metrics[metric.Name]; ok { 114 | return errors.Errorf("metric '%s' is existed", metric.Name) 115 | } 116 | 117 | if metric.Name == "" { 118 | return errors.Errorf("metric name cannot be empty.") 119 | } 120 | if f, ok := promTypeHandler[metric.Type]; ok { 121 | if err := f(metric); err == nil { 122 | prometheus.MustRegister(metric.vec) 123 | m.metrics[metric.Name] = metric 124 | return nil 125 | } 126 | } 127 | return errors.Errorf("metric type '%d' not existed.", metric.Type) 128 | } 129 | 130 | func counterHandler(metric *Metric) error { 131 | metric.vec = prometheus.NewCounterVec( 132 | prometheus.CounterOpts{Name: metric.Name, Help: metric.Description}, 133 | metric.Labels, 134 | ) 135 | return nil 136 | } 137 | 138 | func gaugeHandler(metric *Metric) error { 139 | metric.vec = prometheus.NewGaugeVec( 140 | prometheus.GaugeOpts{Name: metric.Name, Help: metric.Description}, 141 | metric.Labels, 142 | ) 143 | return nil 144 | } 145 | 146 | func histogramHandler(metric *Metric) error { 147 | if len(metric.Buckets) == 0 { 148 | return errors.Errorf("metric '%s' is histogram type, cannot lose bucket param.", metric.Name) 149 | } 150 | metric.vec = prometheus.NewHistogramVec( 151 | prometheus.HistogramOpts{Name: metric.Name, Help: metric.Description, Buckets: metric.Buckets}, 152 | metric.Labels, 153 | ) 154 | return nil 155 | } 156 | 157 | func summaryHandler(metric *Metric) error { 158 | if len(metric.Objectives) == 0 { 159 | return errors.Errorf("metric '%s' is summary type, cannot lose objectives param.", metric.Name) 160 | } 161 | metric.vec = prometheus.NewSummaryVec( 162 | prometheus.SummaryOpts{Name: metric.Name, Help: metric.Description, Objectives: metric.Objectives}, 163 | metric.Labels, 164 | ) 165 | return nil 166 | } 167 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/penglongli/gin-metrics 2 | 3 | go 1.22 4 | 5 | require ( 6 | github.com/bits-and-blooms/bitset v1.2.0 7 | github.com/gin-gonic/gin v1.9.1 8 | github.com/pkg/errors v0.9.1 9 | github.com/prometheus/client_golang v1.12.0 10 | ) 11 | 12 | require ( 13 | github.com/beorn7/perks v1.0.1 // indirect 14 | github.com/bytedance/sonic v1.9.1 // indirect 15 | github.com/cespare/xxhash/v2 v2.1.2 // indirect 16 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect 17 | github.com/gabriel-vasile/mimetype v1.4.2 // indirect 18 | github.com/gin-contrib/sse v0.1.0 // indirect 19 | github.com/go-playground/locales v0.14.1 // indirect 20 | github.com/go-playground/universal-translator v0.18.1 // indirect 21 | github.com/go-playground/validator/v10 v10.14.0 // indirect 22 | github.com/goccy/go-json v0.10.2 // indirect 23 | github.com/golang/protobuf v1.5.2 // indirect 24 | github.com/json-iterator/go v1.1.12 // indirect 25 | github.com/klauspost/cpuid/v2 v2.2.4 // indirect 26 | github.com/leodido/go-urn v1.2.4 // indirect 27 | github.com/mattn/go-isatty v0.0.19 // indirect 28 | github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect 29 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 30 | github.com/modern-go/reflect2 v1.0.2 // indirect 31 | github.com/pelletier/go-toml/v2 v2.0.8 // indirect 32 | github.com/prometheus/client_model v0.2.0 // indirect 33 | github.com/prometheus/common v0.32.1 // indirect 34 | github.com/prometheus/procfs v0.7.3 // indirect 35 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect 36 | github.com/ugorji/go/codec v1.2.11 // indirect 37 | golang.org/x/arch v0.3.0 // indirect 38 | golang.org/x/crypto v0.28.0 // indirect 39 | golang.org/x/net v0.30.0 // indirect 40 | golang.org/x/sys v0.26.0 // indirect 41 | golang.org/x/text v0.19.0 // indirect 42 | google.golang.org/protobuf v1.30.0 // indirect 43 | gopkg.in/yaml.v3 v3.0.1 // indirect 44 | ) 45 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 4 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 5 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 6 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 7 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= 8 | cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= 9 | cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= 10 | cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= 11 | cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= 12 | cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= 13 | cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= 14 | cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= 15 | cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= 16 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 17 | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= 18 | cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= 19 | cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= 20 | cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= 21 | cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= 22 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 23 | cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= 24 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 25 | cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= 26 | cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= 27 | cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= 28 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 29 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 30 | cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= 31 | cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= 32 | cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= 33 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 34 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 35 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 36 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 37 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 38 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 39 | github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 40 | github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= 41 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 42 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 43 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= 44 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 45 | github.com/bits-and-blooms/bitset v1.2.0 h1:Kn4yilvwNtMACtf1eYDlG8H77R07mZSPbMjLyS07ChA= 46 | github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= 47 | github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= 48 | github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= 49 | github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= 50 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 51 | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 52 | github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= 53 | github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 54 | github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= 55 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= 56 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= 57 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 58 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 59 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 60 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 61 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 62 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 63 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 64 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 65 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 66 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 67 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 68 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 69 | github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= 70 | github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= 71 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= 72 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 73 | github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= 74 | github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= 75 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 76 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 77 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 78 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 79 | github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 80 | github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= 81 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 82 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 83 | github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= 84 | github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= 85 | github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= 86 | github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= 87 | github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= 88 | github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= 89 | github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= 90 | github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= 91 | github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= 92 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 93 | github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= 94 | github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= 95 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 96 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 97 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 98 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 99 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 100 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 101 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 102 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 103 | github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 104 | github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 105 | github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 106 | github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= 107 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 108 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 109 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 110 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 111 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 112 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 113 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 114 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 115 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 116 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 117 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 118 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 119 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 120 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 121 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 122 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 123 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 124 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 125 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 126 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 127 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 128 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 129 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 130 | github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 131 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 132 | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 133 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 134 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 135 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 136 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 137 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 138 | github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 139 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 140 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 141 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 142 | github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 143 | github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 144 | github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 145 | github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 146 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 147 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 148 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 149 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 150 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 151 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 152 | github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= 153 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 154 | github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 155 | github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 156 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 157 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 158 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 159 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 160 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 161 | github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= 162 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 163 | github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= 164 | github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= 165 | github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= 166 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 167 | github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 168 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 169 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 170 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 171 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 172 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 173 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 174 | github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= 175 | github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= 176 | github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= 177 | github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 178 | github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= 179 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 180 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 181 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 182 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 183 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 184 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 185 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 186 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 187 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 188 | github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 189 | github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= 190 | github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= 191 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 192 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 193 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 194 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 195 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 196 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 197 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 198 | github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= 199 | github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= 200 | github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= 201 | github.com/prometheus/client_golang v1.12.0 h1:C+UIj/QWtmqY13Arb8kwMt5j34/0Z2iKamrJ+ryC0Gg= 202 | github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= 203 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 204 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 205 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 206 | github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= 207 | github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 208 | github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 209 | github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= 210 | github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= 211 | github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= 212 | github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= 213 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 214 | github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 215 | github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= 216 | github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= 217 | github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= 218 | github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= 219 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 220 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 221 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 222 | github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= 223 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 224 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 225 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 226 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 227 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 228 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 229 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 230 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 231 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 232 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 233 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 234 | github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 235 | github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= 236 | github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 237 | github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= 238 | github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= 239 | github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= 240 | github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= 241 | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 242 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 243 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 244 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 245 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 246 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 247 | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 248 | go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 249 | golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= 250 | golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= 251 | golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= 252 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 253 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 254 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 255 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 256 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 257 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 258 | golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= 259 | golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= 260 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 261 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 262 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 263 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 264 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 265 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 266 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 267 | golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 268 | golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= 269 | golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= 270 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 271 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 272 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 273 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 274 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 275 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 276 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 277 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 278 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 279 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 280 | golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 281 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 282 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 283 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 284 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 285 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 286 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 287 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 288 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 289 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 290 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 291 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 292 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 293 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 294 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 295 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 296 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 297 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 298 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 299 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 300 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 301 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 302 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 303 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 304 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 305 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 306 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 307 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 308 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 309 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 310 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 311 | golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 312 | golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 313 | golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 314 | golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 315 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 316 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 317 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 318 | golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 319 | golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= 320 | golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= 321 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 322 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 323 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 324 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 325 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 326 | golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 327 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 328 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 329 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 330 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 331 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 332 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 333 | golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 334 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 335 | golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 336 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 337 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 338 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 339 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 340 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 341 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 342 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 343 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 344 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 345 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 346 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 347 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 348 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 349 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 350 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 351 | golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 352 | golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 353 | golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 354 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 355 | golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 356 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 357 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 358 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 359 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 360 | golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 361 | golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 362 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 363 | golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 364 | golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 365 | golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 366 | golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 367 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 368 | golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 369 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 370 | golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 371 | golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 372 | golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 373 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 374 | golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= 375 | golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 376 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 377 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 378 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 379 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 380 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 381 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 382 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 383 | golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= 384 | golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 385 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 386 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 387 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 388 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 389 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 390 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 391 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 392 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 393 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 394 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 395 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 396 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 397 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 398 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 399 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 400 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 401 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 402 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 403 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 404 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 405 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 406 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 407 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 408 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 409 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 410 | golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 411 | golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 412 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 413 | golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 414 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 415 | golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 416 | golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 417 | golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 418 | golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 419 | golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 420 | golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 421 | golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 422 | golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 423 | golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 424 | golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 425 | golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 426 | golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 427 | golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 428 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 429 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 430 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 431 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= 432 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 433 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 434 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 435 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 436 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 437 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 438 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 439 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 440 | google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 441 | google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 442 | google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 443 | google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 444 | google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 445 | google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 446 | google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 447 | google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= 448 | google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= 449 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 450 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 451 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 452 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 453 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 454 | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 455 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 456 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 457 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 458 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 459 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 460 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 461 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 462 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 463 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 464 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 465 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 466 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 467 | google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 468 | google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 469 | google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= 470 | google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 471 | google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 472 | google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 473 | google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 474 | google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 475 | google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 476 | google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 477 | google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 478 | google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= 479 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 480 | google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= 481 | google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 482 | google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 483 | google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 484 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 485 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 486 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 487 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 488 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 489 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 490 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 491 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 492 | google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= 493 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 494 | google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 495 | google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 496 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 497 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 498 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 499 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 500 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 501 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 502 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 503 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 504 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= 505 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 506 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 507 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 508 | google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= 509 | google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 510 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 511 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 512 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 513 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 514 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 515 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 516 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 517 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 518 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 519 | gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 520 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 521 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 522 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 523 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 524 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 525 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 526 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 527 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 528 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 529 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 530 | honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 531 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 532 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 533 | rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= 534 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= 535 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= 536 | -------------------------------------------------------------------------------- /grafana/README.md: -------------------------------------------------------------------------------- 1 | ## Manual 2 | 3 | If you want to use this grafana.json. 4 | -------------------------------------------------------------------------------- /grafana/grafana.json: -------------------------------------------------------------------------------- 1 | { 2 | "annotations": { 3 | "list": [ 4 | { 5 | "builtIn": 1, 6 | "datasource": "-- Grafana --", 7 | "enable": true, 8 | "hide": true, 9 | "iconColor": "rgba(0, 211, 255, 1)", 10 | "name": "Annotations & Alerts", 11 | "type": "dashboard" 12 | } 13 | ] 14 | }, 15 | "editable": true, 16 | "gnetId": null, 17 | "graphTooltip": 0, 18 | "id": 1, 19 | "links": [], 20 | "panels": [ 21 | { 22 | "datasource": null, 23 | "description": "Application request rate every 5 minutes.", 24 | "fieldConfig": { 25 | "defaults": { 26 | "custom": {}, 27 | "mappings": [], 28 | "thresholds": { 29 | "mode": "absolute", 30 | "steps": [ 31 | { 32 | "color": "green", 33 | "value": null 34 | }, 35 | { 36 | "color": "red", 37 | "value": 80 38 | } 39 | ] 40 | } 41 | }, 42 | "overrides": [] 43 | }, 44 | "gridPos": { 45 | "h": 6, 46 | "w": 8, 47 | "x": 0, 48 | "y": 0 49 | }, 50 | "id": 4, 51 | "options": { 52 | "reduceOptions": { 53 | "calcs": [ 54 | "mean" 55 | ], 56 | "fields": "", 57 | "values": false 58 | }, 59 | "showThresholdLabels": false, 60 | "showThresholdMarkers": true 61 | }, 62 | "pluginVersion": "7.2.0", 63 | "targets": [ 64 | { 65 | "expr": "rate(gin_request_total[5m])", 66 | "interval": "", 67 | "legendFormat": "", 68 | "refId": "A" 69 | } 70 | ], 71 | "timeFrom": null, 72 | "timeShift": null, 73 | "title": "PV Rate", 74 | "type": "gauge" 75 | }, 76 | { 77 | "aliasColors": {}, 78 | "bars": false, 79 | "dashLength": 10, 80 | "dashes": false, 81 | "datasource": "Prometheus", 82 | "description": "", 83 | "fieldConfig": { 84 | "defaults": { 85 | "custom": {} 86 | }, 87 | "overrides": [] 88 | }, 89 | "fill": 1, 90 | "fillGradient": 0, 91 | "gridPos": { 92 | "h": 6, 93 | "w": 8, 94 | "x": 8, 95 | "y": 0 96 | }, 97 | "hiddenSeries": false, 98 | "id": 2, 99 | "legend": { 100 | "avg": false, 101 | "current": false, 102 | "max": false, 103 | "min": false, 104 | "show": true, 105 | "total": false, 106 | "values": false 107 | }, 108 | "lines": true, 109 | "linewidth": 1, 110 | "nullPointMode": "null", 111 | "options": { 112 | "alertThreshold": true 113 | }, 114 | "percentage": false, 115 | "pluginVersion": "7.2.0", 116 | "pointradius": 2, 117 | "points": false, 118 | "renderer": "flot", 119 | "seriesOverrides": [], 120 | "spaceLength": 10, 121 | "stack": false, 122 | "steppedLine": false, 123 | "targets": [ 124 | { 125 | "expr": "gin_request_total", 126 | "format": "time_series", 127 | "instant": false, 128 | "interval": "", 129 | "legendFormat": "{{instance}}", 130 | "refId": "A" 131 | } 132 | ], 133 | "thresholds": [], 134 | "timeFrom": null, 135 | "timeRegions": [], 136 | "timeShift": null, 137 | "title": "PV", 138 | "tooltip": { 139 | "shared": true, 140 | "sort": 0, 141 | "value_type": "individual" 142 | }, 143 | "type": "graph", 144 | "xaxis": { 145 | "buckets": null, 146 | "mode": "time", 147 | "name": null, 148 | "show": true, 149 | "values": [] 150 | }, 151 | "yaxes": [ 152 | { 153 | "format": "short", 154 | "label": null, 155 | "logBase": 1, 156 | "max": null, 157 | "min": null, 158 | "show": true 159 | }, 160 | { 161 | "format": "short", 162 | "label": null, 163 | "logBase": 1, 164 | "max": null, 165 | "min": null, 166 | "show": true 167 | } 168 | ], 169 | "yaxis": { 170 | "align": false, 171 | "alignLevel": null 172 | } 173 | }, 174 | { 175 | "aliasColors": {}, 176 | "bars": false, 177 | "dashLength": 10, 178 | "dashes": false, 179 | "datasource": null, 180 | "fieldConfig": { 181 | "defaults": { 182 | "custom": {} 183 | }, 184 | "overrides": [] 185 | }, 186 | "fill": 1, 187 | "fillGradient": 0, 188 | "gridPos": { 189 | "h": 6, 190 | "w": 8, 191 | "x": 16, 192 | "y": 0 193 | }, 194 | "hiddenSeries": false, 195 | "id": 6, 196 | "legend": { 197 | "avg": false, 198 | "current": false, 199 | "max": false, 200 | "min": false, 201 | "show": true, 202 | "total": false, 203 | "values": false 204 | }, 205 | "lines": true, 206 | "linewidth": 1, 207 | "nullPointMode": "null", 208 | "options": { 209 | "alertThreshold": true 210 | }, 211 | "percentage": false, 212 | "pluginVersion": "7.2.0", 213 | "pointradius": 2, 214 | "points": false, 215 | "renderer": "flot", 216 | "seriesOverrides": [], 217 | "spaceLength": 10, 218 | "stack": false, 219 | "steppedLine": false, 220 | "targets": [ 221 | { 222 | "expr": "gin_request_uv_total", 223 | "interval": "", 224 | "legendFormat": "{{instance}}", 225 | "refId": "A" 226 | } 227 | ], 228 | "thresholds": [], 229 | "timeFrom": null, 230 | "timeRegions": [], 231 | "timeShift": null, 232 | "title": "UV", 233 | "tooltip": { 234 | "shared": true, 235 | "sort": 0, 236 | "value_type": "individual" 237 | }, 238 | "type": "graph", 239 | "xaxis": { 240 | "buckets": null, 241 | "mode": "time", 242 | "name": null, 243 | "show": true, 244 | "values": [] 245 | }, 246 | "yaxes": [ 247 | { 248 | "format": "short", 249 | "label": null, 250 | "logBase": 1, 251 | "max": null, 252 | "min": null, 253 | "show": true 254 | }, 255 | { 256 | "format": "short", 257 | "label": null, 258 | "logBase": 1, 259 | "max": null, 260 | "min": null, 261 | "show": true 262 | } 263 | ], 264 | "yaxis": { 265 | "align": false, 266 | "alignLevel": null 267 | } 268 | }, 269 | { 270 | "aliasColors": {}, 271 | "bars": false, 272 | "dashLength": 10, 273 | "dashes": false, 274 | "datasource": null, 275 | "fieldConfig": { 276 | "defaults": { 277 | "custom": {}, 278 | "unit": "Bps" 279 | }, 280 | "overrides": [] 281 | }, 282 | "fill": 1, 283 | "fillGradient": 0, 284 | "gridPos": { 285 | "h": 8, 286 | "w": 15, 287 | "x": 0, 288 | "y": 6 289 | }, 290 | "hiddenSeries": false, 291 | "id": 12, 292 | "legend": { 293 | "avg": false, 294 | "current": false, 295 | "max": false, 296 | "min": false, 297 | "show": true, 298 | "total": false, 299 | "values": false 300 | }, 301 | "lines": true, 302 | "linewidth": 1, 303 | "nullPointMode": "null", 304 | "options": { 305 | "alertThreshold": true 306 | }, 307 | "percentage": false, 308 | "pluginVersion": "7.2.0", 309 | "pointradius": 2, 310 | "points": false, 311 | "renderer": "flot", 312 | "seriesOverrides": [], 313 | "spaceLength": 10, 314 | "stack": false, 315 | "steppedLine": false, 316 | "targets": [ 317 | { 318 | "expr": "rate(gin_request_body_total[5m])", 319 | "interval": "", 320 | "legendFormat": "{{instance}}-in", 321 | "refId": "A" 322 | }, 323 | { 324 | "expr": "rate(gin_response_body_total[5m])", 325 | "interval": "", 326 | "legendFormat": "{{instance}}-out", 327 | "refId": "B" 328 | } 329 | ], 330 | "thresholds": [], 331 | "timeFrom": null, 332 | "timeRegions": [], 333 | "timeShift": null, 334 | "title": "Traffic In-Out", 335 | "tooltip": { 336 | "shared": true, 337 | "sort": 0, 338 | "value_type": "individual" 339 | }, 340 | "type": "graph", 341 | "xaxis": { 342 | "buckets": null, 343 | "mode": "time", 344 | "name": null, 345 | "show": true, 346 | "values": [] 347 | }, 348 | "yaxes": [ 349 | { 350 | "format": "Bps", 351 | "label": null, 352 | "logBase": 1, 353 | "max": null, 354 | "min": null, 355 | "show": true 356 | }, 357 | { 358 | "format": "bytes", 359 | "label": null, 360 | "logBase": 1, 361 | "max": null, 362 | "min": null, 363 | "show": true 364 | } 365 | ], 366 | "yaxis": { 367 | "align": false, 368 | "alignLevel": null 369 | } 370 | }, 371 | { 372 | "cacheTimeout": null, 373 | "datasource": null, 374 | "fieldConfig": { 375 | "defaults": { 376 | "custom": { 377 | "align": null, 378 | "filterable": false 379 | }, 380 | "mappings": [], 381 | "thresholds": { 382 | "mode": "absolute", 383 | "steps": [ 384 | { 385 | "color": "blue", 386 | "value": null 387 | }, 388 | { 389 | "color": "green", 390 | "value": 80 391 | } 392 | ] 393 | }, 394 | "unit": "none" 395 | }, 396 | "overrides": [] 397 | }, 398 | "gridPos": { 399 | "h": 8, 400 | "w": 9, 401 | "x": 15, 402 | "y": 6 403 | }, 404 | "id": 10, 405 | "interval": null, 406 | "links": [], 407 | "options": { 408 | "displayMode": "basic", 409 | "orientation": "horizontal", 410 | "reduceOptions": { 411 | "calcs": [ 412 | "last" 413 | ], 414 | "fields": "", 415 | "values": false 416 | }, 417 | "showUnfilled": true 418 | }, 419 | "pluginVersion": "7.2.0", 420 | "targets": [ 421 | { 422 | "expr": "sum by(uri, instance) (gin_uri_request_total)", 423 | "format": "time_series", 424 | "instant": false, 425 | "interval": "", 426 | "intervalFactor": 1, 427 | "legendFormat": "{{instance}}-{{uri}}", 428 | "refId": "A" 429 | } 430 | ], 431 | "timeFrom": null, 432 | "timeShift": null, 433 | "title": "URI Request", 434 | "type": "bargauge" 435 | }, 436 | { 437 | "aliasColors": {}, 438 | "breakPoint": "50%", 439 | "cacheTimeout": null, 440 | "combine": { 441 | "label": "Others", 442 | "threshold": 0 443 | }, 444 | "datasource": null, 445 | "decimals": null, 446 | "fieldConfig": { 447 | "defaults": { 448 | "custom": { 449 | "align": null, 450 | "filterable": false 451 | }, 452 | "mappings": [], 453 | "thresholds": { 454 | "mode": "absolute", 455 | "steps": [ 456 | { 457 | "color": "blue", 458 | "value": null 459 | }, 460 | { 461 | "color": "green", 462 | "value": 80 463 | } 464 | ] 465 | }, 466 | "unit": "none" 467 | }, 468 | "overrides": [] 469 | }, 470 | "fontSize": "80%", 471 | "format": "none", 472 | "gridPos": { 473 | "h": 7, 474 | "w": 7, 475 | "x": 0, 476 | "y": 14 477 | }, 478 | "id": 13, 479 | "interval": null, 480 | "legend": { 481 | "show": true, 482 | "values": true 483 | }, 484 | "legendType": "Right side", 485 | "links": [], 486 | "nullPointMode": "connected", 487 | "pieType": "pie", 488 | "pluginVersion": "7.2.0", 489 | "strokeWidth": 1, 490 | "targets": [ 491 | { 492 | "expr": "sum by(method, instance) (gin_uri_request_total)", 493 | "format": "time_series", 494 | "instant": false, 495 | "interval": "", 496 | "intervalFactor": 1, 497 | "legendFormat": "{{instance}}-{{method}}", 498 | "refId": "A" 499 | } 500 | ], 501 | "timeFrom": null, 502 | "timeShift": null, 503 | "title": "Method", 504 | "type": "piechart", 505 | "valueName": "current" 506 | }, 507 | { 508 | "aliasColors": {}, 509 | "bars": false, 510 | "dashLength": 10, 511 | "dashes": false, 512 | "datasource": null, 513 | "fieldConfig": { 514 | "defaults": { 515 | "custom": {}, 516 | "unit": "s" 517 | }, 518 | "overrides": [] 519 | }, 520 | "fill": 1, 521 | "fillGradient": 0, 522 | "gridPos": { 523 | "h": 7, 524 | "w": 17, 525 | "x": 7, 526 | "y": 14 527 | }, 528 | "hiddenSeries": false, 529 | "id": 16, 530 | "legend": { 531 | "avg": false, 532 | "current": false, 533 | "max": false, 534 | "min": false, 535 | "show": true, 536 | "total": false, 537 | "values": false 538 | }, 539 | "lines": true, 540 | "linewidth": 1, 541 | "nullPointMode": "null", 542 | "options": { 543 | "alertThreshold": true 544 | }, 545 | "percentage": false, 546 | "pluginVersion": "7.2.0", 547 | "pointradius": 2, 548 | "points": false, 549 | "renderer": "flot", 550 | "seriesOverrides": [], 551 | "spaceLength": 10, 552 | "stack": false, 553 | "steppedLine": false, 554 | "targets": [ 555 | { 556 | "expr": "histogram_quantile(0.95, sum (rate(gin_request_duration_bucket[5m])) by (le, instance))", 557 | "interval": "", 558 | "legendFormat": "p95", 559 | "refId": "A" 560 | }, 561 | { 562 | "expr": "histogram_quantile(0.99, sum (rate(gin_request_duration_bucket[5m])) by (le, instance))", 563 | "interval": "", 564 | "legendFormat": "p99", 565 | "refId": "B" 566 | }, 567 | { 568 | "expr": "sum (gin_request_duration_sum) / sum(gin_request_duration_count)", 569 | "interval": "", 570 | "legendFormat": "avg", 571 | "refId": "C" 572 | } 573 | ], 574 | "thresholds": [], 575 | "timeFrom": null, 576 | "timeRegions": [], 577 | "timeShift": null, 578 | "title": "Request Duration", 579 | "tooltip": { 580 | "shared": true, 581 | "sort": 0, 582 | "value_type": "individual" 583 | }, 584 | "type": "graph", 585 | "xaxis": { 586 | "buckets": null, 587 | "mode": "time", 588 | "name": null, 589 | "show": true, 590 | "values": [] 591 | }, 592 | "yaxes": [ 593 | { 594 | "format": "s", 595 | "label": null, 596 | "logBase": 1, 597 | "max": null, 598 | "min": null, 599 | "show": true 600 | }, 601 | { 602 | "format": "bytes", 603 | "label": null, 604 | "logBase": 1, 605 | "max": null, 606 | "min": null, 607 | "show": true 608 | } 609 | ], 610 | "yaxis": { 611 | "align": false, 612 | "alignLevel": null 613 | } 614 | }, 615 | { 616 | "aliasColors": {}, 617 | "breakPoint": "50%", 618 | "cacheTimeout": null, 619 | "combine": { 620 | "label": "Others", 621 | "threshold": 0 622 | }, 623 | "datasource": null, 624 | "decimals": null, 625 | "description": "", 626 | "fieldConfig": { 627 | "defaults": { 628 | "custom": { 629 | "align": null, 630 | "filterable": false 631 | }, 632 | "mappings": [], 633 | "thresholds": { 634 | "mode": "absolute", 635 | "steps": [ 636 | { 637 | "color": "blue", 638 | "value": null 639 | }, 640 | { 641 | "color": "green", 642 | "value": 80 643 | } 644 | ] 645 | }, 646 | "unit": "none" 647 | }, 648 | "overrides": [] 649 | }, 650 | "fontSize": "80%", 651 | "format": "none", 652 | "gridPos": { 653 | "h": 5, 654 | "w": 7, 655 | "x": 0, 656 | "y": 21 657 | }, 658 | "id": 14, 659 | "interval": null, 660 | "legend": { 661 | "show": true, 662 | "values": true 663 | }, 664 | "legendType": "Right side", 665 | "links": [], 666 | "nullPointMode": "connected", 667 | "pieType": "pie", 668 | "pluginVersion": "7.2.0", 669 | "strokeWidth": 1, 670 | "targets": [ 671 | { 672 | "expr": "sum by(code, instance) (gin_uri_request_total)", 673 | "format": "time_series", 674 | "instant": false, 675 | "interval": "", 676 | "intervalFactor": 1, 677 | "legendFormat": "{{instance}}-{{code}}", 678 | "refId": "A" 679 | } 680 | ], 681 | "timeFrom": null, 682 | "timeShift": null, 683 | "title": "Code", 684 | "type": "piechart", 685 | "valueName": "current" 686 | }, 687 | { 688 | "cacheTimeout": null, 689 | "datasource": null, 690 | "fieldConfig": { 691 | "defaults": { 692 | "custom": { 693 | "align": null, 694 | "filterable": false 695 | }, 696 | "mappings": [], 697 | "thresholds": { 698 | "mode": "absolute", 699 | "steps": [ 700 | { 701 | "color": "blue", 702 | "value": null 703 | }, 704 | { 705 | "color": "green", 706 | "value": 80 707 | } 708 | ] 709 | }, 710 | "unit": "none" 711 | }, 712 | "overrides": [] 713 | }, 714 | "gridPos": { 715 | "h": 5, 716 | "w": 17, 717 | "x": 7, 718 | "y": 21 719 | }, 720 | "id": 19, 721 | "interval": null, 722 | "links": [], 723 | "options": { 724 | "displayMode": "basic", 725 | "orientation": "horizontal", 726 | "reduceOptions": { 727 | "calcs": [ 728 | "last" 729 | ], 730 | "fields": "", 731 | "values": false 732 | }, 733 | "showUnfilled": true 734 | }, 735 | "pluginVersion": "7.2.0", 736 | "targets": [ 737 | { 738 | "expr": "sum by(uri, instance) (gin_slow_request_total)", 739 | "format": "time_series", 740 | "instant": false, 741 | "interval": "", 742 | "intervalFactor": 1, 743 | "legendFormat": "{{instance}}-{{uri}}", 744 | "refId": "A" 745 | } 746 | ], 747 | "timeFrom": null, 748 | "timeShift": null, 749 | "title": "Slow Request(default 5s)", 750 | "type": "bargauge" 751 | } 752 | ], 753 | "refresh": "5s", 754 | "schemaVersion": 26, 755 | "style": "dark", 756 | "tags": [], 757 | "templating": { 758 | "list": [] 759 | }, 760 | "time": { 761 | "from": "now-1h", 762 | "to": "now" 763 | }, 764 | "timepicker": {}, 765 | "timezone": "", 766 | "title": "Gin Application Metrics", 767 | "uid": "FDB061FMz", 768 | "version": 11 769 | } 770 | -------------------------------------------------------------------------------- /grafana/grafana.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penglongli/gin-metrics/3cd462047cdcf32dca1c41a09bfb511f54c4c798/grafana/grafana.png --------------------------------------------------------------------------------