package internal import ( "net/http" "net/url" "strconv" "time" "github.com/zeromicro/go-zero/core/metric" "github.com/zeromicro/go-zero/core/timex" ) const clientNamespace = "httpc_client" var ( MetricClientReqDur = metric.NewHistogramVec(&metric.HistogramVecOpts{ Namespace: clientNamespace, Subsystem: "requests", Name: "duration_ms", Help: "http client requests duration(ms).", Labels: []string{"name", "method", "url"}, Buckets: []float64{0.25, 0.5, 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000, 2000, 5000, 10000, 15000}, }) MetricClientReqCodeTotal = metric.NewCounterVec(&metric.CounterVecOpts{ Namespace: clientNamespace, Subsystem: "requests", Name: "code_total", Help: "http client requests code count.", Labels: []string{"name", "method", "url", "code"}, }) ) type MetricsURLRewriter func(u url.URL) string func MetricsInterceptor(name string, pr MetricsURLRewriter) Interceptor { return func(r *http.Request) (*http.Request, ResponseHandler) { startTime := timex.Now() return r, func(resp *http.Response, err error) { var code int var path string // error or resp is nil, set code=500 if err != nil || resp == nil { code = http.StatusInternalServerError } else { code = resp.StatusCode } u := cleanURL(*r.URL) method := r.Method if pr != nil { path = pr(u) } else { path = u.String() } MetricClientReqDur.ObserveFloat(float64(timex.Since(startTime))/float64(time.Millisecond), name, method, path) MetricClientReqCodeTotal.Inc(name, method, path, strconv.Itoa(code)) } } } func cleanURL(r url.URL) url.URL { r.RawQuery = "" r.RawFragment = "" r.User = nil return r }