Add structured logging support to promhttp
In order to better support the standard library `log/slog` add a new interface to the `promhttp` `HandlerOpts`. Signed-off-by: SuperQ <superq@gmail.com>
This commit is contained in:
parent
97aa0493eb
commit
c65233230d
|
@ -168,6 +168,9 @@ func HandlerForTransactional(reg prometheus.TransactionalGatherer, opts HandlerO
|
|||
if opts.ErrorLog != nil {
|
||||
opts.ErrorLog.Println("error gathering metrics:", err)
|
||||
}
|
||||
if opts.StructuredErrorLog != nil {
|
||||
opts.StructuredErrorLog.Error("error gathering metrics", "error", err)
|
||||
}
|
||||
errCnt.WithLabelValues("gathering").Inc()
|
||||
switch opts.ErrorHandling {
|
||||
case PanicOnError:
|
||||
|
@ -197,6 +200,9 @@ func HandlerForTransactional(reg prometheus.TransactionalGatherer, opts HandlerO
|
|||
if opts.ErrorLog != nil {
|
||||
opts.ErrorLog.Println("error getting writer", err)
|
||||
}
|
||||
if opts.StructuredErrorLog != nil {
|
||||
opts.StructuredErrorLog.Error("error getting writer", "error", err)
|
||||
}
|
||||
w = io.Writer(rsp)
|
||||
encodingHeader = string(Identity)
|
||||
}
|
||||
|
@ -218,6 +224,9 @@ func HandlerForTransactional(reg prometheus.TransactionalGatherer, opts HandlerO
|
|||
if opts.ErrorLog != nil {
|
||||
opts.ErrorLog.Println("error encoding and sending metric family:", err)
|
||||
}
|
||||
if opts.StructuredErrorLog != nil {
|
||||
opts.StructuredErrorLog.Error("error encoding and sending metric family", "error", err)
|
||||
}
|
||||
errCnt.WithLabelValues("encoding").Inc()
|
||||
switch opts.ErrorHandling {
|
||||
case PanicOnError:
|
||||
|
@ -344,6 +353,12 @@ type Logger interface {
|
|||
Println(v ...interface{})
|
||||
}
|
||||
|
||||
// StructuredLogger is a minimal interface HandlerOpts needs for structured
|
||||
// logging. This is implementd by the standard library log/slog.Logger type.
|
||||
type StructuredLogger interface {
|
||||
Error(msg string, args ...any)
|
||||
}
|
||||
|
||||
// HandlerOpts specifies options how to serve metrics via an http.Handler. The
|
||||
// zero value of HandlerOpts is a reasonable default.
|
||||
type HandlerOpts struct {
|
||||
|
@ -354,6 +369,9 @@ type HandlerOpts struct {
|
|||
// latter, create a Logger implementation that detects a
|
||||
// prometheus.MultiError and formats the contained errors into one line.
|
||||
ErrorLog Logger
|
||||
// StructuredErrorLog StructuredLogger specifies an optional structured log
|
||||
// handler.
|
||||
StructuredErrorLog StructuredLogger
|
||||
// ErrorHandling defines how errors are handled. Note that errors are
|
||||
// logged regardless of the configured ErrorHandling provided ErrorLog
|
||||
// is not nil.
|
||||
|
|
|
@ -20,8 +20,10 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -130,25 +132,30 @@ func TestHandlerErrorHandling(t *testing.T) {
|
|||
logBuf := &bytes.Buffer{}
|
||||
logger := log.New(logBuf, "", 0)
|
||||
|
||||
slogger := slog.New(slog.NewTextHandler(os.Stderr, nil))
|
||||
|
||||
writer := httptest.NewRecorder()
|
||||
request, _ := http.NewRequest("GET", "/", nil)
|
||||
request.Header.Add("Accept", "test/plain")
|
||||
|
||||
mReg := &mockTransactionGatherer{g: reg}
|
||||
errorHandler := HandlerForTransactional(mReg, HandlerOpts{
|
||||
ErrorLog: logger,
|
||||
ErrorHandling: HTTPErrorOnError,
|
||||
Registry: reg,
|
||||
ErrorLog: logger,
|
||||
StructuredErrorLog: slogger,
|
||||
ErrorHandling: HTTPErrorOnError,
|
||||
Registry: reg,
|
||||
})
|
||||
continueHandler := HandlerForTransactional(mReg, HandlerOpts{
|
||||
ErrorLog: logger,
|
||||
ErrorHandling: ContinueOnError,
|
||||
Registry: reg,
|
||||
ErrorLog: logger,
|
||||
StructuredErrorLog: slogger,
|
||||
ErrorHandling: ContinueOnError,
|
||||
Registry: reg,
|
||||
})
|
||||
panicHandler := HandlerForTransactional(mReg, HandlerOpts{
|
||||
ErrorLog: logger,
|
||||
ErrorHandling: PanicOnError,
|
||||
Registry: reg,
|
||||
ErrorLog: logger,
|
||||
StructuredErrorLog: slogger,
|
||||
ErrorHandling: PanicOnError,
|
||||
Registry: reg,
|
||||
})
|
||||
// Expect gatherer not touched.
|
||||
if got := mReg.gatherInvoked; got != 0 {
|
||||
|
|
Loading…
Reference in New Issue