Skip to content

Commit

Permalink
Implemented ability to add labels to scraped metrics so that end resu…
Browse files Browse the repository at this point in the history
…lt from multiple duplicate pages is valid
  • Loading branch information
warmans committed Apr 27, 2017
1 parent c567924 commit c55f598
Show file tree
Hide file tree
Showing 19 changed files with 165 additions and 220 deletions.
6 changes: 2 additions & 4 deletions config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,5 @@ server:
bind: ":8080"
timeout: 1000 #ms
targets:
- "http://localhost:9100/metrics"
- "http://localhost:9100/metrics"
- "http://localhost:9100/metrics"
- "http://localhost:9100/metrics"
- "http://localhost/prom.txt"
- "http://localhost/prom2.txt"
10 changes: 10 additions & 0 deletions fixture/histogram.golden.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# HELP http_request_duration_seconds A histogram of the request duration.
# TYPE http_request_duration_seconds histogram
http_request_duration_seconds_bucket{ae_source="foo",le="0.05"} 24054
http_request_duration_seconds_bucket{ae_source="foo",le="0.1"} 33444
http_request_duration_seconds_bucket{ae_source="foo",le="0.2"} 100392
http_request_duration_seconds_bucket{ae_source="foo",le="0.5"} 129389
http_request_duration_seconds_bucket{ae_source="foo",le="1"} 133988
http_request_duration_seconds_bucket{ae_source="foo",le="+Inf"} 144320
http_request_duration_seconds_sum{ae_source="foo"} 53423
http_request_duration_seconds_count{ae_source="foo"} 144320
9 changes: 9 additions & 0 deletions fixture/histogram.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# HELP http_requests_total The total number of HTTP requests.
# TYPE http_requests_total counter
http_requests_total{method="post",code="200"} 1027 1395066363000
http_requests_total{method="post",code="400"} 3 1395066363000

# HELP http_requests_total The total number of HTTP requests.
# TYPE http_requests_total counter
http_requests_total{method="post",code="200"} 1027 1395066363000
http_requests_total{method="post",code="400"} 3 1395066363000
26 changes: 21 additions & 5 deletions glide.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions glide.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
package: github.com/warmans/prometheus-aggregate-exporter
import:
- package: gopkg.in/yaml.v2
- package: github.com/prometheus/common
66 changes: 50 additions & 16 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,21 @@ import (
"net/http"
"strconv"
"time"

"github.com/prometheus/client_model/go"
"github.com/prometheus/common/expfmt"
)

var (
Version = "unknown"
Version = "unknown"
)

var (
configPathFlag = flag.String("config", "config.yml", "Path to config YAML file.")
verboseFlag = flag.Bool("verbose", false, "Log more information")
versionFlag = flag.Bool("version", false, "Show version and exit")
verboseFlag = flag.Bool("verbose", false, "Log more information")
versionFlag = flag.Bool("version", false, "Show version and exit")
appendLabel = flag.Bool("label", false, "Add a label to metrics to show their origin target")
labelName = flag.String("label.name", "ae_source", "Label name to use if a target name label is appended to metrics")
)

type Config struct {
Expand Down Expand Up @@ -85,7 +90,7 @@ func main() {
type Result struct {
URL string
SecondsTaken float64
Payload io.ReadCloser
MetricFamily map[string]*io_prometheus_client.MetricFamily
Error error
}

Expand All @@ -102,10 +107,14 @@ func (f *Aggregator) Aggregate(targets []string, output io.Writer) {
}

func(numTargets int, resultChan chan *Result) {

numResuts := 0

allFamilies := make(map[string]*io_prometheus_client.MetricFamily)

for {
if numTargets == numResuts {
return
break
}
select {
case result := <-resultChan:
Expand All @@ -116,34 +125,59 @@ func (f *Aggregator) Aggregate(targets []string, output io.Writer) {
continue
}

_, err := io.Copy(output, result.Payload)
if err != nil {
log.Printf("Copy error: %s", err.Error())
for mfName, mf := range result.MetricFamily {
if *appendLabel {
for _, m := range mf.Metric {
m.Label = append(m.Label, &io_prometheus_client.LabelPair{Name: labelName, Value: &result.URL})
}
}
if existingMf, ok := allFamilies[mfName]; ok {
for _, m := range mf.Metric {
existingMf.Metric = append(existingMf.Metric, m)
}
} else {
allFamilies[*mf.Name] = mf
}
}

err = result.Payload.Close()
if err != nil {
log.Printf("Result body close error: %s", err.Error())
}

if *verboseFlag {
log.Printf("OK: %s was refreshed in %.3f seconds", result.URL, result.SecondsTaken)
}
}
}

encoder := expfmt.NewEncoder(output, expfmt.FmtText)
for _, f := range allFamilies {
encoder.Encode(f)
}

}(len(targets), resultChan)
}

func (f *Aggregator) fetch(target string, resultChan chan *Result) {

startTime := time.Now()
res, err := f.HTTP.Get(target)

result := &Result{URL: target, SecondsTaken: time.Since(startTime).Seconds(), Error: nil}
if res != nil {
result.Payload = res.Body
result.MetricFamily, err = getMetricFamilies(res.Body)
if err != nil {
result.Error = fmt.Errorf("failed to add labels to target %s metrics: %s", target, err.Error())
resultChan <- result
return
}
}
if err != nil {
result.Error = fmt.Errorf("Failed to fetch URL %s due to error: %s", target, err.Error())
result.Error = fmt.Errorf("failed to fetch URL %s due to error: %s", target, err.Error())
}
resultChan <- result
}

func getMetricFamilies(sourceData io.Reader) (map[string]*io_prometheus_client.MetricFamily, error) {
parser := expfmt.TextParser{}
metricFamiles, err := parser.TextToMetricFamilies(sourceData)
if err != nil {
return nil, err
}
return metricFamiles, nil
}
36 changes: 36 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package main

import (
"flag"
"fmt"
"io"
"io/ioutil"
"os"
"testing"
)

var updateGoldenFile = flag.Bool("update.golden", false, "update golden files")

func TestMain(m *testing.M) {

flag.Parse()
os.Exit(m.Run())
}

func mustOpenFile(name string, flag int) *os.File {
file, err := os.OpenFile(fmt.Sprintf("fixture/%s", name), flag, 0666)
if err != nil {
panic(err)
}
return file
}

func mustReadAll(r io.Reader) string {
b, err := ioutil.ReadAll(r)
if err != nil {
panic("failed to readall reader: " + err.Error())
}
return string(b[:])
}

//todo: re-implement tests
1 change: 1 addition & 0 deletions vendor/github.com/golang/protobuf
Submodule protobuf added at 2bba06
1 change: 1 addition & 0 deletions vendor/github.com/matttproud/golang_protobuf_extensions
Submodule golang_protobuf_extensions added at c12348
1 change: 1 addition & 0 deletions vendor/github.com/prometheus/client_model
Submodule client_model added at 6f3806
1 change: 1 addition & 0 deletions vendor/github.com/prometheus/common
Submodule common added at 13ba4d
Loading

0 comments on commit c55f598

Please sign in to comment.