Skip to content

Commit 3fa9fca

Browse files
committed
Add an error counter for internal errors in the HTTP handler
The doc comments explain the rationale in a quite detailed way. Fixes #543 and #542 Signed-off-by: beorn7 <[email protected]>
1 parent ea8c935 commit 3fa9fca

File tree

1 file changed

+43
-4
lines changed

1 file changed

+43
-4
lines changed

prometheus/promhttp/http.go

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,32 @@ func Handler() http.Handler {
8484
// instrumentation. Use the InstrumentMetricHandler function to apply the same
8585
// kind of instrumentation as it is used by the Handler function.
8686
func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler {
87-
var inFlightSem chan struct{}
87+
var (
88+
inFlightSem chan struct{}
89+
errCnt = prometheus.NewCounterVec(
90+
prometheus.CounterOpts{
91+
Name: "promhttp_metric_handler_errors_total",
92+
Help: "Total number of internal errors encountered by the promhttp metric handler.",
93+
},
94+
[]string{"cause"},
95+
)
96+
)
97+
8898
if opts.MaxRequestsInFlight > 0 {
8999
inFlightSem = make(chan struct{}, opts.MaxRequestsInFlight)
90100
}
101+
if opts.Registry != nil {
102+
// Initialize all possibilites that can occur below.
103+
errCnt.WithLabelValues("gathering")
104+
errCnt.WithLabelValues("encoding")
105+
if err := opts.Registry.Register(errCnt); err != nil {
106+
if are, ok := err.(prometheus.AlreadyRegisteredError); ok {
107+
errCnt = are.ExistingCollector.(*prometheus.CounterVec)
108+
} else {
109+
panic(err)
110+
}
111+
}
112+
}
91113

92114
h := http.HandlerFunc(func(rsp http.ResponseWriter, req *http.Request) {
93115
if inFlightSem != nil {
@@ -106,6 +128,7 @@ func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler {
106128
if opts.ErrorLog != nil {
107129
opts.ErrorLog.Println("error gathering metrics:", err)
108130
}
131+
errCnt.WithLabelValues("gathering").Inc()
109132
switch opts.ErrorHandling {
110133
case PanicOnError:
111134
panic(err)
@@ -146,6 +169,7 @@ func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler {
146169
if opts.ErrorLog != nil {
147170
opts.ErrorLog.Println("error encoding and sending metric family:", err)
148171
}
172+
errCnt.WithLabelValues("encoding").Inc()
149173
switch opts.ErrorHandling {
150174
case PanicOnError:
151175
panic(err)
@@ -236,9 +260,12 @@ const (
236260
// Ignore errors and try to serve as many metrics as possible. However,
237261
// if no metrics can be served, serve an HTTP status code 500 and the
238262
// last error message in the body. Only use this in deliberate "best
239-
// effort" metrics collection scenarios. It is recommended to at least
240-
// log errors (by providing an ErrorLog in HandlerOpts) to not mask
241-
// errors completely.
263+
// effort" metrics collection scenarios. In this case, it is highly
264+
// recommended to provide other means of detecting errors: By setting an
265+
// ErrorLog in HandlerOpts, the errors are logged. By providing a
266+
// Registry in HandlerOpts, the exposed metrics include an error counter
267+
// "promhttp_metric_handler_errors_total", which can be used for
268+
// alerts.
242269
ContinueOnError
243270
// Panic upon the first error encountered (useful for "crash only" apps).
244271
PanicOnError
@@ -261,6 +288,18 @@ type HandlerOpts struct {
261288
// logged regardless of the configured ErrorHandling provided ErrorLog
262289
// is not nil.
263290
ErrorHandling HandlerErrorHandling
291+
// If Registry is not nil, it is used to register a metric
292+
// "promhttp_metric_handler_errors_total", partitioned by "cause". A
293+
// failed registration causes a panic. Note that this error counter is
294+
// different from the instrumentation you get from the various
295+
// InstrumentHandler... helpers. It counts errors that don't necessarily
296+
// result in a non-2xx HTTP status code. There are two typical cases:
297+
// (1) Encoding errors that only happen after streaming of the HTTP body
298+
// has already started (and the status code 200 has been sent). This
299+
// should only happen with custom collectors. (2) Collection errors with
300+
// no effect on the HTTP status code because ErrorHandling is set to
301+
// ContinueOnError.
302+
Registry prometheus.Registerer
264303
// If DisableCompression is true, the handler will never compress the
265304
// response, even if requested by the client.
266305
DisableCompression bool

0 commit comments

Comments
 (0)