Skip to content

Commit

Permalink
Merge pull request #4 from cloudflare/allow_dynamic_target
Browse files Browse the repository at this point in the history
Allow OpenTSDB URL to be set at scrape time
  • Loading branch information
mattbostock authored Jun 29, 2017
2 parents 4c033e2 + 96f3290 commit 7ba7191
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 27 deletions.
64 changes: 38 additions & 26 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,27 @@ import (
"time"

"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/prometheus/common/log"
)

const applicationName = "opentsdb_exporter"
const (
applicationName = "opentsdb_exporter"
metricsRoute = "/metrics"
probeRoute = "/opentsdb"
)

var (
nameSanitiser = strings.NewReplacer("tsd.", "opentsdb_", ".", "_", "-", "_")
revision = "unknown"

versionString = fmt.Sprintf("%s %s (%s)", applicationName, revision, runtime.Version())
showVersion = flag.Bool("version", false, "Print version information.")
listenAddress = flag.String("web.listen-address", ":9250", "Address to listen on for web interface and telemetry.")
timeout = flag.Duration("opentsdb.timeout", 5*time.Second, "Timeout for HTTP requests to OpenTSDB.")
)

func main() {
var (
versionString = fmt.Sprintf("%s %s (%s)", applicationName, revision, runtime.Version())
showVersion = flag.Bool("version", false, "Print version information.")
listenAddress = flag.String("web.listen-address", ":9250", "Address to listen on for web interface and telemetry.")
metricsPath = flag.String("web.telemetry-path", "/metrics", "Path under which to expose metrics.")
url = flag.String("opentsdb.url", "http://localhost:4242", "HTTP URL for OpenTSDB server to monitor.")
timeout = flag.Duration("opentsdb.timeout", 5*time.Second, "Timeout for HTTP requests to OpenTSDB.")
)

flag.Parse()

Expand All @@ -41,16 +43,15 @@ func main() {

log.Infoln("Starting", versionString)

exporter := newExporter(*url, *timeout)
prometheus.MustRegister(exporter)

http.Handle(*metricsPath, prometheus.Handler())
http.Handle(metricsRoute, promhttp.Handler())
http.HandleFunc("/opentsdb", handler)
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`<html>
<head><title>OpenTSDB Exporter</title></head>
<body>
<h1>` + versionString + `</h1>
<p><a href='` + *metricsPath + `'>Metrics</a></p>
<p><a href='` + metricsRoute + `'>Metrics</a></p>
<p><a href='` + probeRoute + `?target=http://opentsdb.localhost'>Example OpenTSDB probe</a></p>
</body>
</html>`))
})
Expand All @@ -65,26 +66,37 @@ func main() {
log.Fatal(s.ListenAndServe())
}

type exporter struct {
url string
type collector struct {
target string
timeout time.Duration
}

func newExporter(url string, timeout time.Duration) *exporter {
return &exporter{url, timeout}
func handler(w http.ResponseWriter, r *http.Request) {
target := r.URL.Query().Get("target")
if target == "" {
http.Error(w, "'target' parameter must be specified", 400)
return
}

log.Debugf("Scraping target %q", target)
registry := prometheus.NewRegistry()
registry.MustRegister(&collector{target: target, timeout: *timeout})

h := promhttp.HandlerFor(registry, promhttp.HandlerOpts{})
h.ServeHTTP(w, r)
}

func (e *exporter) Collect(ch chan<- prometheus.Metric) {
metrics, err := e.queryOpenTSDB()
func (c *collector) Collect(ch chan<- prometheus.Metric) {
metrics, err := c.queryOpenTSDB()
if err != nil {
log.Errorf("Error scraping target %s: %s", e.url, err)
log.Errorf("Error scraping target %s: %s", c.target, err)
ch <- prometheus.NewInvalidMetric(prometheus.NewDesc("api_error", "Error scraping target", nil, nil), err)
return
}
for _, m := range *metrics {
value, err := m.Value.Float64()
if err != nil {
log.Errorf("Error scraping target %s: %s", e.url, err)
log.Errorf("Error scraping target %s: %s", c.target, err)
ch <- prometheus.NewInvalidMetric(prometheus.NewDesc("api_error", "Error scraping target", nil, nil), err)
return
}
Expand All @@ -109,17 +121,17 @@ func (e *exporter) Collect(ch chan<- prometheus.Metric) {
}
}

func (e *exporter) Describe(ch chan<- *prometheus.Desc) {
func (c *collector) Describe(ch chan<- *prometheus.Desc) {
// Copied from https://github.com/prometheus/snmp_exporter/blob/bc4b0a4db1e22c5379f7fdb3f314dbb58a48c637/collector.go#L118
ch <- prometheus.NewDesc("dummy", "dummy", nil, nil)
}

func (e *exporter) queryOpenTSDB() (m *metrics, err error) {
func (c *collector) queryOpenTSDB() (m *metrics, err error) {
client := &http.Client{
Timeout: e.timeout,
Timeout: c.timeout,
}

resp, err := client.Get(e.url + "/api/stats")
resp, err := client.Get(c.target + "/api/stats")
if err != nil {
return m, err
}
Expand Down
2 changes: 1 addition & 1 deletion main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func TestHappyPath(t *testing.T) {
}))
defer ts.Close()

e := newExporter(ts.URL, 5*time.Second)
e := &collector{target: ts.URL, timeout: 5 * time.Second}
ch := make(chan prometheus.Metric)
go e.Collect(ch)

Expand Down

0 comments on commit 7ba7191

Please sign in to comment.