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()
|
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 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
|
// If exposeProcessMetrics is true, then various `go_*` and `process_*` metrics
|
||||||
// are exposed for the current process.
|
// are exposed for the current process.
|
||||||
@ -232,6 +244,8 @@ func UnregisterMetric(name string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UnregisterAllMetrics unregisters all the metrics from default set.
|
// UnregisterAllMetrics unregisters all the metrics from default set.
|
||||||
|
//
|
||||||
|
// It also unregisters writeMetrics callbacks passed to RegisterMetricsWriter.
|
||||||
func UnregisterAllMetrics() {
|
func UnregisterAllMetrics() {
|
||||||
defaultSet.UnregisterAllMetrics()
|
defaultSet.UnregisterAllMetrics()
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package metrics
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"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) {
|
func TestRegisterUnregisterSet(t *testing.T) {
|
||||||
const metricName = "metric_from_set"
|
const metricName = "metric_from_set"
|
||||||
const metricValue = 123
|
const metricValue = 123
|
||||||
|
29
set.go
29
set.go
@ -19,6 +19,8 @@ type Set struct {
|
|||||||
a []*namedMetric
|
a []*namedMetric
|
||||||
m map[string]*namedMetric
|
m map[string]*namedMetric
|
||||||
summaries []*Summary
|
summaries []*Summary
|
||||||
|
|
||||||
|
metricsWriters []func(w io.Writer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSet creates new set of metrics.
|
// NewSet creates new set of metrics.
|
||||||
@ -45,6 +47,7 @@ func (s *Set) WritePrometheus(w io.Writer) {
|
|||||||
sort.Slice(s.a, lessFunc)
|
sort.Slice(s.a, lessFunc)
|
||||||
}
|
}
|
||||||
sa := append([]*namedMetric(nil), s.a...)
|
sa := append([]*namedMetric(nil), s.a...)
|
||||||
|
metricsWriters := s.metricsWriters
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
|
|
||||||
prevMetricFamily := ""
|
prevMetricFamily := ""
|
||||||
@ -61,6 +64,10 @@ func (s *Set) WritePrometheus(w io.Writer) {
|
|||||||
nm.metric.marshalTo(nm.name, &bb)
|
nm.metric.marshalTo(nm.name, &bb)
|
||||||
}
|
}
|
||||||
w.Write(bb.Bytes())
|
w.Write(bb.Bytes())
|
||||||
|
|
||||||
|
for _, writeMetrics := range metricsWriters {
|
||||||
|
writeMetrics(w)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewHistogram creates and returns new histogram in s with the given name.
|
// 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.
|
// UnregisterAllMetrics de-registers all metrics registered in s.
|
||||||
|
//
|
||||||
|
// It also de-registers writeMetrics callbacks passed to RegisterMetricsWriter.
|
||||||
func (s *Set) UnregisterAllMetrics() {
|
func (s *Set) UnregisterAllMetrics() {
|
||||||
metricNames := s.ListMetricNames()
|
metricNames := s.ListMetricNames()
|
||||||
for _, name := range metricNames {
|
for _, name := range metricNames {
|
||||||
s.UnregisterMetric(name)
|
s.UnregisterMetric(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.mu.Lock()
|
||||||
|
s.metricsWriters = nil
|
||||||
|
s.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListMetricNames returns sorted list of all the metrics in s.
|
// 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 {
|
func (s *Set) ListMetricNames() []string {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
@ -544,3 +559,17 @@ func (s *Set) ListMetricNames() []string {
|
|||||||
sort.Strings(metricNames)
|
sort.Strings(metricNames)
|
||||||
return 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