mirror of
https://github.com/kubernetes-sigs/external-dns.git
synced 2025-08-05 17:16:59 +02:00
chore(metrics): Updating so that request duration uses the common metrics registry. (#5677)
This commit is contained in:
parent
7857f71d31
commit
0e7c3af221
@ -26,6 +26,7 @@ curl https://localhost:7979/metrics
|
|||||||
| last_sync_timestamp_seconds | Gauge | controller | Timestamp of last successful sync with the DNS provider |
|
| last_sync_timestamp_seconds | Gauge | controller | Timestamp of last successful sync with the DNS provider |
|
||||||
| no_op_runs_total | Counter | controller | Number of reconcile loops ending up with no changes on the DNS provider side. |
|
| no_op_runs_total | Counter | controller | Number of reconcile loops ending up with no changes on the DNS provider side. |
|
||||||
| verified_records | Gauge | controller | Number of DNS records that exists both in source and registry (vector). |
|
| verified_records | Gauge | controller | Number of DNS records that exists both in source and registry (vector). |
|
||||||
|
| request_duration_seconds | Summaryvec | http | The HTTP request latencies in seconds. |
|
||||||
| cache_apply_changes_calls | Counter | provider | Number of calls to the provider cache ApplyChanges. |
|
| cache_apply_changes_calls | Counter | provider | Number of calls to the provider cache ApplyChanges. |
|
||||||
| cache_records_calls | Counter | provider | Number of calls to the provider cache Records list. |
|
| cache_records_calls | Counter | provider | Number of calls to the provider cache Records list. |
|
||||||
| endpoints_total | Gauge | registry | Number of Endpoints in the registry |
|
| endpoints_total | Gauge | registry | Number of Endpoints in the registry |
|
||||||
@ -76,7 +77,6 @@ curl https://localhost:7979/metrics
|
|||||||
| go_memstats_sys_bytes |
|
| go_memstats_sys_bytes |
|
||||||
| go_sched_gomaxprocs_threads |
|
| go_sched_gomaxprocs_threads |
|
||||||
| go_threads |
|
| go_threads |
|
||||||
| http_request_duration_seconds |
|
|
||||||
| process_cpu_seconds_total |
|
| process_cpu_seconds_total |
|
||||||
| process_max_fds |
|
| process_max_fds |
|
||||||
| process_network_receive_bytes_total |
|
| process_network_receive_bytes_total |
|
||||||
|
@ -37,7 +37,7 @@ func TestComputeMetrics(t *testing.T) {
|
|||||||
t.Errorf("Expected not empty metrics registry, got %d", len(reg.Metrics))
|
t.Errorf("Expected not empty metrics registry, got %d", len(reg.Metrics))
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Len(t, reg.Metrics, 20)
|
assert.Len(t, reg.Metrics, 21)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGenerateMarkdownTableRenderer(t *testing.T) {
|
func TestGenerateMarkdownTableRenderer(t *testing.T) {
|
||||||
|
@ -21,14 +21,15 @@ package http
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
|
||||||
|
"sigs.k8s.io/external-dns/pkg/metrics"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
requestDuration = prometheus.NewSummaryVec(
|
RequestDurationMetric = metrics.NewSummaryVecWithOpts(
|
||||||
prometheus.SummaryOpts{
|
prometheus.SummaryOpts{
|
||||||
Name: "request_duration_seconds",
|
Name: "request_duration_seconds",
|
||||||
Help: "The HTTP request latencies in seconds.",
|
Help: "The HTTP request latencies in seconds.",
|
||||||
@ -41,7 +42,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
prometheus.MustRegister(requestDuration)
|
metrics.RegisterMetric.MustRegister(RequestDurationMetric)
|
||||||
}
|
}
|
||||||
|
|
||||||
type CustomRoundTripper struct {
|
type CustomRoundTripper struct {
|
||||||
@ -61,15 +62,8 @@ func (r *CustomRoundTripper) RoundTrip(req *http.Request) (*http.Response, error
|
|||||||
if resp != nil {
|
if resp != nil {
|
||||||
status = fmt.Sprintf("%d", resp.StatusCode)
|
status = fmt.Sprintf("%d", resp.StatusCode)
|
||||||
}
|
}
|
||||||
|
RequestDurationMetric.SetWithLabels(time.Since(start).Seconds(), req.URL.Scheme, req.URL.Host, metrics.PathProcessor(req.URL.Path), req.Method, status)
|
||||||
|
|
||||||
labels := prometheus.Labels{
|
|
||||||
"scheme": req.URL.Scheme,
|
|
||||||
"host": req.URL.Host,
|
|
||||||
"path": pathProcessor(req.URL.Path),
|
|
||||||
"method": req.Method,
|
|
||||||
"status": status,
|
|
||||||
}
|
|
||||||
requestDuration.With(labels).Observe(time.Since(start).Seconds())
|
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,8 +84,3 @@ func NewInstrumentedTransport(next http.RoundTripper) http.RoundTripper {
|
|||||||
|
|
||||||
return &CustomRoundTripper{next: next}
|
return &CustomRoundTripper{next: next}
|
||||||
}
|
}
|
||||||
|
|
||||||
func pathProcessor(path string) string {
|
|
||||||
parts := strings.Split(path, "/")
|
|
||||||
return parts[len(parts)-1]
|
|
||||||
}
|
|
||||||
|
@ -57,25 +57,3 @@ func TestNewInstrumentedClient(t *testing.T) {
|
|||||||
_, ok = result2.Transport.(*CustomRoundTripper)
|
_, ok = result2.Transport.(*CustomRoundTripper)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPathProcessor(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
input string
|
|
||||||
expected string
|
|
||||||
}{
|
|
||||||
{"/foo/bar", "bar"},
|
|
||||||
{"/foo/", ""},
|
|
||||||
{"/", ""},
|
|
||||||
{"", ""},
|
|
||||||
{"/foo/bar/baz", "baz"},
|
|
||||||
{"foo/bar", "bar"},
|
|
||||||
{"foo", "foo"},
|
|
||||||
{"foo/", ""},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.input, func(t *testing.T) {
|
|
||||||
require.Equal(t, tt.expected, pathProcessor(tt.input))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -73,7 +73,7 @@ func NewMetricsRegister() *MetricRegistry {
|
|||||||
// }
|
// }
|
||||||
func (m *MetricRegistry) MustRegister(cs IMetric) {
|
func (m *MetricRegistry) MustRegister(cs IMetric) {
|
||||||
switch v := cs.(type) {
|
switch v := cs.(type) {
|
||||||
case CounterMetric, GaugeMetric, CounterVecMetric, GaugeVecMetric, GaugeFuncMetric:
|
case CounterMetric, GaugeMetric, SummaryVecMetric, CounterVecMetric, GaugeVecMetric, GaugeFuncMetric:
|
||||||
if _, exists := m.mName[cs.Get().FQDN]; exists {
|
if _, exists := m.mName[cs.Get().FQDN]; exists {
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
@ -85,6 +85,8 @@ func (m *MetricRegistry) MustRegister(cs IMetric) {
|
|||||||
m.Registerer.MustRegister(metric.Counter)
|
m.Registerer.MustRegister(metric.Counter)
|
||||||
case GaugeMetric:
|
case GaugeMetric:
|
||||||
m.Registerer.MustRegister(metric.Gauge)
|
m.Registerer.MustRegister(metric.Gauge)
|
||||||
|
case SummaryVecMetric:
|
||||||
|
m.Registerer.MustRegister(metric.SummaryVec)
|
||||||
case GaugeVecMetric:
|
case GaugeVecMetric:
|
||||||
m.Registerer.MustRegister(metric.Gauge)
|
m.Registerer.MustRegister(metric.Gauge)
|
||||||
case CounterVecMetric:
|
case CounterVecMetric:
|
||||||
|
@ -61,8 +61,9 @@ func TestMustRegister(t *testing.T) {
|
|||||||
NewCounterWithOpts(prometheus.CounterOpts{Name: "test_counter_3"}),
|
NewCounterWithOpts(prometheus.CounterOpts{Name: "test_counter_3"}),
|
||||||
NewCounterVecWithOpts(prometheus.CounterOpts{Name: "test_counter_vec_3"}, []string{"label"}),
|
NewCounterVecWithOpts(prometheus.CounterOpts{Name: "test_counter_vec_3"}, []string{"label"}),
|
||||||
NewGaugedVectorOpts(prometheus.GaugeOpts{Name: "test_gauge_v_3"}, []string{"label"}),
|
NewGaugedVectorOpts(prometheus.GaugeOpts{Name: "test_gauge_v_3"}, []string{"label"}),
|
||||||
|
NewSummaryVecWithOpts(prometheus.SummaryOpts{Name: "test_summary_v_3"}, []string{"label"}),
|
||||||
},
|
},
|
||||||
expected: 4,
|
expected: 5,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "unsupported metric",
|
name: "unsupported metric",
|
||||||
|
@ -176,3 +176,42 @@ func NewGaugeFuncMetric(opts prometheus.GaugeOpts) GaugeFuncMetric {
|
|||||||
GaugeFunc: prometheus.NewGaugeFunc(opts, func() float64 { return 1 }),
|
GaugeFunc: prometheus.NewGaugeFunc(opts, func() float64 { return 1 }),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SummaryVecMetric struct {
|
||||||
|
Metric
|
||||||
|
SummaryVec prometheus.SummaryVec
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SummaryVecMetric) Get() *Metric {
|
||||||
|
return &s.Metric
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetWithLabels sets the value of the SummaryVec metric for the specified label values.
|
||||||
|
// All label values are converted to lowercase before being applied.
|
||||||
|
func (s SummaryVecMetric) SetWithLabels(value float64, lvs ...string) {
|
||||||
|
for i, v := range lvs {
|
||||||
|
lvs[i] = strings.ToLower(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.SummaryVec.WithLabelValues(lvs...).Observe(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSummaryVecWithOpts(opts prometheus.SummaryOpts, labelNames []string) SummaryVecMetric {
|
||||||
|
opts.Namespace = Namespace
|
||||||
|
return SummaryVecMetric{
|
||||||
|
Metric: Metric{
|
||||||
|
Type: "summaryVec",
|
||||||
|
Name: opts.Name,
|
||||||
|
FQDN: fmt.Sprintf("%s_%s", opts.Subsystem, opts.Name),
|
||||||
|
Namespace: opts.Namespace,
|
||||||
|
Subsystem: opts.Subsystem,
|
||||||
|
Help: opts.Help,
|
||||||
|
},
|
||||||
|
SummaryVec: *prometheus.NewSummaryVec(opts, labelNames),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PathProcessor(path string) string {
|
||||||
|
parts := strings.Split(path, "/")
|
||||||
|
return parts[len(parts)-1]
|
||||||
|
}
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_model/go"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewGaugeWithOpts(t *testing.T) {
|
func TestNewGaugeWithOpts(t *testing.T) {
|
||||||
@ -128,3 +129,55 @@ func TestNewBuildInfoCollector(t *testing.T) {
|
|||||||
assert.Equal(t, "external_dns_build_info", reflect.ValueOf(desc).Elem().FieldByName("fqName").String())
|
assert.Equal(t, "external_dns_build_info", reflect.ValueOf(desc).Elem().FieldByName("fqName").String())
|
||||||
assert.Contains(t, desc.String(), "version=\"0.0.1\"")
|
assert.Contains(t, desc.String(), "version=\"0.0.1\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSummaryV_SetWithLabels(t *testing.T) {
|
||||||
|
opts := prometheus.SummaryOpts{
|
||||||
|
Name: "test_summaryVec",
|
||||||
|
Namespace: "test_ns",
|
||||||
|
Subsystem: "test_sub",
|
||||||
|
Help: "help text",
|
||||||
|
}
|
||||||
|
sv := NewSummaryVecWithOpts(opts, []string{"label1", "label2"})
|
||||||
|
|
||||||
|
sv.SetWithLabels(5.01, "Alpha", "BETA")
|
||||||
|
|
||||||
|
reg := prometheus.NewRegistry()
|
||||||
|
reg.MustRegister(sv.SummaryVec)
|
||||||
|
|
||||||
|
metricsFamilies, err := reg.Gather()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, metricsFamilies, 1)
|
||||||
|
|
||||||
|
s, err := sv.SummaryVec.GetMetricWithLabelValues("alpha", "beta")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
metricsFamilies, err = reg.Gather()
|
||||||
|
|
||||||
|
s.Observe(5.21)
|
||||||
|
metricsFamilies, err = reg.Gather()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.InDelta(t, 10.22, *metricsFamilies[0].Metric[0].Summary.SampleSum, 0.01)
|
||||||
|
assert.Len(t, metricsFamilies[0].Metric[0].Label, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPathProcessor(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
input string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{"/foo/bar", "bar"},
|
||||||
|
{"/foo/", ""},
|
||||||
|
{"/", ""},
|
||||||
|
{"", ""},
|
||||||
|
{"/foo/bar/baz", "baz"},
|
||||||
|
{"foo/bar", "bar"},
|
||||||
|
{"foo", "foo"},
|
||||||
|
{"foo/", ""},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.input, func(t *testing.T) {
|
||||||
|
require.Equal(t, tt.expected, PathProcessor(tt.input))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user