Skip to content

Commit ce14c97

Browse files
committed
Add structured logging support to promhttp
In order to better support the standard library `log/slog` add a new interface to the `promhttp` `HandlerOpts`. Note, this requires updating the Go minimum version to Go 1.21. Signed-off-by: SuperQ <[email protected]>
1 parent dbf72fc commit ce14c97

File tree

8 files changed

+44
-15
lines changed

8 files changed

+44
-15
lines changed

Diff for: .github/workflows/go.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ jobs:
5454

5555
- name: Run style and unused
5656
uses: dagger/dagger-for-github@v6
57-
if: ${{ matrix.go_version == '1.20' }}
57+
if: ${{ matrix.go_version == '1.21' }}
5858
with:
5959
version: "latest"
6060
verb: call

Diff for: .github/workflows/golangci-lint.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
- name: Install Go
2929
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
3030
with:
31-
go-version: 1.22.x
31+
go-version: 1.23.x
3232
- name: Install snmp_exporter/generator dependencies
3333
run: sudo apt-get update && sudo apt-get -y install libsnmp-dev
3434
if: github.repository == 'prometheus/snmp_exporter'

Diff for: README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ This is the [Go](http://golang.org) client library for
1010
instrumenting application code, and one for creating clients that talk to the
1111
Prometheus HTTP API.
1212

13-
**This library requires Go1.20 or later.**
14-
> The library mandates the use of Go1.20 or subsequent versions. While it has demonstrated functionality with versions as old as Go 1.17, our commitment remains to offer support and rectifications for only the most recent three major releases.
13+
**This library requires Go1.21 or later.**
14+
> The library mandates the use of Go1.21 or subsequent versions. While it has demonstrated functionality with versions as old as Go 1.17, our commitment remains to offer support and rectifications for only the most recent three major releases.
1515
1616
## Important note about releases and stability
1717

Diff for: go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/prometheus/client_golang
22

3-
go 1.20
3+
go 1.21
44

55
require (
66
github.com/beorn7/perks v1.0.1

Diff for: go.sum

+4
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,11 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg
4141
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
4242
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
4343
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
44+
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
4445
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
4546
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
4647
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
48+
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
4749
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
4850
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
4951
golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
@@ -56,6 +58,8 @@ google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6h
5658
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
5759
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
5860
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
61+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
5962
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
6063
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
6164
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
65+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

Diff for: prometheus/promhttp/http.go

+18
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,9 @@ func HandlerForTransactional(reg prometheus.TransactionalGatherer, opts HandlerO
168168
if opts.ErrorLog != nil {
169169
opts.ErrorLog.Println("error gathering metrics:", err)
170170
}
171+
if opts.StructuredErrorLog != nil {
172+
opts.StructuredErrorLog.Error("error gathering metrics", "error", err)
173+
}
171174
errCnt.WithLabelValues("gathering").Inc()
172175
switch opts.ErrorHandling {
173176
case PanicOnError:
@@ -197,6 +200,9 @@ func HandlerForTransactional(reg prometheus.TransactionalGatherer, opts HandlerO
197200
if opts.ErrorLog != nil {
198201
opts.ErrorLog.Println("error getting writer", err)
199202
}
203+
if opts.StructuredErrorLog != nil {
204+
opts.StructuredErrorLog.Error("error getting writer", "error", err)
205+
}
200206
w = io.Writer(rsp)
201207
encodingHeader = string(Identity)
202208
}
@@ -218,6 +224,9 @@ func HandlerForTransactional(reg prometheus.TransactionalGatherer, opts HandlerO
218224
if opts.ErrorLog != nil {
219225
opts.ErrorLog.Println("error encoding and sending metric family:", err)
220226
}
227+
if opts.StructuredErrorLog != nil {
228+
opts.StructuredErrorLog.Error("error encoding and sending metric family", "error", err)
229+
}
221230
errCnt.WithLabelValues("encoding").Inc()
222231
switch opts.ErrorHandling {
223232
case PanicOnError:
@@ -344,6 +353,12 @@ type Logger interface {
344353
Println(v ...interface{})
345354
}
346355

356+
// StructuredLogger is a minimal interface HandlerOpts needs for structured
357+
// logging. This is implementd by the standard library log/slog.Logger type.
358+
type StructuredLogger interface {
359+
Error(msg string, args ...any)
360+
}
361+
347362
// HandlerOpts specifies options how to serve metrics via an http.Handler. The
348363
// zero value of HandlerOpts is a reasonable default.
349364
type HandlerOpts struct {
@@ -354,6 +369,9 @@ type HandlerOpts struct {
354369
// latter, create a Logger implementation that detects a
355370
// prometheus.MultiError and formats the contained errors into one line.
356371
ErrorLog Logger
372+
// StructuredErrorLog StructuredLogger specifies an optional structured log
373+
// handler.
374+
StructuredErrorLog StructuredLogger
357375
// ErrorHandling defines how errors are handled. Note that errors are
358376
// logged regardless of the configured ErrorHandling provided ErrorLog
359377
// is not nil.

Diff for: prometheus/promhttp/http_test.go

+16-9
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@ import (
2020
"fmt"
2121
"io"
2222
"log"
23+
"log/slog"
2324
"net/http"
2425
"net/http/httptest"
26+
"os"
2527
"strings"
2628
"testing"
2729
"time"
@@ -130,25 +132,30 @@ func TestHandlerErrorHandling(t *testing.T) {
130132
logBuf := &bytes.Buffer{}
131133
logger := log.New(logBuf, "", 0)
132134

135+
slogger := slog.New(slog.NewTextHandler(os.Stderr, nil))
136+
133137
writer := httptest.NewRecorder()
134138
request, _ := http.NewRequest("GET", "/", nil)
135139
request.Header.Add("Accept", "test/plain")
136140

137141
mReg := &mockTransactionGatherer{g: reg}
138142
errorHandler := HandlerForTransactional(mReg, HandlerOpts{
139-
ErrorLog: logger,
140-
ErrorHandling: HTTPErrorOnError,
141-
Registry: reg,
143+
ErrorLog: logger,
144+
StructuredErrorLog: slogger,
145+
ErrorHandling: HTTPErrorOnError,
146+
Registry: reg,
142147
})
143148
continueHandler := HandlerForTransactional(mReg, HandlerOpts{
144-
ErrorLog: logger,
145-
ErrorHandling: ContinueOnError,
146-
Registry: reg,
149+
ErrorLog: logger,
150+
StructuredErrorLog: slogger,
151+
ErrorHandling: ContinueOnError,
152+
Registry: reg,
147153
})
148154
panicHandler := HandlerForTransactional(mReg, HandlerOpts{
149-
ErrorLog: logger,
150-
ErrorHandling: PanicOnError,
151-
Registry: reg,
155+
ErrorLog: logger,
156+
StructuredErrorLog: slogger,
157+
ErrorHandling: PanicOnError,
158+
Registry: reg,
152159
})
153160
// Expect gatherer not touched.
154161
if got := mReg.gatherInvoked; got != 0 {

Diff for: supported_go_versions.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1+
1.23
12
1.22
23
1.21
3-
1.20

0 commit comments

Comments
 (0)