Skip to content

Commit

Permalink
Metrics: Add push client to push metrics to endpoint
Browse files Browse the repository at this point in the history
Creates a push client that will be used to push metrics to
Prometheus Aggregation Gateway. The client can be used for
any type of Gateway and it takes in the URL and the HTTP Client
that would have all the necessary information(authentication)
required to push to the gateway.

Configured to take in Prometheus Objects for pushing to gateway.
https://github.com/prometheus/client_golang/tree/master/prometheus
  • Loading branch information
rna-afk committed Jul 6, 2020
1 parent c7d9de6 commit 71c6a0f
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 0 deletions.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ require (
github.com/pierrec/lz4 v2.3.0+incompatible // indirect
github.com/pkg/errors v0.9.1
github.com/pkg/sftp v1.10.1
github.com/prometheus/client_golang v1.5.1
github.com/prometheus/common v0.9.1
github.com/satori/uuid v1.2.0 // indirect
github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd
github.com/sirupsen/logrus v1.5.0
Expand Down
42 changes: 42 additions & 0 deletions pkg/metrics/pushclient/pushclient.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package pushclient

import (
"net/http"

"github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/push"
"github.com/prometheus/common/expfmt"
)

// PushClient is used to send Prometheus metrics objects to any Prometheus
// Push Gateway. It stores the URL and the client that will be used to push
// to the desired gateway.
type PushClient struct {
URL string
Client *http.Client
}

// pushAllToAggregationGateway is a helper that takes care of the actual code that pushes to the prometheus
// aggregation gateway. It takes a list of collectors and pushes all of them to the desired url.
func (p *PushClient) pushAllToAggregationGateway(collectors ...prometheus.Collector) error {
allJobsName := "installer_metrics"
pushClient := push.New(p.URL, allJobsName).Client(p.Client).Format(expfmt.FmtText)

for _, value := range collectors {
pushClient.Collector(value)
}

err := pushClient.Push()
if err != nil {
return errors.Wrap(err, "failed to push metrics")
}
return nil
}

// Push calls the pushAllToAggregationGateway for the all metrics.
// This function acts as a re-router which currently pushes to the aggregation gateway.
// Any change in gateway logic can be written here to route the metrics.
func (p *PushClient) Push(collectors ...prometheus.Collector) error {
return p.pushAllToAggregationGateway(collectors...)
}
97 changes: 97 additions & 0 deletions pkg/metrics/pushclient/pushclient_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package pushclient

import (
"fmt"
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"

"github.com/prometheus/client_golang/prometheus"
"github.com/stretchr/testify/assert"
)

func TestPushMetricsToGateway(t *testing.T) {
promCollector := prometheus.NewCounter(
prometheus.CounterOpts{
Name: "test",
Help: "test metrics",
ConstLabels: map[string]string{"test1": "test1"},
},
)

promCollector.Add(10)

expectedOutput := `# HELP test test metrics
# TYPE test counter
test{test1="test1"} 10
`

testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
buf := new(strings.Builder)
_, err := io.Copy(buf, req.Body)
assert.NoError(t, err)
assert.EqualValues(t, expectedOutput, buf.String())
fmt.Println("all done")
}))
defer testServer.Close()

pushClient := PushClient{URL: testServer.URL, Client: &http.Client{}}
pushClient.Push(promCollector)

}

func TestPushMetricsToAllGateway(t *testing.T) {
counter := prometheus.NewCounter(
prometheus.CounterOpts{
Name: "test_counter",
Help: "test metrics",
ConstLabels: map[string]string{"test1": "test1"},
},
)
counter.Add(10)

histogram := prometheus.NewHistogram(
prometheus.HistogramOpts{
Name: "test_histogram",
Help: "test metrics",
ConstLabels: map[string]string{"test1": "test1"},
},
)
histogram.Observe(10)

promCollector := []prometheus.Collector{counter, histogram}

expectedOutput := `# HELP test_counter test metrics
# TYPE test_counter counter
test_counter{test1="test1"} 10
# HELP test_histogram test metrics
# TYPE test_histogram histogram
test_histogram_bucket{test1="test1",le="0.005"} 0
test_histogram_bucket{test1="test1",le="0.01"} 0
test_histogram_bucket{test1="test1",le="0.025"} 0
test_histogram_bucket{test1="test1",le="0.05"} 0
test_histogram_bucket{test1="test1",le="0.1"} 0
test_histogram_bucket{test1="test1",le="0.25"} 0
test_histogram_bucket{test1="test1",le="0.5"} 0
test_histogram_bucket{test1="test1",le="1"} 0
test_histogram_bucket{test1="test1",le="2.5"} 0
test_histogram_bucket{test1="test1",le="5"} 0
test_histogram_bucket{test1="test1",le="10"} 1
test_histogram_bucket{test1="test1",le="+Inf"} 1
test_histogram_sum{test1="test1"} 10
test_histogram_count{test1="test1"} 1
`

testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
buf := new(strings.Builder)
_, err := io.Copy(buf, req.Body)
assert.NoError(t, err)
assert.EqualValues(t, expectedOutput, buf.String())
fmt.Println("all done")
}))
defer testServer.Close()
pushClient := PushClient{URL: testServer.URL, Client: &http.Client{}}
pushClient.Push(promCollector...)
}

0 comments on commit 71c6a0f

Please sign in to comment.