(w http.ResponseWriter, r *http.Request)
| 312 | } |
| 313 | |
| 314 | func (h *metricsInstrumentedRoute) ServeHTTP(w http.ResponseWriter, r *http.Request) error { |
| 315 | server := serverNameFromContext(r.Context()) |
| 316 | labels := prometheus.Labels{"server": server, "handler": h.handler} |
| 317 | method := caddymetrics.SanitizeMethod(r.Method) |
| 318 | // the "code" value is set later, but initialized here to eliminate the possibility |
| 319 | // of a panic |
| 320 | statusLabels := prometheus.Labels{"server": server, "handler": h.handler, "method": method, "code": ""} |
| 321 | |
| 322 | // Determine if this is an HTTPS request |
| 323 | isHTTPS := r.TLS != nil |
| 324 | |
| 325 | if h.metrics.PerHost { |
| 326 | // Apply cardinality protection for host metrics |
| 327 | if h.metrics.shouldAllowHostMetrics(r.Host, isHTTPS) { |
| 328 | labels["host"] = strings.ToLower(r.Host) |
| 329 | statusLabels["host"] = strings.ToLower(r.Host) |
| 330 | } else { |
| 331 | // Use a catch-all label for unallowed hosts to prevent cardinality explosion |
| 332 | labels["host"] = "_other" |
| 333 | statusLabels["host"] = "_other" |
| 334 | } |
| 335 | } |
| 336 | |
| 337 | inFlight := h.metrics.httpMetrics.requestInFlight.With(labels) |
| 338 | inFlight.Inc() |
| 339 | defer inFlight.Dec() |
| 340 | |
| 341 | start := time.Now() |
| 342 | |
| 343 | // This is a _bit_ of a hack - it depends on the ShouldBufferFunc always |
| 344 | // being called when the headers are written. |
| 345 | // Effectively the same behaviour as promhttp.InstrumentHandlerTimeToWriteHeader. |
| 346 | writeHeaderRecorder := ShouldBufferFunc(func(status int, header http.Header) bool { |
| 347 | statusLabels["code"] = caddymetrics.SanitizeCode(status) |
| 348 | ttfb := time.Since(start).Seconds() |
| 349 | h.metrics.httpMetrics.responseDuration.With(statusLabels).Observe(ttfb) |
| 350 | return false |
| 351 | }) |
| 352 | wrec := NewResponseRecorder(w, nil, writeHeaderRecorder) |
| 353 | err := h.next.ServeHTTP(wrec, r) |
| 354 | dur := time.Since(start).Seconds() |
| 355 | h.metrics.httpMetrics.requestCount.With(labels).Inc() |
| 356 | |
| 357 | observeRequest := func(status int) { |
| 358 | // If the code hasn't been set yet, and we didn't encounter an error, we're |
| 359 | // probably falling through with an empty handler. |
| 360 | if statusLabels["code"] == "" { |
| 361 | // we still sanitize it, even though it's likely to be 0. A 200 is |
| 362 | // returned on fallthrough so we want to reflect that. |
| 363 | statusLabels["code"] = caddymetrics.SanitizeCode(status) |
| 364 | } |
| 365 | |
| 366 | h.metrics.httpMetrics.requestDuration.With(statusLabels).Observe(dur) |
| 367 | h.metrics.httpMetrics.requestSize.With(statusLabels).Observe(float64(computeApproximateRequestSize(r))) |
| 368 | h.metrics.httpMetrics.responseSize.With(statusLabels).Observe(float64(wrec.Size())) |
| 369 | } |
| 370 | |
| 371 | if err != nil { |
nothing calls this directly
no test coverage detected