Skip to content

Commit

Permalink
chore!: adopt slog, drop go-kit/log
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
tjhop committed Oct 18, 2024
1 parent 03abaa7 commit 9cdeb9f
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 103 deletions.
3 changes: 1 addition & 2 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
linters:
enable:
- revive
- sloglint

issues:
exclude-rules:
Expand All @@ -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
Expand Down
35 changes: 17 additions & 18 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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)
Expand All @@ -91,20 +90,20 @@ 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)
}

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()
Expand All @@ -116,15 +115,15 @@ 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
}

registry := prometheus.NewPedanticRegistry()

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}
Expand Down
26 changes: 13 additions & 13 deletions cmd/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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 {
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
39 changes: 19 additions & 20 deletions exporter/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -28,7 +27,7 @@ import (
type JSONMetricCollector struct {
JSONMetrics []JSONMetric
Data []byte
Logger log.Logger
Logger *slog.Logger
}

type JSONMetric struct {
Expand All @@ -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
}

Expand All @@ -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
}

Expand All @@ -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
}

Expand All @@ -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)

Expand All @@ -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
}

Expand All @@ -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)
Expand Down
Loading

0 comments on commit 9cdeb9f

Please sign in to comment.