Skip to content

Commit

Permalink
net: MultiListener add name label to prometheus metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
mmatczuk committed Nov 8, 2024
1 parent cd53cb9 commit b8ed0f2
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 5 deletions.
9 changes: 4 additions & 5 deletions net.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,17 +197,14 @@ type NamedListenerConfig struct {
}

// MultiListener is a builder for multiple listeners sharing the same prometheus configuration.
// The listener name is added as a label to the metrics.
type MultiListener struct {
ListenerConfigs []NamedListenerConfig
TLSConfig func(NamedListenerConfig) *tls.Config
PromConfig
}

func (ml MultiListener) Listen() (_ []net.Listener, ferr error) {
prototype := Listener{
metrics: newListenerMetrics(ml.PromRegistry, ml.PromNamespace),
}

listeners := make([]net.Listener, 0, len(ml.ListenerConfigs))
defer func() {
if ferr != nil {
Expand All @@ -217,13 +214,15 @@ func (ml MultiListener) Listen() (_ []net.Listener, ferr error) {
}
}()

mf := newListenerMetricsWithNameFunc(ml.PromRegistry, ml.PromNamespace)

for _, lc := range ml.ListenerConfigs {
l := new(Listener)
*l = prototype
l.ListenerConfig = lc.ListenerConfig
if ml.TLSConfig != nil {
l.TLSConfig = ml.TLSConfig(lc)
}
l.metrics = mf(lc.Name)
if err := l.Listen(); err != nil {
return nil, err
}
Expand Down
31 changes: 31 additions & 0 deletions net_metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,34 @@ func (m *listenerMetrics) error() {
func (m *listenerMetrics) close() {
m.closed.Inc()
}

func newListenerMetricsWithNameFunc(r prometheus.Registerer, namespace string) func(name string) *listenerMetrics {
if r == nil {
r = prometheus.NewRegistry() // This registry will be discarded.
}
f := promauto.With(r)

accepted := f.NewCounterVec(prometheus.CounterOpts{
Name: "listener_accepted_total",
Namespace: namespace,
Help: "Number of accepted connections",
}, []string{"name"})
errors := f.NewCounterVec(prometheus.CounterOpts{
Name: "listener_errors_total",
Namespace: namespace,
Help: "Number of listener errors when accepting connections",
}, []string{"name"})
closed := f.NewCounterVec(prometheus.CounterOpts{
Name: "listener_closed_total",
Namespace: namespace,
Help: "Number of closed connections",
}, []string{"name"})

return func(name string) *listenerMetrics {
return &listenerMetrics{
accepted: accepted.WithLabelValues(name),
errors: errors.WithLabelValues(name),
closed: closed.WithLabelValues(name),
}
}
}
67 changes: 67 additions & 0 deletions net_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,3 +394,70 @@ func selfSingedCert() *tls.Config {
Certificates: []tls.Certificate{cert},
}
}

func (ml *MultiListener) listenAndWait(t *testing.T) []net.Listener {
t.Helper()

listeners, err := ml.Listen()
if err != nil {
t.Fatal(err)
}
for _, l := range listeners {
for {
if l.Addr() != nil {
break
}
}
}
return listeners
}

func TestMultiListenerMetrics(t *testing.T) {
r := prometheus.NewRegistry()
ml := MultiListener{
ListenerConfigs: []NamedListenerConfig{
{
Name: "a",
ListenerConfig: ListenerConfig{
Address: "localhost:0",
},
},
{
Name: "b",
ListenerConfig: ListenerConfig{
Address: "localhost:0",
},
},
},
PromConfig: PromConfig{
PromNamespace: "test",
PromRegistry: r,
},
}
listeners := ml.listenAndWait(t)
defer func() {
for _, l := range listeners {
l.Close()
}
}()

for _, l := range listeners {
go l.(*Listener).acceptAndCopy() //nolint:forcetypeassert // trust the test
}

for _, l := range listeners {
for range 10 {
conn, err := net.Dial("tcp", l.Addr().String())
if err != nil {
t.Fatalf("net.Dial(): got %v, want no error", err)
}
fmt.Fprintf(conn, "Hello, World!\n")
if _, err := conn.Read(make([]byte, 1)); err != nil {
t.Fatal(err)
}
conn.Close()
}
}

golden.DiffPrometheusMetrics(t, r)
}
12 changes: 12 additions & 0 deletions testdata/TestMultiListenerMetrics.golden.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# HELP test_listener_accepted_total Number of accepted connections
# TYPE test_listener_accepted_total counter
test_listener_accepted_total{name="a"} 10
test_listener_accepted_total{name="b"} 10
# HELP test_listener_closed_total Number of closed connections
# TYPE test_listener_closed_total counter
test_listener_closed_total{name="a"} 10
test_listener_closed_total{name="b"} 10
# HELP test_listener_errors_total Number of listener errors when accepting connections
# TYPE test_listener_errors_total counter
test_listener_errors_total{name="a"} 0
test_listener_errors_total{name="b"} 0

0 comments on commit b8ed0f2

Please sign in to comment.