From a52c4ffebecad6860a1cbc17325809c8d6a6987f Mon Sep 17 00:00:00 2001 From: Han Kang Date: Thu, 25 May 2023 08:03:32 -0700 Subject: [PATCH] add process start time header to client_golang prometheus Signed-off-by: Han Kang --- prometheus/promhttp/http.go | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/prometheus/promhttp/http.go b/prometheus/promhttp/http.go index a4cc9810b..edc9d0ee3 100644 --- a/prometheus/promhttp/http.go +++ b/prometheus/promhttp/http.go @@ -37,21 +37,28 @@ import ( "fmt" "io" "net/http" + "strconv" "strings" "sync" "time" - "github.com/prometheus/common/expfmt" - "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/common/expfmt" ) const ( - contentTypeHeader = "Content-Type" - contentEncodingHeader = "Content-Encoding" - acceptEncodingHeader = "Accept-Encoding" + contentTypeHeader = "Content-Type" + contentEncodingHeader = "Content-Encoding" + acceptEncodingHeader = "Accept-Encoding" + processStartTimeHeader = "Process-Start-Time" ) +var processStartTime time.Time + +func init() { + processStartTime = time.Now() +} + var gzipPool = sync.Pool{ New: func() interface{} { return gzip.NewWriter(nil) @@ -121,6 +128,9 @@ func HandlerForTransactional(reg prometheus.TransactionalGatherer, opts HandlerO } h := http.HandlerFunc(func(rsp http.ResponseWriter, req *http.Request) { + if opts.EnableProcessStartTimeHeader { + rsp.Header().Set(processStartTimeHeader, strconv.FormatInt(processStartTime.Unix(), 10)) + } if inFlightSem != nil { select { case inFlightSem <- struct{}{}: // All good, carry on. @@ -366,6 +376,15 @@ type HandlerOpts struct { // (which changes the identity of the resulting series on the Prometheus // server). EnableOpenMetrics bool + // If true, a process start time header is added to the response along + // with the metrics payload. This is useful because you receive the headers + // prior to the response body, and for large responses, this allows the + // scraping agent to stream metrics using the process start time to + // correctly offset counter metrics. The alternative is to use the metric + // process_start_time_seconds, which unfortunately tends to fall at the end + // of the response body, requiring the scraping agent to buffer the entire + // body in memory until process_start_time_seconds is reached. + EnableProcessStartTimeHeader bool } // gzipAccepted returns whether the client will accept gzip-encoded content.