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

View File

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

View File

@ -22,9 +22,9 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/go-kit/log"
"github.com/prometheus-community/json_exporter/config" "github.com/prometheus-community/json_exporter/config"
pconfig "github.com/prometheus/common/config" pconfig "github.com/prometheus/common/config"
"github.com/prometheus/common/promslog"
) )
func TestFailIfSelfSignedCA(t *testing.T) { 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) req := httptest.NewRequest("GET", "http://example.com/foo"+"?module=default&target="+target.URL, nil)
recorder := httptest.NewRecorder() 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() resp := recorder.Result()
body, _ := io.ReadAll(resp.Body) 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) req := httptest.NewRequest("GET", "http://example.com/foo"+"?module=default&target="+target.URL, nil)
recorder := httptest.NewRecorder() recorder := httptest.NewRecorder()
probeHandler(recorder, req, log.NewNopLogger(), c) probeHandler(recorder, req, promslog.NewNopLogger(), c)
resp := recorder.Result() resp := recorder.Result()
body, _ := io.ReadAll(resp.Body) 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) req := httptest.NewRequest("GET", "http://example.com/foo"+"?target="+target.URL, nil)
recorder := httptest.NewRecorder() 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() resp := recorder.Result()
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
@ -87,7 +87,7 @@ func TestDefaultModule(t *testing.T) {
// Module doesn't exist. // Module doesn't exist.
recorder = httptest.NewRecorder() 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() resp = recorder.Result()
if resp.StatusCode != http.StatusBadRequest { if resp.StatusCode != http.StatusBadRequest {
t.Fatalf("Default module test fails unexpectedly, expected 400, got %d", resp.StatusCode) 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) { func TestFailIfTargetMissing(t *testing.T) {
req := httptest.NewRequest("GET", "http://example.com/foo", nil) req := httptest.NewRequest("GET", "http://example.com/foo", nil)
recorder := httptest.NewRecorder() recorder := httptest.NewRecorder()
probeHandler(recorder, req, log.NewNopLogger(), config.Config{}) probeHandler(recorder, req, promslog.NewNopLogger(), config.Config{})
resp := recorder.Result() resp := recorder.Result()
body, _ := io.ReadAll(resp.Body) 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) req := httptest.NewRequest("GET", "http://example.com/foo"+"?module=default&target="+target.URL, nil)
recorder := httptest.NewRecorder() 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() resp := recorder.Result()
body, _ := io.ReadAll(resp.Body) 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) req := httptest.NewRequest("GET", "http://example.com/foo"+"?module=default&target="+target.URL+test.ServeFile, nil)
recorder := httptest.NewRecorder() recorder := httptest.NewRecorder()
probeHandler(recorder, req, log.NewNopLogger(), c) probeHandler(recorder, req, promslog.NewNopLogger(), c)
resp := recorder.Result() resp := recorder.Result()
body, _ := io.ReadAll(resp.Body) 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() resp := recorder.Result()
body, _ := io.ReadAll(resp.Body) 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() resp := recorder.Result()
body, _ := io.ReadAll(resp.Body) 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() resp := recorder.Result()
body, _ := io.ReadAll(resp.Body) 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() resp := recorder.Result()
respBody, _ := io.ReadAll(resp.Body) 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() resp := recorder.Result()
respBody, _ := io.ReadAll(resp.Body) respBody, _ := io.ReadAll(resp.Body)

View File

@ -16,10 +16,9 @@ package exporter
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"log/slog"
"time" "time"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/prometheus-community/json_exporter/config" "github.com/prometheus-community/json_exporter/config"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"k8s.io/client-go/util/jsonpath" "k8s.io/client-go/util/jsonpath"
@ -28,7 +27,7 @@ import (
type JSONMetricCollector struct { type JSONMetricCollector struct {
JSONMetrics []JSONMetric JSONMetrics []JSONMetric
Data []byte Data []byte
Logger log.Logger Logger *slog.Logger
} }
type JSONMetric struct { type JSONMetric struct {
@ -53,7 +52,7 @@ func (mc JSONMetricCollector) Collect(ch chan<- prometheus.Metric) {
case config.ValueScrape: case config.ValueScrape:
value, err := extractValue(mc.Logger, mc.Data, m.KeyJSONPath, false) value, err := extractValue(mc.Logger, mc.Data, m.KeyJSONPath, false)
if err != nil { 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 continue
} }
@ -66,14 +65,14 @@ func (mc JSONMetricCollector) Collect(ch chan<- prometheus.Metric) {
) )
ch <- timestampMetric(mc.Logger, m, mc.Data, metric) ch <- timestampMetric(mc.Logger, m, mc.Data, metric)
} else { } 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 continue
} }
case config.ObjectScrape: case config.ObjectScrape:
values, err := extractValue(mc.Logger, mc.Data, m.KeyJSONPath, true) values, err := extractValue(mc.Logger, mc.Data, m.KeyJSONPath, true)
if err != nil { 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 continue
} }
@ -82,12 +81,12 @@ func (mc JSONMetricCollector) Collect(ch chan<- prometheus.Metric) {
for _, data := range jsonData { for _, data := range jsonData {
jdata, err := json.Marshal(data) jdata, err := json.Marshal(data)
if err != nil { 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 continue
} }
value, err := extractValue(mc.Logger, jdata, m.ValueJSONPath, false) value, err := extractValue(mc.Logger, jdata, m.ValueJSONPath, false)
if err != nil { 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 continue
} }
@ -100,23 +99,23 @@ func (mc JSONMetricCollector) Collect(ch chan<- prometheus.Metric) {
) )
ch <- timestampMetric(mc.Logger, m, jdata, metric) ch <- timestampMetric(mc.Logger, m, jdata, metric)
} else { } 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 continue
} }
} }
} else { } 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 continue
} }
default: 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 continue
} }
} }
} }
// Returns the last matching value at the given json path // 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{} var jsonData interface{}
buf := new(bytes.Buffer) 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 { 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 return "", err
} }
if err := j.Parse(path); err != nil { 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 return "", err
} }
if err := j.Execute(buf, jsonData); err != nil { 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 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 // 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)) labels := make([]string, len(paths))
for i, path := range paths { for i, path := range paths {
if result, err := extractValue(logger, data, path, false); err == nil { if result, err := extractValue(logger, data, path, false); err == nil {
labels[i] = result labels[i] = result
} else { } 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 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 == "" { if m.EpochTimestampJSONPath == "" {
return pm return pm
} }
ts, err := extractValue(logger, data, m.EpochTimestampJSONPath, false) ts, err := extractValue(logger, data, m.EpochTimestampJSONPath, false)
if err != nil { 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 return pm
} }
epochTime, err := SanitizeIntValue(ts) epochTime, err := SanitizeIntValue(ts)
if err != nil { 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 return pm
} }
timestamp := time.UnixMilli(epochTime) timestamp := time.UnixMilli(epochTime)

View File

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

27
go.mod
View File

@ -1,14 +1,13 @@
module github.com/prometheus-community/json_exporter module github.com/prometheus-community/json_exporter
go 1.21 go 1.22
require ( require (
github.com/Masterminds/sprig/v3 v3.2.3 github.com/Masterminds/sprig/v3 v3.2.3
github.com/alecthomas/kingpin/v2 v2.4.0 github.com/alecthomas/kingpin/v2 v2.4.0
github.com/go-kit/log v0.2.1 github.com/prometheus/client_golang v1.20.5
github.com/prometheus/client_golang v1.19.1 github.com/prometheus/common v0.60.0
github.com/prometheus/common v0.55.0 github.com/prometheus/exporter-toolkit v0.13.0
github.com/prometheus/exporter-toolkit v0.11.0
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
k8s.io/client-go v0.28.3 k8s.io/client-go v0.28.3
) )
@ -18,13 +17,15 @@ require (
github.com/Masterminds/semver/v3 v3.2.0 // indirect github.com/Masterminds/semver/v3 v3.2.0 // indirect
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
github.com/beorn7/perks v1.0.1 // 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/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/google/uuid v1.3.0 // indirect
github.com/huandu/xstrings v1.3.3 // indirect github.com/huandu/xstrings v1.3.3 // indirect
github.com/imdario/mergo v0.3.11 // indirect github.com/imdario/mergo v0.3.11 // indirect
github.com/jpillora/backoff v1.0.0 // 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/copystructure v1.0.0 // indirect
github.com/mitchellh/reflectwalk v1.0.0 // indirect github.com/mitchellh/reflectwalk v1.0.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // 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/shopspring/decimal v1.2.0 // indirect
github.com/spf13/cast v1.3.1 // indirect github.com/spf13/cast v1.3.1 // indirect
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
golang.org/x/crypto v0.24.0 // indirect golang.org/x/crypto v0.27.0 // indirect
golang.org/x/net v0.26.0 // indirect golang.org/x/net v0.29.0 // indirect
golang.org/x/oauth2 v0.21.0 // indirect golang.org/x/oauth2 v0.23.0 // indirect
golang.org/x/sync v0.7.0 // indirect golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.21.0 // indirect golang.org/x/sys v0.25.0 // indirect
golang.org/x/text v0.16.0 // indirect golang.org/x/text v0.18.0 // indirect
google.golang.org/protobuf v1.34.2 // 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/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 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 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.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 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 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 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.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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/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 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 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/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 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= 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 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 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 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= 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/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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= 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 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= 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.60.0 h1:+V9PAREWNvJMAuJ1x1BaWl9dewMW4YrHZQbx0sJNllA=
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= github.com/prometheus/common v0.60.0/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw=
github.com/prometheus/exporter-toolkit v0.11.0 h1:yNTsuZ0aNCNFQ3aFTD2uhPOvr4iD7fdBvKPAEGkNf+g= github.com/prometheus/exporter-toolkit v0.13.0 h1:lmA0Q+8IaXgmFRKw09RldZmZdnvu9wwcDLIXGmTPw1c=
github.com/prometheus/exporter-toolkit v0.11.0/go.mod h1:BVnENhnNecpwoTLiABx7mrPB/OLRIgN74qlQbV+FK1Q= 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 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= 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-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.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.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= 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/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-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-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.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.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= 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-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.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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-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-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-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-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.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.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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-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.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= 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.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.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.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= 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-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.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=