chore!: adopt slog, drop go-kit/log

The bulk of this change set was automated by the following script which
is being used to aid in converting the various exporters/projects to use
slog:

https://gist.github.com/tjhop/49f96fb7ebbe55b12deee0b0312d8434

Signed-off-by: TJ Hoplock <t.hoplock@gmail.com>
This commit is contained in:
TJ Hoplock 2024-10-17 22:26:10 -04:00
parent 03abaa7e9c
commit 9cdeb9f48f
7 changed files with 104 additions and 103 deletions

View File

@ -1,6 +1,7 @@
linters:
enable:
- revive
- sloglint
issues:
exclude-rules:
@ -13,8 +14,6 @@ linters-settings:
exclude-functions:
# Used in HTTP handlers, any error is handled by the server itself.
- (net/http.ResponseWriter).Write
# Never check for logger errors.
- (github.com/go-kit/log.Logger).Log
revive:
rules:
- name: unused-parameter

View File

@ -17,18 +17,17 @@ import (
"context"
"encoding/json"
"fmt"
"log/slog"
"net/http"
"os"
"github.com/alecthomas/kingpin/v2"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/prometheus-community/json_exporter/config"
"github.com/prometheus-community/json_exporter/exporter"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/prometheus/common/promlog"
"github.com/prometheus/common/promlog/flag"
"github.com/prometheus/common/promslog"
"github.com/prometheus/common/promslog/flag"
"github.com/prometheus/common/version"
"github.com/prometheus/exporter-toolkit/web"
"github.com/prometheus/exporter-toolkit/web/kingpinflag"
@ -46,28 +45,28 @@ var (
func Run() {
promlogConfig := &promlog.Config{}
promslogConfig := &promslog.Config{}
flag.AddFlags(kingpin.CommandLine, promlogConfig)
flag.AddFlags(kingpin.CommandLine, promslogConfig)
kingpin.Version(version.Print("json_exporter"))
kingpin.HelpFlag.Short('h')
kingpin.Parse()
logger := promlog.New(promlogConfig)
logger := promslog.New(promslogConfig)
level.Info(logger).Log("msg", "Starting json_exporter", "version", version.Info())
level.Info(logger).Log("msg", "Build context", "build", version.BuildContext())
logger.Info("Starting json_exporter", "version", version.Info())
logger.Info("Build context", "build", version.BuildContext())
level.Info(logger).Log("msg", "Loading config file", "file", *configFile)
logger.Info("Loading config file", "file", *configFile)
config, err := config.LoadConfig(*configFile)
if err != nil {
level.Error(logger).Log("msg", "Error loading config", "err", err)
logger.Error("Error loading config", "err", err)
os.Exit(1)
}
configJSON, err := json.Marshal(config)
if err != nil {
level.Error(logger).Log("msg", "Failed to marshal config to JSON", "err", err)
logger.Error("Failed to marshal config to JSON", "err", err)
}
level.Info(logger).Log("msg", "Loaded config file", "config", string(configJSON))
logger.Info("Loaded config file", "config", string(configJSON))
if *configCheck {
os.Exit(0)
@ -91,7 +90,7 @@ func Run() {
}
landingPage, err := web.NewLandingPage(landingConfig)
if err != nil {
level.Error(logger).Log("err", err)
logger.Error("error creating landing page", "err", err)
os.Exit(1)
}
http.Handle("/", landingPage)
@ -99,12 +98,12 @@ func Run() {
server := &http.Server{}
if err := web.ListenAndServe(server, toolkitFlags, logger); err != nil {
level.Error(logger).Log("msg", "Failed to start the server", "err", err)
logger.Error("Failed to start the server", "err", err)
os.Exit(1)
}
}
func probeHandler(w http.ResponseWriter, r *http.Request, logger log.Logger, config config.Config) {
func probeHandler(w http.ResponseWriter, r *http.Request, logger *slog.Logger, config config.Config) {
ctx, cancel := context.WithCancel(r.Context())
defer cancel()
@ -116,7 +115,7 @@ func probeHandler(w http.ResponseWriter, r *http.Request, logger log.Logger, con
}
if _, ok := config.Modules[module]; !ok {
http.Error(w, fmt.Sprintf("Unknown module %q", module), http.StatusBadRequest)
level.Debug(logger).Log("msg", "Unknown module", "module", module)
logger.Debug("Unknown module", "module", module)
return
}
@ -124,7 +123,7 @@ func probeHandler(w http.ResponseWriter, r *http.Request, logger log.Logger, con
metrics, err := exporter.CreateMetricsList(config.Modules[module])
if err != nil {
level.Error(logger).Log("msg", "Failed to create metrics list from config", "err", err)
logger.Error("Failed to create metrics list from config", "err", err)
}
jsonMetricCollector := exporter.JSONMetricCollector{JSONMetrics: metrics}

View File

@ -22,9 +22,9 @@ import (
"strings"
"testing"
"github.com/go-kit/log"
"github.com/prometheus-community/json_exporter/config"
pconfig "github.com/prometheus/common/config"
"github.com/prometheus/common/promslog"
)
func TestFailIfSelfSignedCA(t *testing.T) {
@ -34,7 +34,7 @@ func TestFailIfSelfSignedCA(t *testing.T) {
req := httptest.NewRequest("GET", "http://example.com/foo"+"?module=default&target="+target.URL, nil)
recorder := httptest.NewRecorder()
probeHandler(recorder, req, log.NewNopLogger(), config.Config{Modules: map[string]config.Module{"default": {}}})
probeHandler(recorder, req, promslog.NewNopLogger(), config.Config{Modules: map[string]config.Module{"default": {}}})
resp := recorder.Result()
body, _ := io.ReadAll(resp.Body)
@ -61,7 +61,7 @@ func TestSucceedIfSelfSignedCA(t *testing.T) {
req := httptest.NewRequest("GET", "http://example.com/foo"+"?module=default&target="+target.URL, nil)
recorder := httptest.NewRecorder()
probeHandler(recorder, req, log.NewNopLogger(), c)
probeHandler(recorder, req, promslog.NewNopLogger(), c)
resp := recorder.Result()
body, _ := io.ReadAll(resp.Body)
@ -78,7 +78,7 @@ func TestDefaultModule(t *testing.T) {
req := httptest.NewRequest("GET", "http://example.com/foo"+"?target="+target.URL, nil)
recorder := httptest.NewRecorder()
probeHandler(recorder, req, log.NewNopLogger(), config.Config{Modules: map[string]config.Module{"default": {}}})
probeHandler(recorder, req, promslog.NewNopLogger(), config.Config{Modules: map[string]config.Module{"default": {}}})
resp := recorder.Result()
if resp.StatusCode != http.StatusOK {
@ -87,7 +87,7 @@ func TestDefaultModule(t *testing.T) {
// Module doesn't exist.
recorder = httptest.NewRecorder()
probeHandler(recorder, req, log.NewNopLogger(), config.Config{Modules: map[string]config.Module{"foo": {}}})
probeHandler(recorder, req, promslog.NewNopLogger(), config.Config{Modules: map[string]config.Module{"foo": {}}})
resp = recorder.Result()
if resp.StatusCode != http.StatusBadRequest {
t.Fatalf("Default module test fails unexpectedly, expected 400, got %d", resp.StatusCode)
@ -97,7 +97,7 @@ func TestDefaultModule(t *testing.T) {
func TestFailIfTargetMissing(t *testing.T) {
req := httptest.NewRequest("GET", "http://example.com/foo", nil)
recorder := httptest.NewRecorder()
probeHandler(recorder, req, log.NewNopLogger(), config.Config{})
probeHandler(recorder, req, promslog.NewNopLogger(), config.Config{})
resp := recorder.Result()
body, _ := io.ReadAll(resp.Body)
@ -119,7 +119,7 @@ func TestDefaultAcceptHeader(t *testing.T) {
req := httptest.NewRequest("GET", "http://example.com/foo"+"?module=default&target="+target.URL, nil)
recorder := httptest.NewRecorder()
probeHandler(recorder, req, log.NewNopLogger(), config.Config{Modules: map[string]config.Module{"default": {}}})
probeHandler(recorder, req, promslog.NewNopLogger(), config.Config{Modules: map[string]config.Module{"default": {}}})
resp := recorder.Result()
body, _ := io.ReadAll(resp.Body)
@ -151,7 +151,7 @@ func TestCorrectResponse(t *testing.T) {
req := httptest.NewRequest("GET", "http://example.com/foo"+"?module=default&target="+target.URL+test.ServeFile, nil)
recorder := httptest.NewRecorder()
probeHandler(recorder, req, log.NewNopLogger(), c)
probeHandler(recorder, req, promslog.NewNopLogger(), c)
resp := recorder.Result()
body, _ := io.ReadAll(resp.Body)
@ -191,7 +191,7 @@ func TestBasicAuth(t *testing.T) {
},
}
probeHandler(recorder, req, log.NewNopLogger(), c)
probeHandler(recorder, req, promslog.NewNopLogger(), c)
resp := recorder.Result()
body, _ := io.ReadAll(resp.Body)
@ -222,7 +222,7 @@ func TestBearerToken(t *testing.T) {
}},
}
probeHandler(recorder, req, log.NewNopLogger(), c)
probeHandler(recorder, req, promslog.NewNopLogger(), c)
resp := recorder.Result()
body, _ := io.ReadAll(resp.Body)
@ -258,7 +258,7 @@ func TestHTTPHeaders(t *testing.T) {
},
}
probeHandler(recorder, req, log.NewNopLogger(), c)
probeHandler(recorder, req, promslog.NewNopLogger(), c)
resp := recorder.Result()
body, _ := io.ReadAll(resp.Body)
@ -321,7 +321,7 @@ func TestBodyPostTemplate(t *testing.T) {
},
}
probeHandler(recorder, req, log.NewNopLogger(), c)
probeHandler(recorder, req, promslog.NewNopLogger(), c)
resp := recorder.Result()
respBody, _ := io.ReadAll(resp.Body)
@ -420,7 +420,7 @@ func TestBodyPostQuery(t *testing.T) {
},
}
probeHandler(recorder, req, log.NewNopLogger(), c)
probeHandler(recorder, req, promslog.NewNopLogger(), c)
resp := recorder.Result()
respBody, _ := io.ReadAll(resp.Body)

View File

@ -16,10 +16,9 @@ package exporter
import (
"bytes"
"encoding/json"
"log/slog"
"time"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/prometheus-community/json_exporter/config"
"github.com/prometheus/client_golang/prometheus"
"k8s.io/client-go/util/jsonpath"
@ -28,7 +27,7 @@ import (
type JSONMetricCollector struct {
JSONMetrics []JSONMetric
Data []byte
Logger log.Logger
Logger *slog.Logger
}
type JSONMetric struct {
@ -53,7 +52,7 @@ func (mc JSONMetricCollector) Collect(ch chan<- prometheus.Metric) {
case config.ValueScrape:
value, err := extractValue(mc.Logger, mc.Data, m.KeyJSONPath, false)
if err != nil {
level.Error(mc.Logger).Log("msg", "Failed to extract value for metric", "path", m.KeyJSONPath, "err", err, "metric", m.Desc)
mc.Logger.Error("Failed to extract value for metric", "path", m.KeyJSONPath, "err", err, "metric", m.Desc)
continue
}
@ -66,14 +65,14 @@ func (mc JSONMetricCollector) Collect(ch chan<- prometheus.Metric) {
)
ch <- timestampMetric(mc.Logger, m, mc.Data, metric)
} else {
level.Error(mc.Logger).Log("msg", "Failed to convert extracted value to float64", "path", m.KeyJSONPath, "value", value, "err", err, "metric", m.Desc)
mc.Logger.Error("Failed to convert extracted value to float64", "path", m.KeyJSONPath, "value", value, "err", err, "metric", m.Desc)
continue
}
case config.ObjectScrape:
values, err := extractValue(mc.Logger, mc.Data, m.KeyJSONPath, true)
if err != nil {
level.Error(mc.Logger).Log("msg", "Failed to extract json objects for metric", "err", err, "metric", m.Desc)
mc.Logger.Error("Failed to extract json objects for metric", "err", err, "metric", m.Desc)
continue
}
@ -82,12 +81,12 @@ func (mc JSONMetricCollector) Collect(ch chan<- prometheus.Metric) {
for _, data := range jsonData {
jdata, err := json.Marshal(data)
if err != nil {
level.Error(mc.Logger).Log("msg", "Failed to marshal data to json", "path", m.ValueJSONPath, "err", err, "metric", m.Desc, "data", data)
mc.Logger.Error("Failed to marshal data to json", "path", m.ValueJSONPath, "err", err, "metric", m.Desc, "data", data)
continue
}
value, err := extractValue(mc.Logger, jdata, m.ValueJSONPath, false)
if err != nil {
level.Error(mc.Logger).Log("msg", "Failed to extract value for metric", "path", m.ValueJSONPath, "err", err, "metric", m.Desc)
mc.Logger.Error("Failed to extract value for metric", "path", m.ValueJSONPath, "err", err, "metric", m.Desc)
continue
}
@ -100,23 +99,23 @@ func (mc JSONMetricCollector) Collect(ch chan<- prometheus.Metric) {
)
ch <- timestampMetric(mc.Logger, m, jdata, metric)
} else {
level.Error(mc.Logger).Log("msg", "Failed to convert extracted value to float64", "path", m.ValueJSONPath, "value", value, "err", err, "metric", m.Desc)
mc.Logger.Error("Failed to convert extracted value to float64", "path", m.ValueJSONPath, "value", value, "err", err, "metric", m.Desc)
continue
}
}
} else {
level.Error(mc.Logger).Log("msg", "Failed to convert extracted objects to json", "err", err, "metric", m.Desc)
mc.Logger.Error("Failed to convert extracted objects to json", "err", err, "metric", m.Desc)
continue
}
default:
level.Error(mc.Logger).Log("msg", "Unknown scrape config type", "type", m.Type, "metric", m.Desc)
mc.Logger.Error("Unknown scrape config type", "type", m.Type, "metric", m.Desc)
continue
}
}
}
// Returns the last matching value at the given json path
func extractValue(logger log.Logger, data []byte, path string, enableJSONOutput bool) (string, error) {
func extractValue(logger *slog.Logger, data []byte, path string, enableJSONOutput bool) (string, error) {
var jsonData interface{}
buf := new(bytes.Buffer)
@ -126,17 +125,17 @@ func extractValue(logger log.Logger, data []byte, path string, enableJSONOutput
}
if err := json.Unmarshal(data, &jsonData); err != nil {
level.Error(logger).Log("msg", "Failed to unmarshal data to json", "err", err, "data", data)
logger.Error("Failed to unmarshal data to json", "err", err, "data", data)
return "", err
}
if err := j.Parse(path); err != nil {
level.Error(logger).Log("msg", "Failed to parse jsonpath", "err", err, "path", path, "data", data)
logger.Error("Failed to parse jsonpath", "err", err, "path", path, "data", data)
return "", err
}
if err := j.Execute(buf, jsonData); err != nil {
level.Error(logger).Log("msg", "Failed to execute jsonpath", "err", err, "path", path, "data", data)
logger.Error("Failed to execute jsonpath", "err", err, "path", path, "data", data)
return "", err
}
@ -149,30 +148,30 @@ func extractValue(logger log.Logger, data []byte, path string, enableJSONOutput
}
// Returns the list of labels created from the list of provided json paths
func extractLabels(logger log.Logger, data []byte, paths []string) []string {
func extractLabels(logger *slog.Logger, data []byte, paths []string) []string {
labels := make([]string, len(paths))
for i, path := range paths {
if result, err := extractValue(logger, data, path, false); err == nil {
labels[i] = result
} else {
level.Error(logger).Log("msg", "Failed to extract label value", "err", err, "path", path, "data", data)
logger.Error("Failed to extract label value", "err", err, "path", path, "data", data)
}
}
return labels
}
func timestampMetric(logger log.Logger, m JSONMetric, data []byte, pm prometheus.Metric) prometheus.Metric {
func timestampMetric(logger *slog.Logger, m JSONMetric, data []byte, pm prometheus.Metric) prometheus.Metric {
if m.EpochTimestampJSONPath == "" {
return pm
}
ts, err := extractValue(logger, data, m.EpochTimestampJSONPath, false)
if err != nil {
level.Error(logger).Log("msg", "Failed to extract timestamp for metric", "path", m.KeyJSONPath, "err", err, "metric", m.Desc)
logger.Error("Failed to extract timestamp for metric", "path", m.KeyJSONPath, "err", err, "metric", m.Desc)
return pm
}
epochTime, err := SanitizeIntValue(ts)
if err != nil {
level.Error(logger).Log("msg", "Failed to parse timestamp for metric", "path", m.KeyJSONPath, "err", err, "metric", m.Desc)
logger.Error("Failed to parse timestamp for metric", "path", m.KeyJSONPath, "err", err, "metric", m.Desc)
return pm
}
timestamp := time.UnixMilli(epochTime)

View File

@ -18,6 +18,7 @@ import (
"errors"
"fmt"
"io"
"log/slog"
"math"
"net/http"
"net/url"
@ -26,8 +27,6 @@ import (
"text/template"
"github.com/Masterminds/sprig/v3"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/prometheus-community/json_exporter/config"
"github.com/prometheus/client_golang/prometheus"
pconfig "github.com/prometheus/common/config"
@ -58,7 +57,7 @@ func SanitizeValue(s string) (float64, error) {
if s == "<nil>" {
return math.NaN(), nil
}
return value, fmt.Errorf(resultErr)
return value, errors.New(resultErr)
}
func SanitizeIntValue(s string) (int64, error) {
@ -71,7 +70,7 @@ func SanitizeIntValue(s string) (int64, error) {
}
resultErr = fmt.Sprintf("%s", err)
return value, fmt.Errorf(resultErr)
return value, errors.New(resultErr)
}
func CreateMetricsList(c config.Module) ([]JSONMetric, error) {
@ -143,12 +142,12 @@ func CreateMetricsList(c config.Module) ([]JSONMetric, error) {
type JSONFetcher struct {
module config.Module
ctx context.Context
logger log.Logger
logger *slog.Logger
method string
body io.Reader
}
func NewJSONFetcher(ctx context.Context, logger log.Logger, m config.Module, tplValues url.Values) *JSONFetcher {
func NewJSONFetcher(ctx context.Context, logger *slog.Logger, m config.Module, tplValues url.Values) *JSONFetcher {
method, body := renderBody(logger, m.Body, tplValues)
return &JSONFetcher{
module: m,
@ -163,7 +162,7 @@ func (f *JSONFetcher) FetchJSON(endpoint string) ([]byte, error) {
httpClientConfig := f.module.HTTPClientConfig
client, err := pconfig.NewClientFromConfig(httpClientConfig, "fetch_json", pconfig.WithKeepAlivesDisabled(), pconfig.WithHTTP2Disabled())
if err != nil {
level.Error(f.logger).Log("msg", "Error generating HTTP client", "err", err)
f.logger.Error("Error generating HTTP client", "err", err)
return nil, err
}
@ -171,7 +170,7 @@ func (f *JSONFetcher) FetchJSON(endpoint string) ([]byte, error) {
req, err = http.NewRequest(f.method, endpoint, f.body)
req = req.WithContext(f.ctx)
if err != nil {
level.Error(f.logger).Log("msg", "Failed to create request", "err", err)
f.logger.Error("Failed to create request", "err", err)
return nil, err
}
@ -188,7 +187,7 @@ func (f *JSONFetcher) FetchJSON(endpoint string) ([]byte, error) {
defer func() {
if _, err := io.Copy(io.Discard, resp.Body); err != nil {
level.Error(f.logger).Log("msg", "Failed to discard body", "err", err)
f.logger.Error("Failed to discard body", "err", err)
}
resp.Body.Close()
}()
@ -219,7 +218,7 @@ func (f *JSONFetcher) FetchJSON(endpoint string) ([]byte, error) {
// Use the configured template to render the body if enabled
// Do not treat template errors as fatal, on such errors just log them
// and continue with static body content
func renderBody(logger log.Logger, body config.Body, tplValues url.Values) (method string, br io.Reader) {
func renderBody(logger *slog.Logger, body config.Body, tplValues url.Values) (method string, br io.Reader) {
method = "POST"
if body.Content == "" {
return "GET", nil
@ -228,16 +227,16 @@ func renderBody(logger log.Logger, body config.Body, tplValues url.Values) (meth
if body.Templatize {
tpl, err := template.New("base").Funcs(sprig.TxtFuncMap()).Parse(body.Content)
if err != nil {
level.Error(logger).Log("msg", "Failed to create a new template from body content", "err", err, "content", body.Content)
logger.Error("Failed to create a new template from body content", "err", err, "content", body.Content)
return
}
tpl = tpl.Option("missingkey=zero")
var b strings.Builder
if err := tpl.Execute(&b, tplValues); err != nil {
level.Error(logger).Log("msg", "Failed to render template with values", "err", err, "tempalte", body.Content)
logger.Error("Failed to render template with values", "err", err, "tempalte", body.Content)
// `tplValues` can contain sensitive values, so log it only when in debug mode
level.Debug(logger).Log("msg", "Failed to render template with values", "err", err, "tempalte", body.Content, "values", tplValues, "rendered_body", b.String())
logger.Debug("Failed to render template with values", "err", err, "tempalte", body.Content, "values", tplValues, "rendered_body", b.String())
return
}
br = strings.NewReader(b.String())

27
go.mod
View File

@ -1,14 +1,13 @@
module github.com/prometheus-community/json_exporter
go 1.21
go 1.22
require (
github.com/Masterminds/sprig/v3 v3.2.3
github.com/alecthomas/kingpin/v2 v2.4.0
github.com/go-kit/log v0.2.1
github.com/prometheus/client_golang v1.19.1
github.com/prometheus/common v0.55.0
github.com/prometheus/exporter-toolkit v0.11.0
github.com/prometheus/client_golang v1.20.5
github.com/prometheus/common v0.60.0
github.com/prometheus/exporter-toolkit v0.13.0
gopkg.in/yaml.v2 v2.4.0
k8s.io/client-go v0.28.3
)
@ -18,13 +17,15 @@ require (
github.com/Masterminds/semver/v3 v3.2.0 // indirect
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/go-logfmt/logfmt v0.5.1 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/huandu/xstrings v1.3.3 // indirect
github.com/imdario/mergo v0.3.11 // indirect
github.com/jpillora/backoff v1.0.0 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/mdlayher/socket v0.4.1 // indirect
github.com/mdlayher/vsock v1.2.1 // indirect
github.com/mitchellh/copystructure v1.0.0 // indirect
github.com/mitchellh/reflectwalk v1.0.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
@ -34,11 +35,11 @@ require (
github.com/shopspring/decimal v1.2.0 // indirect
github.com/spf13/cast v1.3.1 // indirect
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
golang.org/x/crypto v0.24.0 // indirect
golang.org/x/net v0.26.0 // indirect
golang.org/x/oauth2 v0.21.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.21.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/crypto v0.27.0 // indirect
golang.org/x/net v0.29.0 // indirect
golang.org/x/oauth2 v0.23.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/text v0.18.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
)

52
go.sum
View File

@ -10,17 +10,13 @@ github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAu
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
@ -33,10 +29,18 @@ github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
github.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ=
github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE=
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
@ -47,14 +51,14 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
github.com/prometheus/exporter-toolkit v0.11.0 h1:yNTsuZ0aNCNFQ3aFTD2uhPOvr4iD7fdBvKPAEGkNf+g=
github.com/prometheus/exporter-toolkit v0.11.0/go.mod h1:BVnENhnNecpwoTLiABx7mrPB/OLRIgN74qlQbV+FK1Q=
github.com/prometheus/common v0.60.0 h1:+V9PAREWNvJMAuJ1x1BaWl9dewMW4YrHZQbx0sJNllA=
github.com/prometheus/common v0.60.0/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw=
github.com/prometheus/exporter-toolkit v0.13.0 h1:lmA0Q+8IaXgmFRKw09RldZmZdnvu9wwcDLIXGmTPw1c=
github.com/prometheus/exporter-toolkit v0.13.0/go.mod h1:2uop99EZl80KdXhv/MxVI2181fMcwlsumFOqBecGkG0=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
@ -75,29 +79,29 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
@ -105,8 +109,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=