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