Skip to content

Commit

Permalink
use public api for metric collection
Browse files Browse the repository at this point in the history
  • Loading branch information
kikht authored and fujita committed Apr 1, 2023
1 parent 024d88c commit 16ced20
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 210 deletions.
44 changes: 27 additions & 17 deletions cmd/gobgpd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@ import (
"fmt"
"io"
"net/http"
_ "net/http/pprof"
"net/http/pprof"
"os"
"os/signal"
"runtime"
"syscall"

"github.com/coreos/go-systemd/v22/daemon"
grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
"github.com/jessevdk/go-flags"
"github.com/kr/pretty"
"github.com/prometheus/client_golang/prometheus"
Expand All @@ -40,6 +41,7 @@ import (

"github.com/osrg/gobgp/v3/internal/pkg/version"
"github.com/osrg/gobgp/v3/pkg/config"
"github.com/osrg/gobgp/v3/pkg/metrics"
"github.com/osrg/gobgp/v3/pkg/server"
)

Expand All @@ -61,9 +63,9 @@ func main() {
GrpcHosts string `long:"api-hosts" description:"specify the hosts that gobgpd listens on" default:":50051"`
GracefulRestart bool `short:"r" long:"graceful-restart" description:"flag restart-state in graceful-restart capability"`
Dry bool `short:"d" long:"dry-run" description:"check configuration"`
PProfHost string `long:"pprof-host" description:"specify the host that gobgpd listens on for pprof" default:"localhost:6060"`
PProfHost string `long:"pprof-host" description:"specify the host that gobgpd listens on for pprof and metrics" default:"localhost:6060"`
PProfDisable bool `long:"pprof-disable" description:"disable pprof profiling"`
MetricsPath string `long:"metrics-path" description:"specify path for prometheus metrics" default:"/metrics"`
MetricsPath string `long:"metrics-path" description:"specify path for prometheus metrics, empty value disables them" default:"/metrics"`
UseSdNotify bool `long:"sdnotify" description:"use sd_notify protocol"`
TLS bool `long:"tls" description:"enable TLS authentication for gRPC API"`
TLSCertFile string `long:"tls-cert-file" description:"The TLS cert file"`
Expand Down Expand Up @@ -91,16 +93,20 @@ func main() {
runtime.GOMAXPROCS(opts.CPUs)
}

metricRegistry := prometheus.NewRegistry()

httpMux := http.NewServeMux()
if !opts.PProfDisable {
http.Handle(opts.MetricsPath, promhttp.InstrumentMetricHandler(
metricRegistry,
promhttp.HandlerFor(metricRegistry, promhttp.HandlerOpts{}),
))

httpMux.HandleFunc("/debug/pprof/", pprof.Index)
httpMux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
httpMux.HandleFunc("/debug/pprof/profile", pprof.Profile)
httpMux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
httpMux.HandleFunc("/debug/pprof/trace", pprof.Trace)
}
if opts.MetricsPath != "" {
httpMux.Handle(opts.MetricsPath, promhttp.Handler())
}
if !opts.PProfDisable || opts.MetricsPath != "" {
go func() {
logger.Println(http.ListenAndServe(opts.PProfHost, nil))
logger.Println(http.ListenAndServe(opts.PProfHost, httpMux))
}()
}

Expand Down Expand Up @@ -179,13 +185,17 @@ func main() {
grpcOpts = append(grpcOpts, grpc.Creds(creds))
}

if opts.MetricsPath != "" {
grpcOpts = append(
grpcOpts,
grpc.StreamInterceptor(grpc_prometheus.StreamServerInterceptor),
grpc.UnaryInterceptor(grpc_prometheus.UnaryServerInterceptor),
)
}

logger.Info("gobgpd started")
bgpServer := server.NewBgpServer(
server.GrpcListenAddress(opts.GrpcHosts),
server.GrpcOption(grpcOpts),
server.LoggerOption(&builtinLogger{logger: logger}),
server.Metrics(metricRegistry),
)
bgpServer := server.NewBgpServer(server.GrpcListenAddress(opts.GrpcHosts), server.GrpcOption(grpcOpts), server.LoggerOption(&builtinLogger{logger: logger}))
prometheus.MustRegister(metrics.NewBgpCollector(bgpServer))
go bgpServer.Serve()

if opts.UseSdNotify {
Expand Down
136 changes: 136 additions & 0 deletions pkg/metrics/metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package metrics

import (
"context"

"github.com/prometheus/client_golang/prometheus"

api "github.com/osrg/gobgp/v3/api"
"github.com/osrg/gobgp/v3/pkg/packet/bgp"
"github.com/osrg/gobgp/v3/pkg/server"
)

type bgpCollector struct {
server *server.BgpServer
}

var (
peerLabels = []string{"peer"}
rfLabels = []string{"peer", "route_family"}

bgpReceivedUpdateTotalDesc = prometheus.NewDesc("bgp_received_update_total", "Number of received BGP UPDATE messages from peer", peerLabels, nil)
bgpReceivedNotificationTotalDesc = prometheus.NewDesc("bgp_received_notification_total", "Number of received BGP NOTIFICATION messages from peer", peerLabels, nil)
bgpReceivedOpenTotalDesc = prometheus.NewDesc("bgp_received_open_total", "Number of received BGP OPEN messages from peer", peerLabels, nil)
bgpReceivedRefreshTotalDesc = prometheus.NewDesc("bgp_received_refresh_total", "Number of received BGP REFRESH messages from peer", peerLabels, nil)
bgpReceivedKeepaliveTotalDesc = prometheus.NewDesc("bgp_received_keepalive_total", "Number of received BGP KEEPALIVE messages from peer", peerLabels, nil)
bgpReceivedWithdrawUpdateTotalDesc = prometheus.NewDesc("bgp_received_withdraw_update_total", "Number of received BGP WITHDRAW-UPDATE messages from peer", peerLabels, nil)
bgpReceivedWithdrawPrefixTotalDesc = prometheus.NewDesc("bgp_received_withdraw_prefix_total", "Number of received BGP WITHDRAW-PREFIX messages from peer", peerLabels, nil)
bgpReceivedDiscardedTotalDesc = prometheus.NewDesc("bgp_received_discarded_total", "Number of discarded BGP messages from peer", peerLabels, nil)
bgpReceivedMessageTotalDesc = prometheus.NewDesc("bgp_received_message_total", "Number of received BGP messages from peer", peerLabels, nil)

bgpSentUpdateTotalDesc = prometheus.NewDesc("bgp_sent_update_total", "Number of sent BGP UPDATE messages from peer", peerLabels, nil)
bgpSentNotificationTotalDesc = prometheus.NewDesc("bgp_sent_notification_total", "Number of sent BGP NOTIFICATION messages from peer", peerLabels, nil)
bgpSentOpenTotalDesc = prometheus.NewDesc("bgp_sent_open_total", "Number of sent BGP OPEN messages from peer", peerLabels, nil)
bgpSentRefreshTotalDesc = prometheus.NewDesc("bgp_sent_refresh_total", "Number of sent BGP REFRESH messages from peer", peerLabels, nil)
bgpSentKeepaliveTotalDesc = prometheus.NewDesc("bgp_sent_keepalive_total", "Number of sent BGP KEEPALIVE messages from peer", peerLabels, nil)
bgpSentWithdrawUpdateTotalDesc = prometheus.NewDesc("bgp_sent_withdraw_update_total", "Number of sent BGP WITHDRAW-UPDATE messages from peer", peerLabels, nil)
bgpSentWithdrawPrefixTotalDesc = prometheus.NewDesc("bgp_sent_withdraw_prefix_total", "Number of sent BGP WITHDRAW-PREFIX messages from peer", peerLabels, nil)
bgpSentDiscardedTotalDesc = prometheus.NewDesc("bgp_sent_discarded_total", "Number of discarded BGP messages from peer", peerLabels, nil)
bgpSentMessageTotalDesc = prometheus.NewDesc("bgp_sent_message_total", "Number of sent BGP messages from peer", peerLabels, nil)

bgpRoutesReceivedDesc = prometheus.NewDesc(
"bgp_routes_received",
"Number of routes received from peer",
rfLabels, nil,
)
bgpRoutesAcceptedDesc = prometheus.NewDesc(
"bgp_routes_accepted",
"Number of routes accepted from peer",
rfLabels, nil,
)
)

func NewBgpCollector(server *server.BgpServer) prometheus.Collector {
return &bgpCollector{server: server}
}

func (c *bgpCollector) Describe(out chan<- *prometheus.Desc) {
out <- bgpReceivedUpdateTotalDesc
out <- bgpReceivedNotificationTotalDesc
out <- bgpReceivedOpenTotalDesc
out <- bgpReceivedRefreshTotalDesc
out <- bgpReceivedKeepaliveTotalDesc
out <- bgpReceivedWithdrawUpdateTotalDesc
out <- bgpReceivedWithdrawPrefixTotalDesc
out <- bgpReceivedDiscardedTotalDesc
out <- bgpReceivedMessageTotalDesc

out <- bgpSentUpdateTotalDesc
out <- bgpSentNotificationTotalDesc
out <- bgpSentOpenTotalDesc
out <- bgpSentRefreshTotalDesc
out <- bgpSentKeepaliveTotalDesc
out <- bgpSentWithdrawUpdateTotalDesc
out <- bgpSentWithdrawPrefixTotalDesc
out <- bgpSentDiscardedTotalDesc
out <- bgpSentMessageTotalDesc

out <- bgpRoutesReceivedDesc
out <- bgpRoutesAcceptedDesc
}

func (c *bgpCollector) Collect(out chan<- prometheus.Metric) {
req := &api.ListPeerRequest{EnableAdvertised: false}
err := c.server.ListPeer(context.Background(), req, func(p *api.Peer) {
peerAddr := p.GetConf().GetNeighborAddress()
msg := p.GetState().GetMessages()
send := func(desc *prometheus.Desc, cnt uint64) {
out <- prometheus.MustNewConstMetric(desc, prometheus.CounterValue, float64(cnt), peerAddr)
}

send(bgpReceivedUpdateTotalDesc, msg.Received.Update)
send(bgpReceivedNotificationTotalDesc, msg.Received.Notification)
send(bgpReceivedOpenTotalDesc, msg.Received.Open)
send(bgpReceivedRefreshTotalDesc, msg.Received.Refresh)
send(bgpReceivedKeepaliveTotalDesc, msg.Received.Keepalive)
send(bgpReceivedWithdrawUpdateTotalDesc, uint64(msg.Received.WithdrawUpdate))
send(bgpReceivedWithdrawPrefixTotalDesc, uint64(msg.Received.WithdrawPrefix))
send(bgpReceivedDiscardedTotalDesc, msg.Received.Discarded)
send(bgpReceivedMessageTotalDesc, msg.Received.Total)

send(bgpSentUpdateTotalDesc, msg.Sent.Update)
send(bgpSentNotificationTotalDesc, msg.Sent.Notification)
send(bgpSentOpenTotalDesc, msg.Sent.Open)
send(bgpSentRefreshTotalDesc, msg.Sent.Refresh)
send(bgpSentKeepaliveTotalDesc, msg.Sent.Keepalive)
send(bgpSentWithdrawUpdateTotalDesc, uint64(msg.Sent.WithdrawUpdate))
send(bgpSentWithdrawPrefixTotalDesc, uint64(msg.Sent.WithdrawPrefix))
send(bgpSentDiscardedTotalDesc, msg.Sent.Discarded)
send(bgpSentMessageTotalDesc, msg.Sent.Total)

for _, afiSafi := range p.GetAfiSafis() {
if !afiSafi.GetConfig().GetEnabled() {
continue
}
family := bgp.AfiSafiToRouteFamily(
uint16(afiSafi.GetState().GetFamily().GetAfi()),
uint8(afiSafi.GetState().GetFamily().GetSafi()),
).String()
out <- prometheus.MustNewConstMetric(
bgpRoutesReceivedDesc,
prometheus.GaugeValue,
float64(afiSafi.GetState().GetReceived()),
peerAddr, family,
)
out <- prometheus.MustNewConstMetric(
bgpRoutesAcceptedDesc,
prometheus.GaugeValue,
float64(afiSafi.GetState().GetAccepted()),
peerAddr, family,
)
}
})
if err != nil {
out <- prometheus.NewInvalidMetric(prometheus.NewDesc("error", "error during metric collection", nil, nil), err)
}
}
19 changes: 14 additions & 5 deletions pkg/server/metrics_test.go → pkg/metrics/metrics_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package server
package metrics

import (
"context"
Expand All @@ -10,13 +10,16 @@ import (
apb "google.golang.org/protobuf/types/known/anypb"

api "github.com/osrg/gobgp/v3/api"
"github.com/osrg/gobgp/v3/pkg/server"
)

func TestMetrics(test *testing.T) {
assert := assert.New(test)
s := server.NewBgpServer()

registry := prometheus.NewRegistry()
registry.MustRegister(NewBgpCollector(s))

assert := assert.New(test)
s := NewBgpServer(Metrics(registry))
go s.Serve()
err := s.StartBgp(context.Background(), &api.StartBgpRequest{
Global: &api.Global{
Expand All @@ -40,7 +43,7 @@ func TestMetrics(test *testing.T) {
err = s.AddPeer(context.Background(), &api.AddPeerRequest{Peer: p1})
assert.Nil(err)

t := NewBgpServer()
t := server.NewBgpServer()
go t.Serve()
err = t.StartBgp(context.Background(), &api.StartBgpRequest{
Global: &api.Global{
Expand Down Expand Up @@ -69,7 +72,13 @@ func TestMetrics(test *testing.T) {
}

ch := make(chan struct{})
waitEstablished(s, ch)
s.WatchEvent(context.Background(), &api.WatchEventRequest{Peer: &api.WatchEventRequest_Peer{}}, func(r *api.WatchEventResponse) {
if peer := r.GetPeer(); peer != nil {
if peer.Type == api.WatchEventResponse_PeerEvent_STATE && peer.Peer.State.SessionState == api.PeerState_ESTABLISHED {
close(ch)
}
}
})

err = t.AddPeer(context.Background(), &api.AddPeerRequest{Peer: p2})
assert.Nil(err)
Expand Down
Loading

0 comments on commit 16ced20

Please sign in to comment.