diff --git a/README.md b/README.md index e6462ad..faa3ebc 100644 --- a/README.md +++ b/README.md @@ -34,18 +34,24 @@ $ cat example/data.json "count": 3, "some_boolean": false, "state": "ACTIVE" - }, - ] + } + ], + "location": "mars" } -$ cat example/config.yml +$ cat examples/config.yml +--- +metrics: - name: example_global_value path: $.counter + help: Example of a top-level global value scrape in the json labels: environment: beta # static label + location: $.location # dynamic label - name: example_value type: object + help: Example of sub-level value scrapes from a json path: $.values[*]?(@.state == "ACTIVE") labels: environment: beta # static label @@ -55,10 +61,13 @@ $ cat example/config.yml count: $.count # dynamic value boolean: $.some_boolean +headers: + X-Dummy: my-test-header + $ python -m SimpleHTTPServer 8000 & Serving HTTP on 0.0.0.0 port 8000 ... -$ ./json_exporter examples/config.yml & +$ ./json_exporter --config.file examples/config.yml & $ curl "http://localhost:7979/probe?target=http://localhost:8000/examples/data.json" | grep ^example example_global_value{environment="beta",location="mars"} 1234 @@ -78,10 +87,9 @@ Then head over to http://localhost:9090/graph?g0.range_input=1h&g0.expr=example_ ```console docker run \ - -v config.yml:/config.yml + -v $PWD/examples/config.yml:/config.yml quay.io/prometheuscommunity/json-exporter \ - http://example.com/target.json \ - /config.yml + --config.file /config.yml ``` # See Also diff --git a/cmd/main.go b/cmd/main.go index b0b2587..b75f271 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -16,7 +16,6 @@ package cmd import ( "context" "encoding/json" - "fmt" "net/http" "os" "time" @@ -28,48 +27,32 @@ import ( "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/version" - "github.com/urfave/cli" + "gopkg.in/alecthomas/kingpin.v2" ) var ( - defaultOpts = []cli.Flag{ - cli.IntFlag{ - Name: "port", - Usage: "The port number used to expose metrics via http", - Value: 7979, - }, - cli.StringFlag{ - Name: "log-level", - Usage: "Set Logging level", - Value: "info", - }, - } + configFile = kingpin.Flag("config.file", "JSON exporter configuration file.").Default("config.yml").ExistingFile() + listenAddress = kingpin.Flag("web.listen-address", "The address to listen on for HTTP requests.").Default(":7979").String() + configCheck = kingpin.Flag("config.check", "If true validate the config file and then exit.").Default().Bool() ) -func MakeApp() *cli.App { - - app := cli.NewApp() - app.Name = "json_exporter" - app.Usage = "A prometheus exporter for scraping metrics from JSON REST API endpoints" - app.UsageText = "[OPTIONS] CONFIG_PATH" - app.Action = main - app.Flags = defaultOpts - - return app -} - -func main(c *cli.Context) { +func Run() { promlogConfig := &promlog.Config{} + + flag.AddFlags(kingpin.CommandLine, promlogConfig) + kingpin.Version(version.Print("json_exporter")) + kingpin.HelpFlag.Short('h') + kingpin.Parse() logger := promlog.New(promlogConfig) level.Info(logger).Log("msg", "Starting json_exporter", "version", version.Info()) //nolint:errcheck level.Info(logger).Log("msg", "Build context", "build", version.BuildContext()) //nolint:errcheck - internal.Init(logger, c) - - config, err := config.LoadConfig(c.Args()[0]) + level.Info(logger).Log("msg", "Loading config file", "file", *configFile) //nolint:errcheck + config, err := config.LoadConfig(*configFile) if err != nil { level.Error(logger).Log("msg", "Error loading config", "err", err) //nolint:errcheck os.Exit(1) @@ -78,13 +61,17 @@ func main(c *cli.Context) { if err != nil { level.Error(logger).Log("msg", "Failed to marshal config to JOSN", "err", err) //nolint:errcheck } - level.Info(logger).Log("msg", "Loaded config file", "config", configJson) //nolint:errcheck + level.Info(logger).Log("msg", "Loaded config file", "config", string(configJson)) //nolint:errcheck + + if *configCheck { + os.Exit(0) + } http.Handle("/metrics", promhttp.Handler()) http.HandleFunc("/probe", func(w http.ResponseWriter, req *http.Request) { probeHandler(w, req, logger, config) }) - if err := http.ListenAndServe(fmt.Sprintf(":%d", c.Int("port")), nil); err != nil { + if err := http.ListenAndServe(*listenAddress, nil); err != nil { level.Error(logger).Log("msg", "failed to start the server", "err", err) //nolint:errcheck } } diff --git a/go.mod b/go.mod index 4862566..33348f6 100644 --- a/go.mod +++ b/go.mod @@ -9,5 +9,6 @@ require ( github.com/prometheus/client_golang v1.7.1 github.com/prometheus/common v0.10.0 github.com/urfave/cli v1.22.4 + gopkg.in/alecthomas/kingpin.v2 v2.2.6 gopkg.in/yaml.v2 v2.3.0 ) diff --git a/internal/collector.go b/internal/collector.go index 3c55732..f9932a4 100644 --- a/internal/collector.go +++ b/internal/collector.go @@ -14,10 +14,7 @@ package internal import ( - "context" "fmt" - "io/ioutil" - "net/http" "strconv" "github.com/go-kit/kit/log" @@ -171,32 +168,3 @@ func extractLabels(logger log.Logger, json []byte, l map[string]string) map[stri } return labels } - -func FetchJson(ctx context.Context, logger log.Logger, endpoint string, headers map[string]string) ([]byte, error) { - client := &http.Client{} - req, err := http.NewRequest("GET", endpoint, nil) - req = req.WithContext(ctx) - if err != nil { - level.Error(logger).Log("msg", "Failed to create request", "err", err) //nolint:errcheck - return nil, err - } - - for key, value := range headers { - req.Header.Add(key, value) - } - if req.Header.Get("Accept") == "" { - req.Header.Add("Accept", "application/json") - } - resp, err := client.Do(req) - if err != nil { - return nil, fmt.Errorf("failed to fetch json from endpoint;endpoint:<%s>,err:<%s>", endpoint, err) - } - defer resp.Body.Close() - - data, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, fmt.Errorf("failed to read response body;err:<%s>", err) - } - - return data, nil -} diff --git a/internal/init.go b/internal/init.go deleted file mode 100644 index 56092b4..0000000 --- a/internal/init.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2020 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 ( - "os" - - "github.com/go-kit/kit/log" - "github.com/go-kit/kit/log/level" - "github.com/prometheus-community/json_exporter/config" - "github.com/urfave/cli" -) - -func Init(logger log.Logger, c *cli.Context) { - args := c.Args() - - if len(args) < 1 { - cli.ShowAppHelp(c) //nolint:errcheck - level.Error(logger).Log("msg", "Not enough arguments") //nolint:errcheck - os.Exit(1) - } - - var ( - configPath = args[0] - ) - - _, err := config.LoadConfig(configPath) - - if err != nil { - level.Error(logger).Log("msg", "Failed to load config") //nolint:errcheck - os.Exit(1) - } -} diff --git a/internal/util.go b/internal/util.go index 36c713a..1a12c55 100644 --- a/internal/util.go +++ b/internal/util.go @@ -14,11 +14,16 @@ package internal import ( + "context" "fmt" + "io/ioutil" "math" + "net/http" "strconv" "strings" + "github.com/go-kit/kit/log" + "github.com/go-kit/kit/log/level" "github.com/kawamuray/jsonpath" "github.com/prometheus-community/json_exporter/config" "github.com/prometheus/client_golang/prometheus" @@ -100,3 +105,32 @@ func CreateMetricsList(r *prometheus.Registry, c config.Config) ([]JsonGaugeColl } return metrics, nil } + +func FetchJson(ctx context.Context, logger log.Logger, endpoint string, headers map[string]string) ([]byte, error) { + client := &http.Client{} + req, err := http.NewRequest("GET", endpoint, nil) + req = req.WithContext(ctx) + if err != nil { + level.Error(logger).Log("msg", "Failed to create request", "err", err) //nolint:errcheck + return nil, err + } + + for key, value := range headers { + req.Header.Add(key, value) + } + if req.Header.Get("Accept") == "" { + req.Header.Add("Accept", "application/json") + } + resp, err := client.Do(req) + if err != nil { + return nil, fmt.Errorf("failed to fetch json from endpoint;endpoint:<%s>,err:<%s>", endpoint, err) + } + defer resp.Body.Close() + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("failed to read response body;err:<%s>", err) + } + + return data, nil +} diff --git a/main.go b/main.go index 8c2fc33..a2ec551 100644 --- a/main.go +++ b/main.go @@ -14,14 +14,9 @@ package main import ( - "os" - "github.com/prometheus-community/json_exporter/cmd" ) func main() { - err := cmd.MakeApp().Run(os.Args) - if err != nil { - os.Exit(1) - } + cmd.Run() }