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  }