Skip to content

Commit

Permalink
Implementing Prometheus Metrics Exporter as in #477
Browse files Browse the repository at this point in the history
Signed-off-by: Flávio Stutz <flaviostutz@gmail.com>
  • Loading branch information
flaviostutz committed Jul 22, 2023
1 parent 3a8efbf commit 7962a87
Show file tree
Hide file tree
Showing 8 changed files with 35 additions and 33 deletions.
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -785,7 +785,7 @@ It'll read and sort them by timestamp before generating reports.
vegeta report *.bin
```

Another way to gather results in distributed tests is to use the built-in Prometheus Exporter and configure a Prometheus Server to get test results from all Vegeta instances. See `attack` option "prom-enable" for more details and a complete example in the section "Prometheus Exporter Support"
Another way to gather results in distributed tests is to use the built-in Prometheus Exporter and configure a Prometheus Server to get test results from all Vegeta instances. See `attack` option "prometheus-url" for more details and a complete example in the section "Prometheus Exporter Support"

## Usage: Real-time Analysis

Expand Down Expand Up @@ -868,7 +868,6 @@ Just pass a new number as the argument to change it.
Vegeta has a built-in Prometheus Exporter that may be enabled during "attacks" so that you can point any Prometheus instance to Vegeta instances and get some metrics about http requests performance and about the Vegeta process itself.

To enable the Prometheus Exporter on the command line, use the "prometheus-url" flag.
To enable Prometheus Exporter on lib usage, add Option "PrometheusEnable" and/or "PrometheusSettings".

A Prometheus HTTP endpoint will be available only during the lifespan of an "attack" and will be closed right after the attack is finished.

Expand Down
7 changes: 4 additions & 3 deletions attack.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,14 +215,15 @@ func attack(opts *attackOpts) (err error) {
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt, syscall.SIGTERM)

return processAttack(atk, res, enc, sig)
return processAttack(atk, res, enc, sig, promMetrics)
}

func processAttack(
atk *vegeta.Attacker,
res <-chan *vegeta.Result,
enc vegeta.Encoder,
sig <-chan os.Signal,
promMetrics *prom.PrometheusMetrics,
) error {
for {
select {
Expand All @@ -235,10 +236,10 @@ func processAttack(
if !ok {
return nil
}
if opts.promURL != "" {
if promMetrics != nil {
promMetrics.Observe(r)
}
if err = enc.Encode(r); err != nil {
if err := enc.Encode(r); err != nil {
return err
}
}
Expand Down
4 changes: 2 additions & 2 deletions attack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func TestAttackSignalOnce(t *testing.T) {
wg.Add(1)
go func() {
defer wg.Done()
processAttack(atk, res, enc, sig)
processAttack(atk, res, enc, sig, nil)
}()

// Allow more than one request to have started before stopping.
Expand Down Expand Up @@ -139,7 +139,7 @@ func TestAttackSignalTwice(t *testing.T) {
wg.Add(1)
go func() {
defer wg.Done()
processAttack(atk, res, enc, sig)
processAttack(atk, res, enc, sig, nil)
}()

// Exit as soon as possible.
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ services:
image: tsenart/vegeta
ports:
- 8880:8880
command: sh -c 'echo "GET https://www.yahoo.com" | vegeta attack -duration=30s -rate=5 -prometheus-enable=true'
command: sh -c 'echo "GET https://www.yahoo.com" | vegeta attack -duration=30s -rate=5 -prometheus-url=0.0.0.0:8880'

prometheus:
image: flaviostutz/prometheus
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ require (
github.com/influxdata/tdigest v0.0.1
github.com/mailru/easyjson v0.7.7
github.com/miekg/dns v1.1.55
github.com/prometheus/client_golang v1.16.0
github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417
github.com/streadway/quantile v0.0.0-20220407130108-4246515d968d
github.com/tsenart/go-tsz v0.0.0-20180814235614-0bd30b3df1c3
Expand All @@ -26,7 +27,6 @@ require (
github.com/iancoleman/orderedmap v0.3.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/prometheus/client_golang v1.16.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.42.0 // indirect
github.com/prometheus/procfs v0.10.1 // indirect
Expand Down
1 change: 0 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417/go.mod h1:qe5TWALJ8/a1
github.com/streadway/quantile v0.0.0-20220407130108-4246515d968d h1:X4+kt6zM/OVO6gbJdAfJR60MGPsqCzbtXNnjoGqdfAs=
github.com/streadway/quantile v0.0.0-20220407130108-4246515d968d/go.mod h1:lbP8tGiBjZ5YWIc2fzuRpTaz0b/53vT6PEs3QuAWzuU=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709 h1:Ko2LQMrRU+Oy/+EDBwX7eZ2jp3C47eDBB8EIhKTun+I=
github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/tsenart/go-tsz v0.0.0-20180814235614-0bd30b3df1c3 h1:pcQGQzTwCg//7FgVywqge1sW9Yf8VMsMdG58MI5kd8s=
github.com/tsenart/go-tsz v0.0.0-20180814235614-0bd30b3df1c3/go.mod h1:SWZznP1z5Ki7hDT2ioqiFKEse8K9tU2OUvaRI0NeGQo=
Expand Down
32 changes: 16 additions & 16 deletions lib/prom/prom.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import (
vegeta "github.com/tsenart/vegeta/v12/lib"
)

//PrometheusMetrics vegeta metrics observer with exposition as Prometheus metrics endpoint
type PrometheusMetrics struct {
// Metrics vegeta metrics observer with exposition as Prometheus metrics endpoint
type Metrics struct {
requestSecondsHistogram *prometheus.HistogramVec
requestBytesInCounter *prometheus.CounterVec
requestBytesOutCounter *prometheus.CounterVec
Expand All @@ -26,18 +26,18 @@ type PrometheusMetrics struct {
registry *prometheus.Registry
}

//NewPrometheusMetrics same as NewPrometheusMetricsWithParams with default params:
func NewPrometheusMetrics() (*PrometheusMetrics, error) {
return NewPrometheusMetricsWithParams("http://0.0.0.0:8880")
// NewMetrics same as NewMetricsWithParams with default params:
func NewMetrics() (*Metrics, error) {
return NewMetricsWithParams("http://0.0.0.0:8880")
}

// NewPrometheusMetricsWithParams creates a new Prometheus Metrics to Observe attack results and expose metrics
// For example, after using NewPrometheusMetricsWithParams("http://0.0.0.0:8880"),
// NewMetricsWithParams creates a new Prometheus Metrics to Observe attack results and expose metrics
// For example, after using NewMetricsWithParams("http://0.0.0.0:8880"),
// during an "attack" you can call "curl http://127.0.0.0:8880" to see current metrics.
// This endpoint can be configured in scrapper section of your Prometheus server.
func NewPrometheusMetricsWithParams(bindURL string) (*PrometheusMetrics, error) {
func NewMetricsWithParams(bindURL string) (*Metrics, error) {

//parse bind url elements
// parse bind url elements
p, err := url.Parse(bindURL)
if err != nil {
return nil, fmt.Errorf("Invalid bindURL %s. Must be in format 'http://0.0.0.0:8880'. err=%s", bindURL, err)
Expand All @@ -47,7 +47,7 @@ func NewPrometheusMetricsWithParams(bindURL string) (*PrometheusMetrics, error)
return nil, fmt.Errorf("Invalid bindURL %s. Must be in format 'http://0.0.0.0:8880'. err=%s", bindURL, err)
}

pm := &PrometheusMetrics{
pm := &Metrics{
registry: prometheus.NewRegistry(),
}

Expand Down Expand Up @@ -92,7 +92,7 @@ func NewPrometheusMetricsWithParams(bindURL string) (*PrometheusMetrics, error)
})
pm.registry.MustRegister(pm.requestFailCounter)

//setup prometheus metrics http server
// setup prometheus metrics http server
pm.srv = http.Server{
Addr: fmt.Sprintf("%s:%s", bindHost, bindPort),
Handler: promhttp.HandlerFor(pm.registry, promhttp.HandlerOpts{}),
Expand All @@ -105,18 +105,18 @@ func NewPrometheusMetricsWithParams(bindURL string) (*PrometheusMetrics, error)
return pm, nil
}

//Close shutdown http server exposing Prometheus metrics and unregister
//all prometheus collectors
func (pm *PrometheusMetrics) Close() error {
// Close shutdown http server exposing Prometheus metrics and unregister
// all prometheus collectors
func (pm *Metrics) Close() error {
prometheus.Unregister(pm.requestSecondsHistogram)
prometheus.Unregister(pm.requestBytesInCounter)
prometheus.Unregister(pm.requestBytesOutCounter)
prometheus.Unregister(pm.requestFailCounter)
return pm.srv.Shutdown(context.Background())
}

//Observe register metrics about hit results
func (pm *PrometheusMetrics) Observe(res *vegeta.Result) {
// Observe register metrics about hit results
func (pm *Metrics) Observe(res *vegeta.Result) {
code := strconv.FormatUint(uint64(res.Code), 10)
pm.requestBytesInCounter.WithLabelValues(res.Method, res.URL, code).Add(float64(res.BytesIn))
pm.requestBytesOutCounter.WithLabelValues(res.Method, res.URL, code).Add(float64(res.BytesOut))
Expand Down
17 changes: 10 additions & 7 deletions lib/prom/prom_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@ import (
"testing"
"time"

"github.com/stretchr/testify/assert"
vegeta "github.com/tsenart/vegeta/v12/lib"
)

func TestPromServerBasic1(t *testing.T) {
pm, err := NewPrometheusMetrics()
pm, err := NewMetrics()
if err != nil {
t.Errorf("Error launching Prometheus http server. err=%s", err)
}
Expand All @@ -24,7 +23,7 @@ func TestPromServerBasic1(t *testing.T) {
}

func TestPromServerBasic2(t *testing.T) {
pm, err := NewPrometheusMetrics()
pm, err := NewMetrics()
if err != nil {
t.Errorf("Error launching Prometheus metrics. err=%s", err)
}
Expand All @@ -33,7 +32,7 @@ func TestPromServerBasic2(t *testing.T) {
t.Errorf("Error stopping Prometheus http server. err=%s", err)
}

pm, err = NewPrometheusMetrics()
pm, err = NewMetrics()
if err != nil {
t.Errorf("Error launching Prometheus metrics. err=%s", err)
}
Expand All @@ -42,7 +41,7 @@ func TestPromServerBasic2(t *testing.T) {
t.Errorf("Error stopping Prometheus http server. err=%s", err)
}

pm, err = NewPrometheusMetrics()
pm, err = NewMetrics()
if err != nil {
t.Errorf("Error launching Prometheus metrics. err=%s", err)
}
Expand All @@ -53,8 +52,12 @@ func TestPromServerBasic2(t *testing.T) {
}

func TestPromServerObserve(t *testing.T) {
pm, err := NewPrometheusMetrics()
assert.Nil(t, err, "Error launching Prometheus http server. err=%s", err)
pm, err := NewMetrics()
if err != nil {
if err != nil {
t.Errorf("Error launching Prometheus http server. err=%s", err)
}
}

r := &vegeta.Result{
URL: "http://test.com/test1",
Expand Down

0 comments on commit 7962a87

Please sign in to comment.