Add Set.RegisterMetricsWriter() function for registering user-defined callbacks for arbitrary metrics generation in Prometheus text exposition format
This commit is contained in:
parent
64b88f0e8f
commit
fdfd428a62
16
metrics.go
16
metrics.go
@ -62,9 +62,21 @@ func UnregisterSet(s *Set) {
|
||||
registeredSetsLock.Unlock()
|
||||
}
|
||||
|
||||
// WritePrometheus writes all the metrics from default set and all the registered sets in Prometheus format to w.
|
||||
// RegisterMetricsWriter registers writeMetrics callback for including metrics in the output generated by WritePrometheus.
|
||||
//
|
||||
// The writeMetrics callback must write metrics to w in Prometheus text exposition format without timestamps and trailing comments.
|
||||
// The last line generated by writeMetrics must end with \n.
|
||||
// See https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md#text-based-format
|
||||
//
|
||||
// It is OK to register multiple writeMetrics callbacks - all of them will be called sequentially for gererating the output at WritePrometheus.
|
||||
func RegisterMetricsWriter(writeMetrics func(w io.Writer)) {
|
||||
defaultSet.RegisterMetricsWriter(writeMetrics)
|
||||
}
|
||||
|
||||
// WritePrometheus writes all the metrics in Prometheus format from the default set, all the added sets and metrics writers to w.
|
||||
//
|
||||
// Additional sets can be registered via RegisterSet() call.
|
||||
// Additional metric writers can be registered via RegisterMetricsWriter() call.
|
||||
//
|
||||
// If exposeProcessMetrics is true, then various `go_*` and `process_*` metrics
|
||||
// are exposed for the current process.
|
||||
@ -232,6 +244,8 @@ func UnregisterMetric(name string) bool {
|
||||
}
|
||||
|
||||
// UnregisterAllMetrics unregisters all the metrics from default set.
|
||||
//
|
||||
// It also unregisters writeMetrics callbacks passed to RegisterMetricsWriter.
|
||||
func UnregisterAllMetrics() {
|
||||
defaultSet.UnregisterAllMetrics()
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package metrics
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@ -108,6 +109,29 @@ func TestUnregisterAllMetrics(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterMetricsWriter(t *testing.T) {
|
||||
RegisterMetricsWriter(func(w io.Writer) {
|
||||
WriteCounterUint64(w, `counter{label="abc"}`, 1234)
|
||||
WriteGaugeFloat64(w, `gauge{a="b",c="d"}`, -34.43)
|
||||
})
|
||||
|
||||
var bb bytes.Buffer
|
||||
WritePrometheus(&bb, false)
|
||||
data := bb.String()
|
||||
|
||||
UnregisterAllMetrics()
|
||||
|
||||
expectedLine := fmt.Sprintf(`counter{label="abc"} 1234` + "\n")
|
||||
if !strings.Contains(data, expectedLine) {
|
||||
t.Fatalf("missing %q in\n%s", expectedLine, data)
|
||||
}
|
||||
|
||||
expectedLine = fmt.Sprintf(`gauge{a="b",c="d"} -34.43` + "\n")
|
||||
if !strings.Contains(data, expectedLine) {
|
||||
t.Fatalf("missing %q in\n%s", expectedLine, data)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterUnregisterSet(t *testing.T) {
|
||||
const metricName = "metric_from_set"
|
||||
const metricValue = 123
|
||||
|
29
set.go
29
set.go
@ -19,6 +19,8 @@ type Set struct {
|
||||
a []*namedMetric
|
||||
m map[string]*namedMetric
|
||||
summaries []*Summary
|
||||
|
||||
metricsWriters []func(w io.Writer)
|
||||
}
|
||||
|
||||
// NewSet creates new set of metrics.
|
||||
@ -45,6 +47,7 @@ func (s *Set) WritePrometheus(w io.Writer) {
|
||||
sort.Slice(s.a, lessFunc)
|
||||
}
|
||||
sa := append([]*namedMetric(nil), s.a...)
|
||||
metricsWriters := s.metricsWriters
|
||||
s.mu.Unlock()
|
||||
|
||||
prevMetricFamily := ""
|
||||
@ -61,6 +64,10 @@ func (s *Set) WritePrometheus(w io.Writer) {
|
||||
nm.metric.marshalTo(nm.name, &bb)
|
||||
}
|
||||
w.Write(bb.Bytes())
|
||||
|
||||
for _, writeMetrics := range metricsWriters {
|
||||
writeMetrics(w)
|
||||
}
|
||||
}
|
||||
|
||||
// NewHistogram creates and returns new histogram in s with the given name.
|
||||
@ -523,14 +530,22 @@ func (s *Set) unregisterMetricLocked(nm *namedMetric) bool {
|
||||
}
|
||||
|
||||
// UnregisterAllMetrics de-registers all metrics registered in s.
|
||||
//
|
||||
// It also de-registers writeMetrics callbacks passed to RegisterMetricsWriter.
|
||||
func (s *Set) UnregisterAllMetrics() {
|
||||
metricNames := s.ListMetricNames()
|
||||
for _, name := range metricNames {
|
||||
s.UnregisterMetric(name)
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
s.metricsWriters = nil
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
||||
// ListMetricNames returns sorted list of all the metrics in s.
|
||||
//
|
||||
// The returned list doesn't include metrics generated by metricsWriter passed to RegisterMetricsWriter.
|
||||
func (s *Set) ListMetricNames() []string {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
@ -544,3 +559,17 @@ func (s *Set) ListMetricNames() []string {
|
||||
sort.Strings(metricNames)
|
||||
return metricNames
|
||||
}
|
||||
|
||||
// RegisterMetricsWriter registers writeMetrics callback for including metrics in the output generated by s.WritePrometheus.
|
||||
//
|
||||
// The writeMetrics callback must write metrics to w in Prometheus text exposition format without timestamps and trailing comments.
|
||||
// The last line generated by writeMetrics must end with \n.
|
||||
// See https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md#text-based-format
|
||||
//
|
||||
// It is OK to reguster multiple writeMetrics callbacks - all of them will be called sequentially for gererating the output at s.WritePrometheus.
|
||||
func (s *Set) RegisterMetricsWriter(writeMetrics func(w io.Writer)) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
s.metricsWriters = append(s.metricsWriters, writeMetrics)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user