Skip to content

Commit e575c9c

Browse files
authored
promhttp: Isolate zstd support and klauspost/compress library use to promhttp/zstd package (#1765)
Signed-off-by: Jordan Liggitt <[email protected]>
1 parent f2276aa commit e575c9c

File tree

4 files changed

+85
-12
lines changed

4 files changed

+85
-12
lines changed

Diff for: prometheus/promhttp/http.go

+15-11
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ import (
4141
"sync"
4242
"time"
4343

44-
"github.com/klauspost/compress/zstd"
4544
"github.com/prometheus/common/expfmt"
4645

4746
"github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil"
4847
"github.com/prometheus/client_golang/prometheus"
48+
"github.com/prometheus/client_golang/prometheus/promhttp/internal"
4949
)
5050

5151
const (
@@ -65,7 +65,13 @@ const (
6565
Zstd Compression = "zstd"
6666
)
6767

68-
var defaultCompressionFormats = []Compression{Identity, Gzip, Zstd}
68+
func defaultCompressionFormats() []Compression {
69+
if internal.NewZstdWriter != nil {
70+
return []Compression{Identity, Gzip, Zstd}
71+
} else {
72+
return []Compression{Identity, Gzip}
73+
}
74+
}
6975

7076
var gzipPool = sync.Pool{
7177
New: func() interface{} {
@@ -138,7 +144,7 @@ func HandlerForTransactional(reg prometheus.TransactionalGatherer, opts HandlerO
138144
// Select compression formats to offer based on default or user choice.
139145
var compressions []string
140146
if !opts.DisableCompression {
141-
offers := defaultCompressionFormats
147+
offers := defaultCompressionFormats()
142148
if len(opts.OfferedCompressions) > 0 {
143149
offers = opts.OfferedCompressions
144150
}
@@ -466,14 +472,12 @@ func negotiateEncodingWriter(r *http.Request, rw io.Writer, compressions []strin
466472

467473
switch selected {
468474
case "zstd":
469-
// TODO(mrueg): Replace klauspost/compress with stdlib implementation once https://github.com/golang/go/issues/62513 is implemented.
470-
z, err := zstd.NewWriter(rw, zstd.WithEncoderLevel(zstd.SpeedFastest))
471-
if err != nil {
472-
return nil, "", func() {}, err
475+
if internal.NewZstdWriter == nil {
476+
// The content encoding was not implemented yet.
477+
return nil, "", func() {}, fmt.Errorf("content compression format not recognized: %s. Valid formats are: %s", selected, defaultCompressionFormats())
473478
}
474-
475-
z.Reset(rw)
476-
return z, selected, func() { _ = z.Close() }, nil
479+
writer, closeWriter, err := internal.NewZstdWriter(rw)
480+
return writer, selected, closeWriter, err
477481
case "gzip":
478482
gz := gzipPool.Get().(*gzip.Writer)
479483
gz.Reset(rw)
@@ -483,6 +487,6 @@ func negotiateEncodingWriter(r *http.Request, rw io.Writer, compressions []strin
483487
return rw, selected, func() {}, nil
484488
default:
485489
// The content encoding was not implemented yet.
486-
return nil, "", func() {}, fmt.Errorf("content compression format not recognized: %s. Valid formats are: %s", selected, defaultCompressionFormats)
490+
return nil, "", func() {}, fmt.Errorf("content compression format not recognized: %s. Valid formats are: %s", selected, defaultCompressionFormats())
487491
}
488492
}

Diff for: prometheus/promhttp/http_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
dto "github.com/prometheus/client_model/go"
3131

3232
"github.com/prometheus/client_golang/prometheus"
33+
_ "github.com/prometheus/client_golang/prometheus/promhttp/zstd"
3334
)
3435

3536
type errorCollector struct{}
@@ -484,7 +485,7 @@ func TestInstrumentMetricHandlerWithCompression(t *testing.T) {
484485
func TestNegotiateEncodingWriter(t *testing.T) {
485486
var defaultCompressions []string
486487

487-
for _, comp := range defaultCompressionFormats {
488+
for _, comp := range defaultCompressionFormats() {
488489
defaultCompressions = append(defaultCompressions, string(comp))
489490
}
490491

Diff for: prometheus/promhttp/internal/compression.go

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2025 The Prometheus Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package internal
15+
16+
import (
17+
"io"
18+
)
19+
20+
// NewZstdWriter enables zstd write support if non-nil.
21+
var NewZstdWriter func(rw io.Writer) (_ io.Writer, closeWriter func(), _ error)

Diff for: prometheus/promhttp/zstd/zstd.go

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright 2025 The Prometheus Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
// Package zstd activates support for zstd compression.
15+
// To enable zstd compression support, import like this:
16+
//
17+
// import (
18+
// _ "github.com/prometheus/client_golang/prometheus/promhttp/zstd"
19+
// )
20+
//
21+
// This support is currently implemented via the github.com/klauspost/compress library,
22+
// so importing this package requires linking and building that library.
23+
// Once stdlib support is added to the Go standard library (https://github.com/golang/go/issues/62513),
24+
// this package is expected to become a no-op, and zstd support will be enabled by default.
25+
package zstd
26+
27+
import (
28+
"io"
29+
30+
"github.com/klauspost/compress/zstd"
31+
32+
"github.com/prometheus/client_golang/prometheus/promhttp/internal"
33+
)
34+
35+
func init() {
36+
// Enable zstd support
37+
internal.NewZstdWriter = func(rw io.Writer) (_ io.Writer, closeWriter func(), _ error) {
38+
// TODO(mrueg): Replace klauspost/compress with stdlib implementation once https://github.com/golang/go/issues/62513 is implemented, and move this package to be a no-op / backfill for older go versions.
39+
z, err := zstd.NewWriter(rw, zstd.WithEncoderLevel(zstd.SpeedFastest))
40+
if err != nil {
41+
return nil, func() {}, err
42+
}
43+
44+
z.Reset(rw)
45+
return z, func() { _ = z.Close() }, nil
46+
}
47+
}

0 commit comments

Comments
 (0)