github.com/gogf/gf/v2@v2.7.4/net/ghttp/ghttp_server_metric.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/gogf/gf. 6 7 package ghttp 8 9 import ( 10 "net" 11 "net/http" 12 13 "github.com/gogf/gf/v2" 14 "github.com/gogf/gf/v2/errors/gerror" 15 "github.com/gogf/gf/v2/os/gmetric" 16 "github.com/gogf/gf/v2/text/gstr" 17 ) 18 19 type localMetricManager struct { 20 HttpServerRequestActive gmetric.UpDownCounter 21 HttpServerRequestTotal gmetric.Counter 22 HttpServerRequestDuration gmetric.Histogram 23 HttpServerRequestDurationTotal gmetric.Counter 24 HttpServerRequestBodySize gmetric.Counter 25 HttpServerResponseBodySize gmetric.Counter 26 } 27 28 const ( 29 metricAttrKeyServerAddress = "server.address" 30 metricAttrKeyServerPort = "server.port" 31 metricAttrKeyHttpRoute = "http.route" 32 metricAttrKeyUrlSchema = "url.schema" 33 metricAttrKeyHttpRequestMethod = "http.request.method" 34 metricAttrKeyErrorCode = "error.code" 35 metricAttrKeyHttpResponseStatusCode = "http.response.status_code" 36 metricAttrKeyNetworkProtocolVersion = "network.protocol.version" 37 ) 38 39 var ( 40 // metricManager for http server metrics. 41 metricManager = newMetricManager() 42 ) 43 44 func newMetricManager() *localMetricManager { 45 meter := gmetric.GetGlobalProvider().Meter(gmetric.MeterOption{ 46 Instrument: instrumentName, 47 InstrumentVersion: gf.VERSION, 48 }) 49 mm := &localMetricManager{ 50 HttpServerRequestDuration: meter.MustHistogram( 51 "http.server.request.duration", 52 gmetric.MetricOption{ 53 Help: "Measures the duration of inbound request.", 54 Unit: "ms", 55 Attributes: gmetric.Attributes{}, 56 Buckets: []float64{ 57 1, 58 5, 59 10, 60 25, 61 50, 62 75, 63 100, 64 250, 65 500, 66 750, 67 1000, 68 2500, 69 5000, 70 7500, 71 10000, 72 30000, 73 60000, 74 }, 75 }, 76 ), 77 HttpServerRequestTotal: meter.MustCounter( 78 "http.server.request.total", 79 gmetric.MetricOption{ 80 Help: "Total processed request number.", 81 Unit: "", 82 Attributes: gmetric.Attributes{}, 83 }, 84 ), 85 HttpServerRequestActive: meter.MustUpDownCounter( 86 "http.server.request.active", 87 gmetric.MetricOption{ 88 Help: "Number of active server requests.", 89 Unit: "", 90 Attributes: gmetric.Attributes{}, 91 }, 92 ), 93 HttpServerRequestDurationTotal: meter.MustCounter( 94 "http.server.request.duration_total", 95 gmetric.MetricOption{ 96 Help: "Total execution duration of request.", 97 Unit: "ms", 98 Attributes: gmetric.Attributes{}, 99 }, 100 ), 101 HttpServerRequestBodySize: meter.MustCounter( 102 "http.server.request.body_size", 103 gmetric.MetricOption{ 104 Help: "Incoming request bytes total.", 105 Unit: "bytes", 106 Attributes: gmetric.Attributes{}, 107 }, 108 ), 109 HttpServerResponseBodySize: meter.MustCounter( 110 "http.server.response.body_size", 111 gmetric.MetricOption{ 112 Help: "Response bytes total.", 113 Unit: "bytes", 114 Attributes: gmetric.Attributes{}, 115 }, 116 ), 117 } 118 return mm 119 } 120 121 func (m *localMetricManager) GetMetricOptionForRequestDurationByMap(attrMap gmetric.AttributeMap) gmetric.Option { 122 return gmetric.Option{ 123 Attributes: attrMap.Pick( 124 metricAttrKeyServerAddress, 125 metricAttrKeyServerPort, 126 ), 127 } 128 } 129 130 func (m *localMetricManager) GetMetricOptionForRequest(r *Request) gmetric.Option { 131 attrMap := m.GetMetricAttributeMap(r) 132 return m.GetMetricOptionForRequestByMap(attrMap) 133 } 134 135 func (m *localMetricManager) GetMetricOptionForRequestByMap(attrMap gmetric.AttributeMap) gmetric.Option { 136 return gmetric.Option{ 137 Attributes: attrMap.Pick( 138 metricAttrKeyServerAddress, 139 metricAttrKeyServerPort, 140 metricAttrKeyHttpRoute, 141 metricAttrKeyUrlSchema, 142 metricAttrKeyHttpRequestMethod, 143 metricAttrKeyNetworkProtocolVersion, 144 ), 145 } 146 } 147 148 func (m *localMetricManager) GetMetricOptionForResponseByMap(attrMap gmetric.AttributeMap) gmetric.Option { 149 return gmetric.Option{ 150 Attributes: attrMap.Pick( 151 metricAttrKeyServerAddress, 152 metricAttrKeyServerPort, 153 metricAttrKeyHttpRoute, 154 metricAttrKeyUrlSchema, 155 metricAttrKeyHttpRequestMethod, 156 metricAttrKeyNetworkProtocolVersion, 157 metricAttrKeyErrorCode, 158 metricAttrKeyHttpResponseStatusCode, 159 ), 160 } 161 } 162 163 func (m *localMetricManager) GetMetricAttributeMap(r *Request) gmetric.AttributeMap { 164 var ( 165 serverAddress string 166 serverPort string 167 httpRoute string 168 protocolVersion string 169 handler = r.GetServeHandler() 170 localAddr = r.Context().Value(http.LocalAddrContextKey) 171 attrMap = make(gmetric.AttributeMap) 172 ) 173 serverAddress, serverPort = gstr.List2(r.Host, ":") 174 if localAddr != nil { 175 _, serverPort = gstr.List2(localAddr.(net.Addr).String(), ":") 176 } 177 if handler != nil && handler.Handler.Router != nil { 178 httpRoute = handler.Handler.Router.Uri 179 } else { 180 httpRoute = r.URL.Path 181 } 182 if array := gstr.Split(r.Proto, "/"); len(array) > 1 { 183 protocolVersion = array[1] 184 } 185 attrMap.Sets(gmetric.AttributeMap{ 186 metricAttrKeyServerAddress: serverAddress, 187 metricAttrKeyServerPort: serverPort, 188 metricAttrKeyHttpRoute: httpRoute, 189 metricAttrKeyUrlSchema: r.GetSchema(), 190 metricAttrKeyHttpRequestMethod: r.Method, 191 metricAttrKeyNetworkProtocolVersion: protocolVersion, 192 }) 193 if r.LeaveTime != nil { 194 var errCode int 195 if err := r.GetError(); err != nil { 196 errCode = gerror.Code(err).Code() 197 } 198 attrMap.Sets(gmetric.AttributeMap{ 199 metricAttrKeyErrorCode: errCode, 200 metricAttrKeyHttpResponseStatusCode: r.Response.Status, 201 }) 202 } 203 return attrMap 204 } 205 206 func (s *Server) handleMetricsBeforeRequest(r *Request) { 207 if !gmetric.IsEnabled() { 208 return 209 } 210 var ( 211 ctx = r.Context() 212 attrMap = metricManager.GetMetricAttributeMap(r) 213 requestOption = metricManager.GetMetricOptionForRequestByMap(attrMap) 214 ) 215 metricManager.HttpServerRequestActive.Inc( 216 ctx, 217 requestOption, 218 ) 219 metricManager.HttpServerRequestBodySize.Add( 220 ctx, 221 float64(r.ContentLength), 222 requestOption, 223 ) 224 } 225 226 func (s *Server) handleMetricsAfterRequestDone(r *Request) { 227 if !gmetric.IsEnabled() { 228 return 229 } 230 var ( 231 ctx = r.Context() 232 attrMap = metricManager.GetMetricAttributeMap(r) 233 durationMilli = float64(r.LeaveTime.Sub(r.EnterTime).Milliseconds()) 234 responseOption = metricManager.GetMetricOptionForResponseByMap(attrMap) 235 histogramOption = metricManager.GetMetricOptionForRequestDurationByMap(attrMap) 236 ) 237 metricManager.HttpServerRequestTotal.Inc(ctx, responseOption) 238 metricManager.HttpServerRequestActive.Dec( 239 ctx, 240 metricManager.GetMetricOptionForRequestByMap(attrMap), 241 ) 242 metricManager.HttpServerResponseBodySize.Add( 243 ctx, 244 float64(r.Response.BytesWritten()), 245 responseOption, 246 ) 247 metricManager.HttpServerRequestDurationTotal.Add( 248 ctx, 249 durationMilli, 250 responseOption, 251 ) 252 metricManager.HttpServerRequestDuration.Record( 253 durationMilli, 254 histogramOption, 255 ) 256 }