github.com/unionj-cloud/go-doudou@v1.3.8-0.20221011095552-0088008e5b31/framework/http/prometheus/middleware.go (about) 1 package prometheus 2 3 // borrow code from https://github.com/TannerGabriel/learning-go/tree/master/advanced-programs/PrometheusHTTPServer 4 // Many thanks to TannerGabriel https://github.com/TannerGabriel 5 // Post link https://gabrieltanner.org/blog/collecting-prometheus-metrics-in-golang written by TannerGabriel 6 import ( 7 "github.com/prometheus/client_golang/prometheus" 8 "github.com/unionj-cloud/go-doudou/framework/buildinfo" 9 "github.com/unionj-cloud/go-doudou/toolkit/constants" 10 "github.com/unionj-cloud/go-doudou/toolkit/load" 11 "github.com/unionj-cloud/go-doudou/toolkit/process" 12 "github.com/unionj-cloud/go-doudou/toolkit/stringutils" 13 logger "github.com/unionj-cloud/go-doudou/toolkit/zlogger" 14 "net/http" 15 "runtime" 16 "strconv" 17 "sync" 18 "time" 19 ) 20 21 type responseWriter struct { 22 http.ResponseWriter 23 statusCode int 24 } 25 26 // NewResponseWriter creates new responseWriter 27 func NewResponseWriter(w http.ResponseWriter) *responseWriter { 28 return &responseWriter{w, http.StatusOK} 29 } 30 31 // WriteHeader set header to code 32 func (rw *responseWriter) WriteHeader(code int) { 33 rw.statusCode = code 34 rw.ResponseWriter.WriteHeader(code) 35 } 36 37 var countRequests = prometheus.NewCounterVec( 38 prometheus.CounterOpts{ 39 Name: "go_doudou_http_request_count", 40 Help: "Number of http requests.", 41 }, 42 []string{"path", "method", "status"}, 43 ) 44 45 var httpDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{ 46 Name: "go_doudou_http_response_time_seconds", 47 Help: "Duration of HTTP requests.", 48 }, []string{"path", "method"}) 49 50 // PrometheusMiddleware returns http HandlerFunc for prometheus matrix 51 func PrometheusMiddleware(next http.Handler) http.Handler { 52 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 53 path := r.URL.Path 54 method := r.Method 55 timer := prometheus.NewTimer(httpDuration.WithLabelValues(path, method)) 56 57 rw := NewResponseWriter(w) 58 next.ServeHTTP(rw, r) 59 60 statusCode := rw.statusCode 61 62 countRequests.WithLabelValues(path, method, strconv.Itoa(statusCode)).Inc() 63 64 timer.ObserveDuration() 65 }) 66 } 67 68 var processPool sync.Pool 69 70 func init() { 71 processPool = sync.Pool{ 72 New: func() interface{} { 73 return process.NewCurrentProcess() 74 }, 75 } 76 prometheus.Register(countRequests) 77 prometheus.Register(httpDuration) 78 buildTime := buildinfo.BuildTime 79 if stringutils.IsNotEmpty(buildinfo.BuildTime) { 80 if t, err := time.Parse(constants.FORMAT15, buildinfo.BuildTime); err == nil { 81 buildTime = t.Local().Format(constants.FORMAT8) 82 } 83 } 84 appInfo := prometheus.NewGauge(prometheus.GaugeOpts{ 85 Name: "go_doudou_app_info", 86 Help: "Information about the go-doudou app", 87 ConstLabels: prometheus.Labels{ 88 "goVer": runtime.Version(), 89 "gddVer": buildinfo.GddVer, 90 "buildUser": buildinfo.BuildUser, 91 "buildTime": buildTime, 92 }, 93 }) 94 appInfo.Set(1) 95 prometheus.Register(appInfo) 96 97 prometheus.Register(prometheus.NewGaugeFunc(prometheus.GaugeOpts{ 98 Name: "go_doudou_gomaxprocs", 99 Help: "The value of gomaxprocs", 100 ConstLabels: nil, 101 }, func() float64 { 102 return float64(runtime.GOMAXPROCS(0)) 103 })) 104 105 prometheus.Register(prometheus.NewGaugeFunc(prometheus.GaugeOpts{ 106 Name: "go_doudou_numcpu", 107 Help: "The value of numcpu", 108 ConstLabels: nil, 109 }, func() float64 { 110 return float64(runtime.NumCPU()) 111 })) 112 113 prometheus.Register(prometheus.NewGaugeFunc(prometheus.GaugeOpts{ 114 Name: "go_doudou_system_cpu_usage", 115 Help: "The \"recent cpu usage\" for the whole system", 116 ConstLabels: nil, 117 }, func() float64 { 118 p := processPool.Get().(*process.Process) 119 defer processPool.Put(p) 120 if p.Err != nil { 121 return 0 122 } 123 ts, err := p.Times1() 124 if err != nil { 125 logger.Error().Err(err).Msg("") 126 return 0 127 } 128 return ts.System 129 })) 130 prometheus.Register(prometheus.NewGaugeFunc(prometheus.GaugeOpts{ 131 Name: "go_doudou_process_cpu_usage", 132 Help: "The \"recent cpu usage\" for the go-doudou process", 133 ConstLabels: nil, 134 }, func() float64 { 135 p := processPool.Get().(*process.Process) 136 defer processPool.Put(p) 137 if p.Err != nil { 138 return 0 139 } 140 ts, err := p.Times1() 141 if err != nil { 142 logger.Error().Err(err).Msg("") 143 return 0 144 } 145 return ts.User 146 })) 147 prometheus.Register(prometheus.NewGaugeFunc(prometheus.GaugeOpts{ 148 Name: "go_doudou_process_start_time_millis", 149 Help: "Start time of the process since unix epoch.", 150 ConstLabels: nil, 151 }, func() float64 { 152 p := processPool.Get().(*process.Process) 153 defer processPool.Put(p) 154 if p.Err != nil { 155 return float64(time.Unix(0, 0).UnixMilli()) 156 } 157 start, err := p.CreateTime() 158 if err != nil { 159 logger.Error().Err(err).Msg("") 160 return float64(time.Unix(0, 0).UnixMilli()) 161 } 162 return float64(start) 163 })) 164 prometheus.Register(prometheus.NewGaugeFunc(prometheus.GaugeOpts{ 165 Name: "go_doudou_process_uptime_millis", 166 Help: "The uptime of the go-doudou process.", 167 ConstLabels: nil, 168 }, func() float64 { 169 p := processPool.Get().(*process.Process) 170 defer processPool.Put(p) 171 if p.Err != nil { 172 return float64(time.Since(time.Unix(0, 0).Local()).Milliseconds()) 173 } 174 start, err := p.CreateTime() 175 if err != nil { 176 logger.Error().Err(err).Msg("") 177 return float64(time.Since(time.Unix(0, 0).Local()).Milliseconds()) 178 } 179 return float64(time.Since(time.UnixMilli(start).Local()).Milliseconds()) 180 })) 181 182 prometheus.Register(prometheus.NewGaugeFunc(prometheus.GaugeOpts{ 183 Name: "go_doudou_system_load_average_1m", 184 Help: "The sum of the number of runnable entities queued to available processors and the number of runnable entities running on the available processors averaged over a period of time", 185 ConstLabels: nil, 186 }, func() float64 { 187 as, err := load.Avg1() 188 if err != nil { 189 logger.Error().Err(err).Msg("") 190 return 0 191 } 192 return as.Load1 193 })) 194 }