-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: use urfave/cli to parse the CLI flags
- Loading branch information
1 parent
b655076
commit 96883e9
Showing
6 changed files
with
200 additions
and
109 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package cli | ||
|
||
import ( | ||
"log" | ||
"time" | ||
|
||
"github.com/urfave/cli/v2" | ||
|
||
"github.com/marcfrederick/imaginary-exporter/internal/cmd" | ||
) | ||
|
||
func Run(version string, args []string) { | ||
if err := NewApp(version).Run(args); err != nil { | ||
log.Fatalln(err) | ||
} | ||
} | ||
|
||
func NewApp(version string) *cli.App { | ||
return &cli.App{ | ||
Name: "imaginary-exporter", | ||
Version: version, | ||
Compiled: time.Now(), | ||
Authors: []*cli.Author{ | ||
{Name: "Marc Trölitzsch", Email: "[email protected]"}, | ||
}, | ||
Usage: "Prometheus exporter for Imaginary metrics", | ||
EnableBashCompletion: true, | ||
|
||
Flags: cli.FlagsByName{ | ||
&cli.StringFlag{ | ||
Name: "addr", | ||
Usage: "address to listen on", | ||
Value: ":8080", | ||
}, | ||
&cli.StringFlag{ | ||
Name: "url", | ||
Usage: "base url of the imaginary instance", | ||
Required: true, | ||
}, | ||
}, | ||
|
||
Action: func(cliCtx *cli.Context) error { | ||
exitCode, err := cmd.Run(cliCtx) | ||
if err != nil { | ||
return cli.Exit(err.Error(), exitCode) | ||
} | ||
return cli.Exit("", exitCode) | ||
}, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package cmd | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"net/http" | ||
"net/url" | ||
|
||
"github.com/prometheus/client_golang/prometheus" | ||
"github.com/prometheus/client_golang/prometheus/promhttp" | ||
"github.com/urfave/cli/v2" | ||
|
||
"github.com/marcfrederick/imaginary-exporter/pkg/collector" | ||
"github.com/marcfrederick/imaginary-exporter/pkg/imaginary" | ||
) | ||
|
||
func Run(cliCtx *cli.Context) (int, error) { | ||
address := cliCtx.String("addr") | ||
imaginaryURL := cliCtx.String("url") | ||
if !isURL(imaginaryURL) { | ||
return 1, fmt.Errorf("the given URL '%s' is invalid", imaginaryURL) | ||
} | ||
|
||
client := imaginary.NewClient(imaginaryURL) | ||
c := collector.NewImaginaryCollector(client) | ||
if err := prometheus.Register(c); err != nil { | ||
return 1, fmt.Errorf("error registering imaginary collector: %w", err) | ||
} | ||
|
||
http.Handle("/metrics", promhttp.Handler()) | ||
log.Printf("listening on address %s", address) | ||
if err := http.ListenAndServe(address, nil); err != nil { | ||
return 1, fmt.Errorf("error listening on address %s: %w", address, err) | ||
} | ||
|
||
return 0, nil | ||
} | ||
|
||
func isURL(str string) bool { | ||
u, err := url.Parse(str) | ||
return err == nil && u.Scheme != "" && u.Host != "" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,104 +1,15 @@ | ||
package main | ||
|
||
import ( | ||
"flag" | ||
"log" | ||
"net/http" | ||
"net/url" | ||
"os" | ||
|
||
"github.com/prometheus/client_golang/prometheus" | ||
"github.com/prometheus/client_golang/prometheus/promhttp" | ||
|
||
"github.com/marcfrederick/imaginary-exporter/pkg/imaginary" | ||
"github.com/marcfrederick/imaginary-exporter/internal/cli" | ||
) | ||
|
||
// ImaginaryCollector collects metrics from a given Imaginary instance. | ||
type ImaginaryCollector struct { | ||
client *imaginary.Client | ||
uptimeMetric *prometheus.Desc | ||
allocatedMemoryMetric *prometheus.Desc | ||
totalAllocatedMemoryMetric *prometheus.Desc | ||
goroutinesMetric *prometheus.Desc | ||
completedGCCyclesMetric *prometheus.Desc | ||
cpusMetric *prometheus.Desc | ||
maxHeapUsageMetric *prometheus.Desc | ||
heapInUseMetric *prometheus.Desc | ||
objectsInUseMetric *prometheus.Desc | ||
oSMemoryObtainedMetric *prometheus.Desc | ||
} | ||
|
||
var _ prometheus.Collector = (*ImaginaryCollector)(nil) | ||
|
||
// newImaginaryCollector creates a new ImaginaryCollector and initializes it. | ||
func newImaginaryCollector(client *imaginary.Client) *ImaginaryCollector { | ||
return &ImaginaryCollector{ | ||
client: client, | ||
uptimeMetric: prometheus.NewDesc("imaginary_uptime", "The current uptime.", nil, nil), | ||
allocatedMemoryMetric: prometheus.NewDesc("imaginary_allocated_memory", "The currently allocated memory.", nil, nil), | ||
totalAllocatedMemoryMetric: prometheus.NewDesc("imaginary_allocated_memory_total", "The total allocated memory.", nil, nil), | ||
goroutinesMetric: prometheus.NewDesc("imaginary_goroutines", "The number of running goroutines.", nil, nil), | ||
completedGCCyclesMetric: prometheus.NewDesc("imaginary_gc_cycles_total", "The number of garbage collection cycles.", nil, nil), | ||
cpusMetric: prometheus.NewDesc("imaginary_cpus_total", "The number of CPUs available.", nil, nil), | ||
maxHeapUsageMetric: prometheus.NewDesc("imaginary_heap_usage_max", "The maximum heap usage.", nil, nil), | ||
heapInUseMetric: prometheus.NewDesc("imaginary_heap_usage", "The current heap usage.", nil, nil), | ||
objectsInUseMetric: prometheus.NewDesc("imaginary_objects", "The number of currently used objects.", nil, nil), | ||
oSMemoryObtainedMetric: prometheus.NewDesc("imaginary_os_memory", "The amount of OS memory obtained.", nil, nil), | ||
} | ||
} | ||
|
||
func (c *ImaginaryCollector) Describe(ch chan<- *prometheus.Desc) { | ||
ch <- c.uptimeMetric | ||
ch <- c.uptimeMetric | ||
ch <- c.allocatedMemoryMetric | ||
ch <- c.totalAllocatedMemoryMetric | ||
ch <- c.goroutinesMetric | ||
ch <- c.completedGCCyclesMetric | ||
ch <- c.cpusMetric | ||
ch <- c.maxHeapUsageMetric | ||
ch <- c.heapInUseMetric | ||
ch <- c.objectsInUseMetric | ||
ch <- c.oSMemoryObtainedMetric | ||
} | ||
|
||
func (c *ImaginaryCollector) Collect(ch chan<- prometheus.Metric) { | ||
res, err := c.client.GetHealthStats() | ||
if err != nil { | ||
log.Printf("error getting metrics: %s", err) | ||
return | ||
} | ||
ch <- prometheus.MustNewConstMetric(c.uptimeMetric, prometheus.CounterValue, float64(res.Uptime)) | ||
ch <- prometheus.MustNewConstMetric(c.allocatedMemoryMetric, prometheus.GaugeValue, res.AllocatedMemory) | ||
ch <- prometheus.MustNewConstMetric(c.totalAllocatedMemoryMetric, prometheus.GaugeValue, res.TotalAllocatedMemory) | ||
ch <- prometheus.MustNewConstMetric(c.goroutinesMetric, prometheus.GaugeValue, float64(res.Goroutines)) | ||
ch <- prometheus.MustNewConstMetric(c.completedGCCyclesMetric, prometheus.GaugeValue, float64(res.CompletedGCCycles)) | ||
ch <- prometheus.MustNewConstMetric(c.cpusMetric, prometheus.GaugeValue, float64(res.CPUs)) | ||
ch <- prometheus.MustNewConstMetric(c.maxHeapUsageMetric, prometheus.GaugeValue, res.MaxHeapUsage) | ||
ch <- prometheus.MustNewConstMetric(c.heapInUseMetric, prometheus.GaugeValue, res.HeapInUse) | ||
ch <- prometheus.MustNewConstMetric(c.objectsInUseMetric, prometheus.GaugeValue, float64(res.ObjectsInUse)) | ||
ch <- prometheus.MustNewConstMetric(c.oSMemoryObtainedMetric, prometheus.GaugeValue, res.OSMemoryObtained) | ||
} | ||
|
||
// isURL checks whether the given string is a valid url | ||
func isURL(str string) bool { | ||
u, err := url.Parse(str) | ||
return err == nil && u.Scheme != "" && u.Host != "" | ||
} | ||
// Injected by GoReleaser during the release process | ||
// https://goreleaser.com/cookbooks/using-main.version/ | ||
var version = "devel" | ||
|
||
func main() { | ||
addr := flag.String("addr", ":8080", "address to listen on") | ||
imaginaryURL := flag.String("url", "", "url of the imaginary instance") | ||
flag.Parse() | ||
if !isURL(*imaginaryURL) { | ||
log.Fatalf("the given imaginary URL '%s' is invalid.", *imaginaryURL) | ||
} | ||
|
||
c := newImaginaryCollector(imaginary.NewClient(*imaginaryURL)) | ||
if err := prometheus.Register(c); err != nil { | ||
log.Fatalf("failed to register imaginary collector: %+v", err) | ||
} | ||
|
||
http.Handle("/metrics", promhttp.Handler()) | ||
if err := http.ListenAndServe(*addr, nil); err != nil { | ||
log.Fatal(err) | ||
} | ||
cli.Run(version, os.Args) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package collector | ||
|
||
import ( | ||
"log" | ||
|
||
"github.com/prometheus/client_golang/prometheus" | ||
|
||
"github.com/marcfrederick/imaginary-exporter/pkg/imaginary" | ||
) | ||
|
||
// ImaginaryCollector collects metrics from a given Imaginary instance. | ||
type ImaginaryCollector struct { | ||
client *imaginary.Client | ||
uptimeMetric *prometheus.Desc | ||
allocatedMemoryMetric *prometheus.Desc | ||
totalAllocatedMemoryMetric *prometheus.Desc | ||
goroutinesMetric *prometheus.Desc | ||
completedGCCyclesMetric *prometheus.Desc | ||
cpusMetric *prometheus.Desc | ||
maxHeapUsageMetric *prometheus.Desc | ||
heapInUseMetric *prometheus.Desc | ||
objectsInUseMetric *prometheus.Desc | ||
oSMemoryObtainedMetric *prometheus.Desc | ||
} | ||
|
||
var _ prometheus.Collector = (*ImaginaryCollector)(nil) | ||
|
||
// NewImaginaryCollector creates a new ImaginaryCollector and initializes it. | ||
func NewImaginaryCollector(client *imaginary.Client) *ImaginaryCollector { | ||
return &ImaginaryCollector{ | ||
client: client, | ||
uptimeMetric: prometheus.NewDesc("imaginary_uptime", "The current uptime.", nil, nil), | ||
allocatedMemoryMetric: prometheus.NewDesc("imaginary_allocated_memory", "The currently allocated memory.", nil, nil), | ||
totalAllocatedMemoryMetric: prometheus.NewDesc("imaginary_allocated_memory_total", "The total allocated memory.", nil, nil), | ||
goroutinesMetric: prometheus.NewDesc("imaginary_goroutines", "The number of running goroutines.", nil, nil), | ||
completedGCCyclesMetric: prometheus.NewDesc("imaginary_gc_cycles_total", "The number of garbage collection cycles.", nil, nil), | ||
cpusMetric: prometheus.NewDesc("imaginary_cpus_total", "The number of CPUs available.", nil, nil), | ||
maxHeapUsageMetric: prometheus.NewDesc("imaginary_heap_usage_max", "The maximum heap usage.", nil, nil), | ||
heapInUseMetric: prometheus.NewDesc("imaginary_heap_usage", "The current heap usage.", nil, nil), | ||
objectsInUseMetric: prometheus.NewDesc("imaginary_objects", "The number of currently used objects.", nil, nil), | ||
oSMemoryObtainedMetric: prometheus.NewDesc("imaginary_os_memory", "The amount of OS memory obtained.", nil, nil), | ||
} | ||
} | ||
|
||
func (c *ImaginaryCollector) Describe(ch chan<- *prometheus.Desc) { | ||
ch <- c.uptimeMetric | ||
ch <- c.uptimeMetric | ||
ch <- c.allocatedMemoryMetric | ||
ch <- c.totalAllocatedMemoryMetric | ||
ch <- c.goroutinesMetric | ||
ch <- c.completedGCCyclesMetric | ||
ch <- c.cpusMetric | ||
ch <- c.maxHeapUsageMetric | ||
ch <- c.heapInUseMetric | ||
ch <- c.objectsInUseMetric | ||
ch <- c.oSMemoryObtainedMetric | ||
} | ||
|
||
func (c *ImaginaryCollector) Collect(ch chan<- prometheus.Metric) { | ||
res, err := c.client.GetHealthStats() | ||
if err != nil { | ||
log.Printf("error getting metrics: %s", err) | ||
return | ||
} | ||
ch <- prometheus.MustNewConstMetric(c.uptimeMetric, prometheus.CounterValue, float64(res.Uptime)) | ||
ch <- prometheus.MustNewConstMetric(c.allocatedMemoryMetric, prometheus.GaugeValue, res.AllocatedMemory) | ||
ch <- prometheus.MustNewConstMetric(c.totalAllocatedMemoryMetric, prometheus.GaugeValue, res.TotalAllocatedMemory) | ||
ch <- prometheus.MustNewConstMetric(c.goroutinesMetric, prometheus.GaugeValue, float64(res.Goroutines)) | ||
ch <- prometheus.MustNewConstMetric(c.completedGCCyclesMetric, prometheus.GaugeValue, float64(res.CompletedGCCycles)) | ||
ch <- prometheus.MustNewConstMetric(c.cpusMetric, prometheus.GaugeValue, float64(res.CPUs)) | ||
ch <- prometheus.MustNewConstMetric(c.maxHeapUsageMetric, prometheus.GaugeValue, res.MaxHeapUsage) | ||
ch <- prometheus.MustNewConstMetric(c.heapInUseMetric, prometheus.GaugeValue, res.HeapInUse) | ||
ch <- prometheus.MustNewConstMetric(c.objectsInUseMetric, prometheus.GaugeValue, float64(res.ObjectsInUse)) | ||
ch <- prometheus.MustNewConstMetric(c.oSMemoryObtainedMetric, prometheus.GaugeValue, res.OSMemoryObtained) | ||
} |