Replace hashicorp/go-multierror by own implementation

The own implementation is much easier as it only has to serve our one
use case.
This commit is contained in:
beorn7 2016-08-04 16:03:06 +02:00
parent f0c45acc50
commit 1dc03a72f6
3 changed files with 32 additions and 13 deletions

View File

@ -82,18 +82,18 @@ func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler {
mfs, err := reg.Gather() mfs, err := reg.Gather()
if err != nil { if err != nil {
if opts.ErrorLog != nil { if opts.ErrorLog != nil {
opts.ErrorLog.Println("error collecting metrics:", err) opts.ErrorLog.Println("error gathering metrics:", err)
} }
switch opts.ErrorHandling { switch opts.ErrorHandling {
case PanicOnError: case PanicOnError:
panic(err) panic(err)
case ContinueOnError: case ContinueOnError:
if len(mfs) == 0 { if len(mfs) == 0 {
http.Error(w, "No metrics collected, last error:\n\n"+err.Error(), http.StatusInternalServerError) http.Error(w, "No metrics gathered, last error:\n\n"+err.Error(), http.StatusInternalServerError)
return return
} }
case HTTPErrorOnError: case HTTPErrorOnError:
http.Error(w, "An error has occurred during metrics collection:\n\n"+err.Error(), http.StatusInternalServerError) http.Error(w, "An error has occurred during metrics gathering:\n\n"+err.Error(), http.StatusInternalServerError)
return return
} }
} }

View File

@ -88,14 +88,12 @@ func TestHandlerErrorHandling(t *testing.T) {
ErrorLog: logger, ErrorLog: logger,
ErrorHandling: PanicOnError, ErrorHandling: PanicOnError,
}) })
wantMsg := `error collecting metrics: 1 error(s) occurred: wantMsg := `error gathering metrics: 1 error(s) occurred:
* error collecting metric Desc{fqName: "invalid_metric", help: "not helpful", constLabels: {}, variableLabels: []}: collect error * error collecting metric Desc{fqName: "invalid_metric", help: "not helpful", constLabels: {}, variableLabels: []}: collect error
` `
wantErrorBody := `An error has occurred during metrics collection: wantErrorBody := `An error has occurred during metrics gathering:
1 error(s) occurred: 1 error(s) occurred:
* error collecting metric Desc{fqName: "invalid_metric", help: "not helpful", constLabels: {}, variableLabels: []}: collect error * error collecting metric Desc{fqName: "invalid_metric", help: "not helpful", constLabels: {}, variableLabels: []}: collect error
` `
wantOKBody := `# HELP name docstring wantOKBody := `# HELP name docstring

View File

@ -14,6 +14,7 @@
package prometheus package prometheus
import ( import (
"bytes"
"errors" "errors"
"fmt" "fmt"
"os" "os"
@ -21,7 +22,6 @@ import (
"sync" "sync"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/hashicorp/go-multierror"
dto "github.com/prometheus/client_model/go" dto "github.com/prometheus/client_model/go"
) )
@ -220,6 +220,22 @@ func (err AlreadyRegisteredError) Error() string {
return "duplicate metrics collector registration attempted" return "duplicate metrics collector registration attempted"
} }
// MultiError is a slice of errors implementing the error interface. It is used
// by a Gatherer to report multiple errors during MetricFamily gathering.
type MultiError []error
func (errs MultiError) Error() string {
if len(errs) == 0 {
return ""
}
buf := &bytes.Buffer{}
fmt.Fprintf(buf, "%d error(s) occurred:", len(errs))
for _, err := range errs {
fmt.Fprintf(buf, "\n* %s", err)
}
return buf.String()
}
// Registry registers Prometheus collectors, collects their metrics, and gathers // Registry registers Prometheus collectors, collects their metrics, and gathers
// them into MetricFamilies for exposition. It implements Registerer and // them into MetricFamilies for exposition. It implements Registerer and
// Gatherer. The zero value is not usable. Create instances with NewRegistry or // Gatherer. The zero value is not usable. Create instances with NewRegistry or
@ -366,7 +382,7 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) {
metricChan = make(chan Metric, capMetricChan) metricChan = make(chan Metric, capMetricChan)
metricHashes = map[uint64]struct{}{} metricHashes = map[uint64]struct{}{}
wg sync.WaitGroup wg sync.WaitGroup
errs error // The collected errors to return in the end. errs MultiError // The collected errors to return in the end.
registeredDescIDs map[uint64]struct{} // Only used for pedantic checks registeredDescIDs map[uint64]struct{} // Only used for pedantic checks
) )
@ -419,7 +435,7 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) {
} }
dtoMetric := &dto.Metric{} dtoMetric := &dto.Metric{}
if err := metric.Write(dtoMetric); err != nil { if err := metric.Write(dtoMetric); err != nil {
errs = multierror.Append(errs, fmt.Errorf( errs = append(errs, fmt.Errorf(
"error collecting metric %v: %s", desc, err, "error collecting metric %v: %s", desc, err,
)) ))
continue continue
@ -438,13 +454,13 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) {
case dtoMetric.Histogram != nil: case dtoMetric.Histogram != nil:
metricFamily.Type = dto.MetricType_HISTOGRAM.Enum() metricFamily.Type = dto.MetricType_HISTOGRAM.Enum()
default: default:
errs = multierror.Append(errs, fmt.Errorf( errs = append(errs, fmt.Errorf(
"empty metric collected: %s", dtoMetric, "empty metric collected: %s", dtoMetric,
)) ))
continue continue
} }
if err := r.checkConsistency(metricFamily, dtoMetric, desc, metricHashes, registeredDescIDs); err != nil { if err := r.checkConsistency(metricFamily, dtoMetric, desc, metricHashes, registeredDescIDs); err != nil {
errs = multierror.Append(errs, err) errs = append(errs, err)
continue continue
} }
metricFamily.Metric = append(metricFamily.Metric, dtoMetric) metricFamily.Metric = append(metricFamily.Metric, dtoMetric)
@ -464,7 +480,7 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) {
} }
for _, m := range mf.Metric { for _, m := range mf.Metric {
if err := r.checkConsistency(existingMF, m, nil, metricHashes, nil); err != nil { if err := r.checkConsistency(existingMF, m, nil, metricHashes, nil); err != nil {
errs = multierror.Append(errs, err) errs = append(errs, err)
continue continue
} }
existingMF.Metric = append(existingMF.Metric, m) existingMF.Metric = append(existingMF.Metric, m)
@ -493,6 +509,11 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) {
for _, name := range names { for _, name := range names {
result = append(result, metricFamiliesByName[name]) result = append(result, metricFamiliesByName[name])
} }
// We cannot just `return result, errs`. Even if errs == nil, it will
// not be seen as nil through the error interface.
if len(errs) == 0 {
return result, nil
}
return result, errs return result, errs
} }