Skip to content
This repository has been archived by the owner on May 7, 2024. It is now read-only.

Commit

Permalink
Merge pull request #11 from exoscale/pushgw_metrics
Browse files Browse the repository at this point in the history
Prometheus Push Gateway metrics
  • Loading branch information
jespada authored Feb 5, 2020
2 parents 980494c + 8b3d9fa commit 47e24e0
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 2 deletions.
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ require (
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348
github.com/mattn/go-colorable v0.0.9 // indirect
github.com/mattn/go-isatty v0.0.4 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/pkg/errors v0.8.1
github.com/prometheus/client_golang v1.1.0
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a
Expand All @@ -20,3 +18,5 @@ require (
)

replace github.com/rcrowley/go-metrics => github.com/exoscale/go-metrics v0.0.0-20180729161012-6a0b1c6c28ec

go 1.13
5 changes: 5 additions & 0 deletions metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ func (r *Reporter) Timer(name string) metrics.Timer {
return metrics.GetOrRegisterTimer(expandName(name, r.prefix), r.metrics.Registry)
}

// Push pushes registered metrics to a push gateway.
func (r *Reporter) Push() error {
return r.metrics.Push()
}

// Healthcheck holds healthcheck state.
type Healthcheck struct {
metrics.Healthcheck
Expand Down
6 changes: 6 additions & 0 deletions metrics/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ func (c *Configuration) UnmarshalYAML(unmarshal func(interface{}) error) error {
return errors.Wrapf(err, "incorrect collectd configuration for item %d", i+1)
}
finalConfiguration[i] = &exporterConfiguration
case "prompushgw":
var exporterConfiguration PromPushGWConfiguration
if err := yaml.Unmarshal(strExporterConfiguration, &exporterConfiguration); err != nil {
return errors.Wrapf(err, "incorrect prompushgw configuration for item %d", i+1)
}
finalConfiguration[i] = &exporterConfiguration
default:
return errors.Errorf("unknown metric system %q for item %d",
exporterName, i+1)
Expand Down
24 changes: 24 additions & 0 deletions metrics/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,23 @@ func TestUnmarshalConfiguration(t *testing.T) {
CacertFile: config.FilePath("/tmp/baz"),
},
},
{
in: `
- prompushgw:
url: https://my.pushgateway.net
job: bar
certfile: /tmp/foo
keyfile: /tmp/bar
cacertfile: /tmp/baz
`,
want: PromPushGWConfiguration{
URL: "https://my.pushgateway.net",
Job: "bar",
CertFile: config.FilePath("/tmp/foo"),
KeyFile: config.FilePath("/tmp/bar"),
CacertFile: config.FilePath("/tmp/baz"),
},
},
}
for _, c := range cases {
var got Configuration
Expand Down Expand Up @@ -117,6 +134,13 @@ func TestUnmarshalIncompleteConfiguration(t *testing.T) {
namespace: foo
subsystem: bar
certfile: /tmp/foo
`,
`
- prompushgw:
url: https://my.pushgateway.net
certfile: /tmp/foo
keyfile: /tmp/bar
cacertfile: /tmp/baz
`,
}
for _, c := range cases {
Expand Down
82 changes: 82 additions & 0 deletions metrics/prompushgw.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package metrics

import (
"crypto/tls"
"crypto/x509"
"io/ioutil"
"net/http"

"github.com/exoscale/go-reporter/config"
"github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus/push"
)

type PromPushGWConfiguration struct {
URL string
Job string
CertFile config.FilePath
KeyFile config.FilePath
CacertFile config.FilePath

pusher *push.Pusher
}

func (c *PromPushGWConfiguration) UnmarshalYAML(unmarshal func(interface{}) error) error {
type rawPromPushGWConfiguration PromPushGWConfiguration
raw := rawPromPushGWConfiguration{}
if err := unmarshal(&raw); err != nil {
return errors.Wrap(err, "unable to decode prompushgw configuration")
}
if raw.URL == "" {
return errors.Errorf("missing URL value")
}
if raw.Job == "" {
return errors.Errorf("missing job value")
}
if (raw.CertFile != "" || raw.KeyFile != "" || raw.CacertFile != "") &&
(raw.CertFile == "" || raw.KeyFile == "" || raw.CacertFile == "") {
return errors.Errorf("certfile, keyfile and cacertfile should be configured")
}
*c = PromPushGWConfiguration(raw)
return nil
}

func (c *PromPushGWConfiguration) initExporter(m *Metrics) error {
httpClient, err := NewHTTPClient(*c)
if err != nil {
return errors.Wrap(err, "can't create http client with given prompushgw config")
}

c.pusher = push.New(c.URL, c.Job).Client(httpClient)
return nil
}

// NewHTTPClient creates an HTTP client for a given config.
func NewHTTPClient(config PromPushGWConfiguration) (*http.Client, error) {
var transport = &http.Transport{}
var tlsConfig *tls.Config

if config.CacertFile != "" {
cert, err := tls.LoadX509KeyPair(string(config.CertFile), string(config.KeyFile))
if err != nil {
return nil, errors.Wrap(err, "can't load certificate pair")
}

caCert, err := ioutil.ReadFile(string(config.CertFile))
if err != nil {
return nil, errors.Wrap(err, "can't load certificate")
}

caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)

tlsConfig = &tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: caCertPool,
}
tlsConfig.BuildNameToCertificate()
transport = &http.Transport{TLSClientConfig: tlsConfig}
}

return &http.Client{Transport: transport}, nil
}
36 changes: 36 additions & 0 deletions metrics/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
package metrics

import (
"errors"
"strings"
"time"

"github.com/prometheus/client_golang/prometheus"
"github.com/rcrowley/go-metrics"
"gopkg.in/tomb.v2"
)
Expand Down Expand Up @@ -71,6 +74,39 @@ func (m *Metrics) MustStart() {
}
}

// Push pushes registered metrics to a Prometheus push gateway.
func (m *Metrics) Push() error {
registry := prometheus.NewRegistry()
m.Registry.Each(func(name string, metric interface{}) {
name = strings.Replace(strings.ToLower(name), ".", "_", -1)

switch metric := metric.(type) {
case *metrics.StandardGauge:
g := prometheus.NewGauge(prometheus.GaugeOpts{Name: name})
g.Set(float64(metric.Value()))
registry.Register(g)

case *metrics.StandardGaugeFloat64:
g := prometheus.NewGauge(prometheus.GaugeOpts{Name: name})
g.Set(float64(metric.Value()))
registry.Register(g)

case *metrics.StandardCounter:
c := prometheus.NewCounter(prometheus.CounterOpts{Name: name})
c.Add(float64(metric.Count()))
registry.Register(c)
}
})

for _, c := range m.config {
if p, ok := c.(*PromPushGWConfiguration); ok {
return p.pusher.Gatherer(registry).Push()
}
}

return errors.New("no prompushgw exporter configured")
}

// Stop stops all exporters and wait for them to terminate.
func (m *Metrics) Stop() error {
m.t.Kill(nil)
Expand Down

0 comments on commit 47e24e0

Please sign in to comment.