Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

metrics: add options to disable metrics and to set Prometheus registerer #2116

Merged
merged 2 commits into from
Feb 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 24 additions & 13 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
relayv2 "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay"
"github.com/libp2p/go-libp2p/p2p/protocol/holepunch"
"github.com/libp2p/go-libp2p/p2p/transport/quicreuse"
"github.com/prometheus/client_golang/prometheus"

ma "github.com/multiformats/go-multiaddr"
madns "github.com/multiformats/go-multiaddr-dns"
Expand Down Expand Up @@ -117,6 +118,9 @@ type Config struct {

EnableHolePunching bool
HolePunchingOptions []holepunch.Option

DisableMetrics bool
PrometheusRegisterer prometheus.Registerer
}

func (cfg *Config) makeSwarm(enableMetrics bool) (*swarm.Swarm, error) {
Expand Down Expand Up @@ -168,7 +172,8 @@ func (cfg *Config) makeSwarm(enableMetrics bool) (*swarm.Swarm, error) {
opts = append(opts, swarm.WithMultiaddrResolver(cfg.MultiaddrResolver))
}
if enableMetrics {
opts = append(opts, swarm.WithMetricsTracer(swarm.NewMetricsTracer()))
opts = append(opts,
swarm.WithMetricsTracer(swarm.NewMetricsTracer(swarm.WithRegisterer(cfg.PrometheusRegisterer))))
}
// TODO: Make the swarm implementation configurable.
return swarm.NewSwarm(pid, cfg.Peerstore, opts...)
Expand Down Expand Up @@ -279,22 +284,24 @@ func (cfg *Config) addTransports(h host.Host) error {
//
// This function consumes the config. Do not reuse it (really!).
func (cfg *Config) NewNode() (host.Host, error) {
swrm, err := cfg.makeSwarm(true)
swrm, err := cfg.makeSwarm(!cfg.DisableMetrics)
if err != nil {
return nil, err
}

h, err := bhost.NewHost(swrm, &bhost.HostOpts{
ConnManager: cfg.ConnManager,
AddrsFactory: cfg.AddrsFactory,
NATManager: cfg.NATManager,
EnablePing: !cfg.DisablePing,
UserAgent: cfg.UserAgent,
ProtocolVersion: cfg.ProtocolVersion,
EnableHolePunching: cfg.EnableHolePunching,
HolePunchingOptions: cfg.HolePunchingOptions,
EnableRelayService: cfg.EnableRelayService,
RelayServiceOpts: cfg.RelayServiceOpts,
ConnManager: cfg.ConnManager,
AddrsFactory: cfg.AddrsFactory,
NATManager: cfg.NATManager,
EnablePing: !cfg.DisablePing,
UserAgent: cfg.UserAgent,
ProtocolVersion: cfg.ProtocolVersion,
EnableHolePunching: cfg.EnableHolePunching,
HolePunchingOptions: cfg.HolePunchingOptions,
EnableRelayService: cfg.EnableRelayService,
RelayServiceOpts: cfg.RelayServiceOpts,
EnableMetrics: !cfg.DisableMetrics,
PrometheusRegisterer: cfg.PrometheusRegisterer,
})
if err != nil {
swrm.Close()
Expand Down Expand Up @@ -354,7 +361,11 @@ func (cfg *Config) NewNode() (host.Host, error) {
autonat.UsingAddresses(func() []ma.Multiaddr {
return addrF(h.AllAddrs())
}),
autonat.WithMetricsTracer(autonat.NewMetricsTracer()),
}
if !cfg.DisableMetrics {
autonatOpts = append(autonatOpts,
autonat.WithMetricsTracer(
autonat.NewMetricsTracer(autonat.WithRegisterer(cfg.PrometheusRegisterer))))
}
if cfg.AutoNATConfig.ThrottleInterval != 0 {
autonatOpts = append(autonatOpts,
Expand Down
10 changes: 10 additions & 0 deletions defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/libp2p/go-libp2p/p2p/transport/tcp"
ws "github.com/libp2p/go-libp2p/p2p/transport/websocket"
webtransport "github.com/libp2p/go-libp2p/p2p/transport/webtransport"
"github.com/prometheus/client_golang/prometheus"

"github.com/multiformats/go-multiaddr"
madns "github.com/multiformats/go-multiaddr-dns"
Expand Down Expand Up @@ -129,6 +130,11 @@ var DefaultMultiaddrResolver = func(cfg *Config) error {
return cfg.Apply(MultiaddrResolver(madns.DefaultResolver))
}

// DefaultPrometheusRegisterer configures libp2p to use the default registerer
var DefaultPrometheusRegisterer = func(cfg *Config) error {
return cfg.Apply(PrometheusRegisterer(prometheus.DefaultRegisterer))
}

// Complete list of default options and when to fallback on them.
//
// Please *DON'T* specify default options any other way. Putting this all here
Expand Down Expand Up @@ -181,6 +187,10 @@ var defaults = []struct {
fallback: func(cfg *Config) bool { return cfg.MultiaddrResolver == nil },
opt: DefaultMultiaddrResolver,
},
{
fallback: func(cfg *Config) bool { return !cfg.DisableMetrics && cfg.PrometheusRegisterer == nil },
opt: DefaultPrometheusRegisterer,
},
}

// Defaults configures libp2p to use the default options. Can be combined with
Expand Down
26 changes: 26 additions & 0 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
relayv2 "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay"
"github.com/libp2p/go-libp2p/p2p/protocol/holepunch"
"github.com/libp2p/go-libp2p/p2p/transport/quicreuse"
"github.com/prometheus/client_golang/prometheus"

ma "github.com/multiformats/go-multiaddr"
madns "github.com/multiformats/go-multiaddr-dns"
Expand Down Expand Up @@ -548,3 +549,28 @@ func WithDialTimeout(t time.Duration) Option {
return nil
}
}

// DisableMetrics configures libp2p to disable prometheus metrics
func DisableMetrics() Option {
return func(cfg *Config) error {
cfg.DisableMetrics = true
return nil
}
}

// PrometheusRegisterer configures libp2p to use reg as the Registerer for all metrics subsystems
func PrometheusRegisterer(reg prometheus.Registerer) Option {
return func(cfg *Config) error {
if cfg.DisableMetrics {
return errors.New("cannot set registerer when metrics are disabled")
}
if cfg.PrometheusRegisterer != nil {
return errors.New("registerer already set")
}
if reg == nil {
return errors.New("registerer cannot be nil")
}
cfg.PrometheusRegisterer = reg
return nil
}
}
51 changes: 23 additions & 28 deletions p2p/host/autonat/metrics.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package autonat

import (
"sync"
"time"

"github.com/libp2p/go-libp2p/core/network"
Expand Down Expand Up @@ -58,20 +57,15 @@ var (
Help: "Time of next probe",
},
)
)

var initMetricsOnce sync.Once

func initMetrics(reg prometheus.Registerer) {
reg.MustRegister(
collectors = []prometheus.Collector{
reachabilityStatus,
reachabilityStatusConfidence,
receivedDialResponseTotal,
outgoingDialResponseTotal,
outgoingDialRefusedTotal,
nextProbeTimestamp,
)
}
}
)

type MetricsTracer interface {
ReachabilityStatus(status network.Reachability)
Expand Down Expand Up @@ -107,14 +101,32 @@ const (
no_valid_address = "no valid address"
)

type metricsTracer struct{}

var _ MetricsTracer = &metricsTracer{}

type metricsTracerSetting struct {
reg prometheus.Registerer
}

type metricsTracer struct {
type MetricsTracerOption func(*metricsTracerSetting)

func WithRegisterer(reg prometheus.Registerer) MetricsTracerOption {
return func(s *metricsTracerSetting) {
if reg != nil {
s.reg = reg
}
}
}

var _ MetricsTracer = &metricsTracer{}
func NewMetricsTracer(opts ...MetricsTracerOption) MetricsTracer {
setting := &metricsTracerSetting{reg: prometheus.DefaultRegisterer}
for _, opt := range opts {
opt(setting)
}
metricshelper.RegisterCollectors(setting.reg, collectors...)
return &metricsTracer{}
}

func (mt *metricsTracer) ReachabilityStatus(status network.Reachability) {
reachabilityStatus.Set(float64(status))
Expand Down Expand Up @@ -148,20 +160,3 @@ func (mt *metricsTracer) OutgoingDialRefused(reason string) {
func (mt *metricsTracer) NextProbeTime(t time.Time) {
nextProbeTimestamp.Set(float64(t.Unix()))
}

type MetricsTracerOption = func(*metricsTracerSetting)

func MustRegisterWith(reg prometheus.Registerer) MetricsTracerOption {
return func(s *metricsTracerSetting) {
s.reg = reg
}
}

func NewMetricsTracer(opts ...MetricsTracerOption) MetricsTracer {
settings := &metricsTracerSetting{reg: prometheus.DefaultRegisterer}
for _, opt := range opts {
opt(settings)
}
initMetricsOnce.Do(func() { initMetrics(settings.reg) })
return &metricsTracer{}
}
49 changes: 31 additions & 18 deletions p2p/host/basic/basic_host.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/libp2p/go-libp2p/p2p/protocol/holepunch"
"github.com/libp2p/go-libp2p/p2p/protocol/identify"
"github.com/libp2p/go-libp2p/p2p/protocol/ping"
"github.com/prometheus/client_golang/prometheus"

"github.com/libp2p/go-netroute"

Expand Down Expand Up @@ -151,19 +152,32 @@ type HostOpts struct {
EnableHolePunching bool
// HolePunchingOptions are options for the hole punching service
HolePunchingOptions []holepunch.Option

// EnableMetrics enables the metrics subsystems
EnableMetrics bool
// PrometheusRegisterer is the PrometheusRegisterer used for metrics
PrometheusRegisterer prometheus.Registerer
}

// NewHost constructs a new *BasicHost and activates it by attaching its stream and connection handlers to the given inet.Network.
func NewHost(n network.Network, opts *HostOpts) (*BasicHost, error) {
eventBus := eventbus.NewBus(eventbus.WithMetricsTracer(eventbus.NewMetricsTracer()))
if opts == nil {
opts = &HostOpts{}
}

var eventBus event.Bus
if opts.EnableMetrics {
eventBus = eventbus.NewBus(
eventbus.WithMetricsTracer(eventbus.NewMetricsTracer(eventbus.WithRegisterer(opts.PrometheusRegisterer))))
} else {
eventBus = eventbus.NewBus()
}

psManager, err := pstoremanager.NewPeerstoreManager(n.Peerstore(), eventBus)
if err != nil {
return nil, err
}
hostCtx, cancel := context.WithCancel(context.Background())
if opts == nil {
opts = &HostOpts{}
}

h := &BasicHost{
network: n,
Expand Down Expand Up @@ -223,23 +237,22 @@ func NewHost(n network.Network, opts *HostOpts) (*BasicHost, error) {
h.mux = opts.MultistreamMuxer
}

idOpts := []identify.Option{
identify.UserAgent(opts.UserAgent),
identify.ProtocolVersion(opts.ProtocolVersion),
}

// we can't set this as a default above because it depends on the *BasicHost.
if h.disableSignedPeerRecord {
h.ids, err = identify.NewIDService(
h,
identify.UserAgent(opts.UserAgent),
identify.ProtocolVersion(opts.ProtocolVersion),
identify.DisableSignedPeerRecord(),
identify.WithMetricsTracer(identify.NewMetricsTracer()),
)
} else {
h.ids, err = identify.NewIDService(
h,
identify.UserAgent(opts.UserAgent),
identify.ProtocolVersion(opts.ProtocolVersion),
identify.WithMetricsTracer(identify.NewMetricsTracer()),
)
idOpts = append(idOpts, identify.DisableSignedPeerRecord())
}
if opts.EnableMetrics {
idOpts = append(idOpts,
identify.WithMetricsTracer(
identify.NewMetricsTracer(identify.WithRegisterer(opts.PrometheusRegisterer))))
}

h.ids, err = identify.NewIDService(h, idOpts...)
if err != nil {
return nil, fmt.Errorf("failed to create Identify service: %s", err)
}
Expand Down
28 changes: 15 additions & 13 deletions p2p/host/eventbus/basic_metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package eventbus
import (
"reflect"
"strings"
"sync"

"github.com/libp2p/go-libp2p/p2p/metricshelper"

Expand Down Expand Up @@ -53,6 +52,13 @@ var (
},
[]string{"subscriber_name"},
)
collectors = []prometheus.Collector{
eventsEmitted,
totalSubscribers,
subscriberQueueLength,
subscriberQueueFull,
subscriberEventQueued,
}
)

// MetricsTracer tracks metrics for the eventbus subsystem
Expand Down Expand Up @@ -81,30 +87,26 @@ type metricsTracer struct{}

var _ MetricsTracer = &metricsTracer{}

type MetricsTracerOption = func(*metricsTracerSetting)

type metricsTracerSetting struct {
reg prometheus.Registerer
}

var initMetricsOnce sync.Once

func initMetrics(reg prometheus.Registerer) {
reg.MustRegister(eventsEmitted, totalSubscribers, subscriberQueueLength, subscriberQueueFull, subscriberEventQueued)
}
type MetricsTracerOption func(*metricsTracerSetting)

func MustRegisterWith(reg prometheus.Registerer) MetricsTracerOption {
func WithRegisterer(reg prometheus.Registerer) MetricsTracerOption {
return func(s *metricsTracerSetting) {
s.reg = reg
if reg != nil {
s.reg = reg
}
}
}

func NewMetricsTracer(opts ...MetricsTracerOption) MetricsTracer {
settings := &metricsTracerSetting{reg: prometheus.DefaultRegisterer}
setting := &metricsTracerSetting{reg: prometheus.DefaultRegisterer}
for _, opt := range opts {
opt(settings)
opt(setting)
}
initMetricsOnce.Do(func() { initMetrics(settings.reg) })
metricshelper.RegisterCollectors(setting.reg, collectors...)
return &metricsTracer{}
}

Expand Down
20 changes: 20 additions & 0 deletions p2p/metricshelper/registerer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package metricshelper

import (
"errors"

"github.com/prometheus/client_golang/prometheus"
)

// RegisterCollectors registers the collectors with reg ignoring
// reregistration error and panics on any other error
func RegisterCollectors(reg prometheus.Registerer, collectors ...prometheus.Collector) {
for _, c := range collectors {
err := reg.Register(c)
if err != nil {
if ok := errors.As(err, &prometheus.AlreadyRegisteredError{}); !ok {
panic(err)
}
}
}
}
Loading