From f3cda15667b36859c49cd1dd2c42f38be164ef5d Mon Sep 17 00:00:00 2001 From: beorn7 Date: Sun, 15 Mar 2015 19:29:57 +0100 Subject: [PATCH] Add functions to push individual collectors to a Pushgateway. Move all Pushgateway related top-level functions to push.go. --- prometheus/examples_test.go | 18 ++++++++++ prometheus/push.go | 65 +++++++++++++++++++++++++++++++++++++ prometheus/registry.go | 35 +++++--------------- 3 files changed, 92 insertions(+), 26 deletions(-) create mode 100644 prometheus/push.go diff --git a/prometheus/examples_test.go b/prometheus/examples_test.go index 5e62967..d106c42 100644 --- a/prometheus/examples_test.go +++ b/prometheus/examples_test.go @@ -18,8 +18,10 @@ import ( "fmt" "math" "net/http" + "os" "runtime" "sort" + "time" dto "github.com/prometheus/client_model/go" @@ -498,3 +500,19 @@ func ExampleHistogram() { // > // > } + +func ExamplePushCollectors() { + hostname, _ := os.Hostname() + completionTime := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "db_backup_last_completion_time", + Help: "The timestamp of the last succesful completion of a DB backup.", + }) + completionTime.Set(float64(time.Now().Unix())) + if err := prometheus.PushCollectors( + "db_backup", hostname, + "http://pushgateway:9091", + completionTime, + ); err != nil { + fmt.Println("Could not push completion time to Pushgateway:", err) + } +} diff --git a/prometheus/push.go b/prometheus/push.go new file mode 100644 index 0000000..1c33848 --- /dev/null +++ b/prometheus/push.go @@ -0,0 +1,65 @@ +// Copyright 2015 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright (c) 2013, The Prometheus Authors +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be found +// in the LICENSE file. + +package prometheus + +// Push triggers a metric collection by the default registry and pushes all +// collected metrics to the Pushgateway specified by addr. See the Pushgateway +// documentation for detailed implications of the job and instance +// parameter. instance can be left empty. You can use just host:port or ip:port +// as url, in which case 'http://' is added automatically. You can also include +// the schema in the URL. However, do not include the '/metrics/jobs/...' part. +// +// Note that all previously pushed metrics with the same job and instance will +// be replaced with the metrics pushed by this call. (It uses HTTP method 'PUT' +// to push to the Pushgateway.) +func Push(job, instance, url string) error { + return defRegistry.Push(job, instance, url, "PUT") +} + +// PushAdd works like Push, but only previously pushed metrics with the same +// name (and the same job and instance) will be replaced. (It uses HTTP method +// 'POST' to push to the Pushgateway.) +func PushAdd(job, instance, url string) error { + return defRegistry.Push(job, instance, url, "POST") +} + +// PushCollectors works like Push, but it does not collect from the default +// registry. Instead, it collects from the provided collectors. It is a +// convenient way to push only a few metrics. +func PushCollectors(job, instance, url string, collectors ...Collector) error { + return pushCollectors(job, instance, url, "PUT", collectors...) +} + +// PushAddCollectors works like PushAdd, but it does not collect from the +// default registry. Instead, it collects from the provided collectors. It is a +// convenient way to push only a few metrics. +func PushAddCollectors(job, instance, url string, collectors ...Collector) error { + return pushCollectors(job, instance, url, "POST", collectors...) +} + +func pushCollectors(job, instance, url, method string, collectors ...Collector) error { + r := newRegistry() + for _, collector := range collectors { + if _, err := r.Register(collector); err != nil { + return err + } + } + return r.Push(job, instance, url, method) +} diff --git a/prometheus/registry.go b/prometheus/registry.go index 5507541..4cc26d9 100644 --- a/prometheus/registry.go +++ b/prometheus/registry.go @@ -158,7 +158,7 @@ func Unregister(c Collector) bool { // SetMetricFamilyInjectionHook sets a function that is called whenever metrics // are collected. The hook function must be set before metrics collection begins // (i.e. call SetMetricFamilyInjectionHook before setting the HTTP handler.) The -// MetricFamily protobufs returned by the hook function are added to the +// MetricFamily protobufs returned by the hook function areadded to the // delivered metrics. Each returned MetricFamily must have a unique name (also // taking into account the MetricFamilies created in the regular way). // @@ -187,26 +187,6 @@ func EnableCollectChecks(b bool) { defRegistry.collectChecksEnabled = b } -// Push triggers a metric collection and pushes all collected metrics to the -// Pushgateway specified by addr. See the Pushgateway documentation for detailed -// implications of the job and instance parameter. instance can be left -// empty. The Pushgateway will then use the client's IP number instead. Use just -// host:port or ip:port ass addr. (Don't add 'http://' or any path.) -// -// Note that all previously pushed metrics with the same job and instance will -// be replaced with the metrics pushed by this call. (It uses HTTP method 'PUT' -// to push to the Pushgateway.) -func Push(job, instance, addr string) error { - return defRegistry.Push(job, instance, addr, "PUT") -} - -// PushAdd works like Push, but only previously pushed metrics with the same -// name (and the same job and instance) will be replaced. (It uses HTTP method -// 'POST' to push to the Pushgateway.) -func PushAdd(job, instance, addr string) error { - return defRegistry.Push(job, instance, addr, "POST") -} - // encoder is a function that writes a dto.MetricFamily to an io.Writer in a // certain encoding. It returns the number of bytes written and any error // encountered. Note that ext.WriteDelimited and text.MetricFamilyToText are @@ -346,10 +326,13 @@ func (r *registry) Unregister(c Collector) bool { return true } -func (r *registry) Push(job, instance, addr, method string) error { - u := fmt.Sprintf("http://%s/metrics/jobs/%s", addr, url.QueryEscape(job)) +func (r *registry) Push(job, instance, pushURL, method string) error { + if !strings.Contains(pushURL, "://") { + pushURL = "http://" + pushURL + } + pushURL = fmt.Sprintf("%s/metrics/jobs/%s", pushURL, url.QueryEscape(job)) if instance != "" { - u += "/instances/" + url.QueryEscape(instance) + pushURL += "/instances/" + url.QueryEscape(instance) } buf := r.getBuf() defer r.giveBuf(buf) @@ -359,7 +342,7 @@ func (r *registry) Push(job, instance, addr, method string) error { } return err } - req, err := http.NewRequest(method, u, buf) + req, err := http.NewRequest(method, pushURL, buf) if err != nil { return err } @@ -370,7 +353,7 @@ func (r *registry) Push(job, instance, addr, method string) error { } defer resp.Body.Close() if resp.StatusCode != 202 { - return fmt.Errorf("unexpected status code %d while pushing to %s", resp.StatusCode, u) + return fmt.Errorf("unexpected status code %d while pushing to %s", resp.StatusCode, pushURL) } return nil }