Skip to content

promhttp: Isolate zstd support and klauspost/compress library use to promhttp/zstd package #1765

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 15 additions & 11 deletions prometheus/promhttp/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ import (
"sync"
"time"

"github.com/klauspost/compress/zstd"
"github.com/prometheus/common/expfmt"

"github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp/internal"
)

const (
Expand All @@ -65,7 +65,13 @@ const (
Zstd Compression = "zstd"
)

var defaultCompressionFormats = []Compression{Identity, Gzip, Zstd}
func defaultCompressionFormats() []Compression {
if internal.NewZstdWriter != nil {
return []Compression{Identity, Gzip, Zstd}
} else {
return []Compression{Identity, Gzip}
}
}

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

switch selected {
case "zstd":
// TODO(mrueg): Replace klauspost/compress with stdlib implementation once https://github.com/golang/go/issues/62513 is implemented.
z, err := zstd.NewWriter(rw, zstd.WithEncoderLevel(zstd.SpeedFastest))
if err != nil {
return nil, "", func() {}, err
if internal.NewZstdWriter == nil {
// The content encoding was not implemented yet.
return nil, "", func() {}, fmt.Errorf("content compression format not recognized: %s. Valid formats are: %s", selected, defaultCompressionFormats())
}

z.Reset(rw)
return z, selected, func() { _ = z.Close() }, nil
writer, closeWriter, err := internal.NewZstdWriter(rw)
return writer, selected, closeWriter, err
case "gzip":
gz := gzipPool.Get().(*gzip.Writer)
gz.Reset(rw)
Expand All @@ -483,6 +487,6 @@ func negotiateEncodingWriter(r *http.Request, rw io.Writer, compressions []strin
return rw, selected, func() {}, nil
default:
// The content encoding was not implemented yet.
return nil, "", func() {}, fmt.Errorf("content compression format not recognized: %s. Valid formats are: %s", selected, defaultCompressionFormats)
return nil, "", func() {}, fmt.Errorf("content compression format not recognized: %s. Valid formats are: %s", selected, defaultCompressionFormats())
}
}
3 changes: 2 additions & 1 deletion prometheus/promhttp/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
dto "github.com/prometheus/client_model/go"

"github.com/prometheus/client_golang/prometheus"
_ "github.com/prometheus/client_golang/prometheus/promhttp/zstd"
)

type errorCollector struct{}
Expand Down Expand Up @@ -484,7 +485,7 @@ func TestInstrumentMetricHandlerWithCompression(t *testing.T) {
func TestNegotiateEncodingWriter(t *testing.T) {
var defaultCompressions []string

for _, comp := range defaultCompressionFormats {
for _, comp := range defaultCompressionFormats() {
defaultCompressions = append(defaultCompressions, string(comp))
}

Expand Down
21 changes: 21 additions & 0 deletions prometheus/promhttp/internal/compression.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2025 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package internal

import (
"io"
)

// NewZstdWriter enables zstd write support if non-nil.
var NewZstdWriter func(rw io.Writer) (_ io.Writer, closeWriter func(), _ error)
47 changes: 47 additions & 0 deletions prometheus/promhttp/zstd/zstd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright 2025 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package zstd activates support for zstd compression.
// To enable zstd compression support, import like this:
//
// import (
// _ "github.com/prometheus/client_golang/prometheus/promhttp/zstd"
// )
//
// This support is currently implemented via the github.com/klauspost/compress library,
// so importing this package requires linking and building that library.
// Once stdlib support is added to the Go standard library (https://github.com/golang/go/issues/62513),
// this package is expected to become a no-op, and zstd support will be enabled by default.
package zstd

import (
"io"

"github.com/klauspost/compress/zstd"

"github.com/prometheus/client_golang/prometheus/promhttp/internal"
)

func init() {
// Enable zstd support
internal.NewZstdWriter = func(rw io.Writer) (_ io.Writer, closeWriter func(), _ error) {
// 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.
z, err := zstd.NewWriter(rw, zstd.WithEncoderLevel(zstd.SpeedFastest))
if err != nil {
return nil, func() {}, err
}

z.Reset(rw)
return z, func() { _ = z.Close() }, nil
}
}
Loading