From caa7d2344a38af0668c764fbddd6884d4d540cb3 Mon Sep 17 00:00:00 2001 From: sukun Date: Wed, 1 Mar 2023 18:58:33 +0530 Subject: [PATCH 1/8] relay service: add metrics Metrics Added: ReservationRequest: Opened, Closed, Renewed ReservationRequestResponseStatus ReservationRejectionReason ConnectionRequest: Opened, Closed ConnectionRequestResponseStatus ConnectionRejectionReason ConnectionDuration BytesTransferred RelayStatus --- p2p/host/basic/basic_host.go | 7 + p2p/protocol/circuitv2/relay/metrics.go | 226 ++++++++++++++++++++++++ p2p/protocol/circuitv2/relay/options.go | 8 + p2p/protocol/circuitv2/relay/relay.go | 178 ++++++++++++++++--- 4 files changed, 391 insertions(+), 28 deletions(-) create mode 100644 p2p/protocol/circuitv2/relay/metrics.go diff --git a/p2p/host/basic/basic_host.go b/p2p/host/basic/basic_host.go index 63a8f4eed7..c11447974b 100644 --- a/p2p/host/basic/basic_host.go +++ b/p2p/host/basic/basic_host.go @@ -280,6 +280,13 @@ func NewHost(n network.Network, opts *HostOpts) (*BasicHost, error) { } if opts.EnableRelayService { + if opts.EnableMetrics { + // Prefer explicitly provided metrics tracer + metricsOpt := []relayv2.Option{ + relayv2.WithMetricsTracer( + relayv2.NewMetricsTracer(relayv2.WithRegisterer(opts.PrometheusRegisterer)))} + opts.RelayServiceOpts = append(metricsOpt, opts.RelayServiceOpts...) + } h.relayManager = relaysvc.NewRelayManager(h, opts.RelayServiceOpts...) } diff --git a/p2p/protocol/circuitv2/relay/metrics.go b/p2p/protocol/circuitv2/relay/metrics.go new file mode 100644 index 0000000000..63961b17e5 --- /dev/null +++ b/p2p/protocol/circuitv2/relay/metrics.go @@ -0,0 +1,226 @@ +package relay + +import ( + "time" + + "github.com/libp2p/go-libp2p/p2p/metricshelper" + "github.com/prometheus/client_golang/prometheus" +) + +const metricNamespace = "libp2p_relaysvc" + +var ( + status = prometheus.NewGauge( + prometheus.GaugeOpts{ + Namespace: metricNamespace, + Name: "status", + Help: "Relay Current Status", + }, + ) + + reservationTotal = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricNamespace, + Name: "reservation_total", + Help: "Relay Reservation Request", + }, + []string{"type"}, + ) + reservationRequestStatusTotal = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricNamespace, + Name: "reservation_request_status_total", + Help: "Relay Reservation Request Status", + }, + []string{"status"}, + ) + reservationRejectedTotal = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricNamespace, + Name: "reservation_rejected_total", + Help: "Relay Reservation Rejected Reason", + }, + []string{"reason"}, + ) + + connectionTotal = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricNamespace, + Name: "connection_total", + Help: "Relay Connection Total", + }, + []string{"type"}, + ) + connectionRequestStatusTotal = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricNamespace, + Name: "connection_request_status_total", + Help: "Relay Connection Request Status", + }, + []string{"status"}, + ) + connectionRejectionTotal = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricNamespace, + Name: "connection_rejected_total", + Help: "Relay Connection Rejected Reason", + }, + []string{"reason"}, + ) + connectionDurationSeconds = prometheus.NewHistogram( + prometheus.HistogramOpts{ + Namespace: metricNamespace, + Name: "connection_duration_seconds", + Help: "Relay Connection Duration", + }, + ) + + bytesTransferredTotal = prometheus.NewCounter( + prometheus.CounterOpts{ + Namespace: metricNamespace, + Name: "bytes_transferred_total", + Help: "Bytes Transferred Total", + }, + ) + + collectors = []prometheus.Collector{ + status, + reservationTotal, + reservationRequestStatusTotal, + reservationRejectedTotal, + connectionTotal, + connectionRequestStatusTotal, + connectionRejectionTotal, + connectionDurationSeconds, + bytesTransferredTotal, + } +) + +const ( + requestStatusOK = "ok" + requestStatusRejected = "rejected" + requestStatusError = "error" +) + +const ( + typeReceived = "received" + typeOpened = "opened" + typeClosed = "closed" +) + +const ( + rejectionReasonAttemptOverRelay = "attempt over relay" + rejectionReasonDisallowed = "disallowed" + rejectionReasonIPConstraintViolation = "ip constraint violation" + rejectionReasonResourceLimitExceeded = "resource limit exceeded" + rejectionReasonBadRequest = "bad request" + rejectionReasonNoReservation = "no reservation" + rejectionReasonClosed = "closed" +) + +// MetricsTracer is the interface for tracking metrics for relay service +type MetricsTracer interface { + // RelayStatus tracks whether the service is currently active + RelayStatus(enabled bool) + + // ConnectionRequestReceived tracks a new relay connect request + ConnectionRequestReceived() + // ConnectionOpened tracks metrics on opening a relay connection + ConnectionOpened() + // ConnectionClosed tracks metrics on closing a relay connection + ConnectionClosed(d time.Duration) + // ConnectionRequestHandled tracks metrics on handling a relay connection request + // rejectionReason is ignored for status other than `requestStatusRejected` + ConnectionRequestHandled(status string, rejectionReason string) + + // ReservationRequestReceived tracks a new relay reservation request + ReservationRequestReceived() + // ReservationOpened tracks metrics on Opening a relay reservation + ReservationOpened() + // ReservationRequestClosed tracks metrics on closing a relay reservation + ReservationClosed(cnt int) + // ReservationRequestHandled tracks metrics on handling a relay reservation request + // rejectionReason is ignored for status other than `requestStatusRejected` + ReservationRequestHandled(status string, rejectionReason string) + + // BytesTransferred tracks the total bytes transferred(incoming + outgoing) by the relay service + BytesTransferred(cnt int) +} + +type metricsTracer struct{} + +var _ MetricsTracer = &metricsTracer{} + +type metricsTracerSetting struct { + reg prometheus.Registerer +} + +type MetricsTracerOption func(*metricsTracerSetting) + +func WithRegisterer(reg prometheus.Registerer) MetricsTracerOption { + return func(s *metricsTracerSetting) { + if reg != nil { + s.reg = reg + } + } +} + +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) RelayStatus(enabled bool) { + if enabled { + status.Set(1) + } else { + status.Set(0) + } +} + +func (mt *metricsTracer) ConnectionRequestReceived() { + connectionTotal.WithLabelValues(typeReceived).Add(1) +} + +func (mt *metricsTracer) ConnectionOpened() { + connectionTotal.WithLabelValues(typeOpened).Add(1) +} + +func (mt *metricsTracer) ConnectionClosed(d time.Duration) { + connectionTotal.WithLabelValues(typeClosed).Add(1) + connectionDurationSeconds.Observe(d.Seconds()) +} + +func (mt *metricsTracer) ConnectionRequestHandled(status string, rejectionReason string) { + connectionRequestStatusTotal.WithLabelValues(status).Add(1) + if status == requestStatusRejected { + connectionRejectionTotal.WithLabelValues(rejectionReason).Add(1) + } +} + +func (mt *metricsTracer) ReservationRequestReceived() { + reservationTotal.WithLabelValues(typeReceived).Add(1) +} + +func (mt *metricsTracer) ReservationOpened() { + reservationTotal.WithLabelValues(typeOpened).Add(1) +} + +func (mt *metricsTracer) ReservationClosed(cnt int) { + reservationTotal.WithLabelValues(typeClosed).Add(float64(cnt)) +} + +func (mt *metricsTracer) ReservationRequestHandled(status string, rejectionReason string) { + reservationRequestStatusTotal.WithLabelValues(status).Add(1) + if status == requestStatusRejected { + reservationRejectedTotal.WithLabelValues(rejectionReason).Add(1) + } +} + +func (mt *metricsTracer) BytesTransferred(cnt int) { + bytesTransferredTotal.Add(float64(cnt)) +} diff --git a/p2p/protocol/circuitv2/relay/options.go b/p2p/protocol/circuitv2/relay/options.go index a69b658ec1..3b50ec385f 100644 --- a/p2p/protocol/circuitv2/relay/options.go +++ b/p2p/protocol/circuitv2/relay/options.go @@ -33,3 +33,11 @@ func WithACL(acl ACLFilter) Option { return nil } } + +// WithMetricsTracer is a Relay option that supplies a MetricsTracer for metrics +func WithMetricsTracer(mt MetricsTracer) Option { + return func(r *Relay) error { + r.metricsTracer = mt + return nil + } +} diff --git a/p2p/protocol/circuitv2/relay/relay.go b/p2p/protocol/circuitv2/relay/relay.go index 77c592e8b7..63d46ad2a8 100644 --- a/p2p/protocol/circuitv2/relay/relay.go +++ b/p2p/protocol/circuitv2/relay/relay.go @@ -2,6 +2,7 @@ package relay import ( "context" + "errors" "fmt" "io" "sync" @@ -59,6 +60,8 @@ type Relay struct { closed bool selfAddr ma.Multiaddr + + metricsTracer MetricsTracer } // New constructs a new limited relay that can provide relay services in the given host. @@ -100,6 +103,9 @@ func New(h host.Host, opts ...Option) (*Relay, error) { r.notifiee = &network.NotifyBundle{DisconnectedF: r.disconnected} h.Network().Notify(r.notifiee) + if r.metricsTracer != nil { + r.metricsTracer.RelayStatus(true) + } r.wg.Add(1) go r.background() @@ -116,6 +122,9 @@ func (r *Relay) Close() error { r.host.Network().StopNotify(r.notifiee) r.scope.Done() r.cancel() + if r.metricsTracer != nil { + r.metricsTracer.RelayStatus(false) + } r.wg.Wait() return nil } @@ -169,18 +178,24 @@ func (r *Relay) handleStream(s network.Stream) { func (r *Relay) handleReserve(s network.Stream) { defer s.Close() + if r.metricsTracer != nil { + r.metricsTracer.ReservationRequestReceived() + } + p := s.Conn().RemotePeer() a := s.Conn().RemoteMultiaddr() if isRelayAddr(a) { log.Debugf("refusing relay reservation for %s; reservation attempt over relay connection") - r.handleError(s, pbv2.Status_PERMISSION_DENIED) + r.handleErrorAndTrackMetrics(s, pbv2.HopMessage_RESERVE, pbv2.Status_PERMISSION_DENIED, + rejectionReasonAttemptOverRelay) return } if r.acl != nil && !r.acl.AllowReserve(p, a) { log.Debugf("refusing relay reservation for %s; permission denied", p) - r.handleError(s, pbv2.Status_PERMISSION_DENIED) + r.handleErrorAndTrackMetrics(s, pbv2.HopMessage_RESERVE, pbv2.Status_PERMISSION_DENIED, + rejectionReasonDisallowed) return } @@ -199,7 +214,8 @@ func (r *Relay) handleReserve(s network.Stream) { if err := r.constraints.AddReservation(p, a); err != nil { r.mx.Unlock() log.Debugf("refusing relay reservation for %s; IP constraint violation: %s", p, err) - r.handleError(s, pbv2.Status_RESERVATION_REFUSED) + r.handleErrorAndTrackMetrics(s, pbv2.HopMessage_RESERVE, pbv2.Status_RESERVATION_REFUSED, + rejectionReasonIPConstraintViolation) return } } @@ -208,6 +224,9 @@ func (r *Relay) handleReserve(s network.Stream) { r.rsvp[p] = expire r.host.ConnManager().TagPeer(p, "relay-reservation", ReservationTagWeight) r.mx.Unlock() + if !exists && r.metricsTracer != nil { + r.metricsTracer.ReservationOpened() + } log.Debugf("reserving relay slot for %s", p) @@ -217,47 +236,59 @@ func (r *Relay) handleReserve(s network.Stream) { if err := r.writeResponse(s, pbv2.Status_OK, r.makeReservationMsg(p, expire), r.makeLimitMsg(p)); err != nil { log.Debugf("error writing reservation response; retracting reservation for %s", p) s.Reset() + if r.metricsTracer != nil { + r.metricsTracer.ReservationRequestHandled(requestStatusError, "") + } + } + + if r.metricsTracer != nil { + r.metricsTracer.ReservationRequestHandled(requestStatusOK, "") } } func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) { + if r.metricsTracer != nil { + r.metricsTracer.ConnectionRequestReceived() + } + src := s.Conn().RemotePeer() a := s.Conn().RemoteMultiaddr() span, err := r.scope.BeginSpan() if err != nil { log.Debugf("failed to begin relay transaction: %s", err) - r.handleError(s, pbv2.Status_RESOURCE_LIMIT_EXCEEDED) + r.handleErrorAndTrackMetrics(s, pbv2.HopMessage_CONNECT, pbv2.Status_RESOURCE_LIMIT_EXCEEDED, + rejectionReasonResourceLimitExceeded) return } - fail := func(status pbv2.Status) { + fail := func(status pbv2.Status, rejectionReason string) { span.Done() - r.handleError(s, status) + r.handleErrorAndTrackMetrics(s, pbv2.HopMessage_CONNECT, status, rejectionReason) } // reserve buffers for the relay if err := span.ReserveMemory(2*r.rc.BufferSize, network.ReservationPriorityHigh); err != nil { log.Debugf("error reserving memory for relay: %s", err) - fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED) + fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED, rejectionReasonResourceLimitExceeded) return } if isRelayAddr(a) { log.Debugf("refusing connection from %s; connection attempt over relay connection") - fail(pbv2.Status_PERMISSION_DENIED) + fail(pbv2.Status_PERMISSION_DENIED, rejectionReasonAttemptOverRelay) return } dest, err := util.PeerToPeerInfoV2(msg.GetPeer()) if err != nil { - fail(pbv2.Status_MALFORMED_MESSAGE) + fail(pbv2.Status_MALFORMED_MESSAGE, rejectionReasonBadRequest) return } if r.acl != nil && !r.acl.AllowConnect(src, s.Conn().RemoteMultiaddr(), dest.ID) { log.Debugf("refusing connection from %s to %s; permission denied", src, dest.ID) - fail(pbv2.Status_PERMISSION_DENIED) + fail(pbv2.Status_PERMISSION_DENIED, rejectionReasonDisallowed) return } @@ -266,7 +297,7 @@ func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) { if !rsvp { r.mx.Unlock() log.Debugf("refusing connection from %s to %s; no reservation", src, dest.ID) - fail(pbv2.Status_NO_RESERVATION) + fail(pbv2.Status_NO_RESERVATION, rejectionReasonNoReservation) return } @@ -274,7 +305,7 @@ func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) { if srcConns >= r.rc.MaxCircuits { r.mx.Unlock() log.Debugf("refusing connection from %s to %s; too many connections from %s", src, dest.ID, src) - fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED) + fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED, rejectionReasonResourceLimitExceeded) return } @@ -282,7 +313,7 @@ func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) { if destConns >= r.rc.MaxCircuits { r.mx.Unlock() log.Debugf("refusing connection from %s to %s; too many connecitons to %s", src, dest.ID, dest.ID) - fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED) + fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED, rejectionReasonResourceLimitExceeded) return } @@ -290,12 +321,20 @@ func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) { r.addConn(dest.ID) r.mx.Unlock() + if r.metricsTracer != nil { + r.metricsTracer.ConnectionOpened() + } + connStTime := time.Now() + cleanup := func() { span.Done() r.mx.Lock() r.rmConn(src) r.rmConn(dest.ID) r.mx.Unlock() + if r.metricsTracer != nil { + r.metricsTracer.ConnectionClosed(time.Since(connStTime)) + } } ctx, cancel := context.WithTimeout(r.ctx, ConnectTimeout) @@ -307,26 +346,26 @@ func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) { if err != nil { log.Debugf("error opening relay stream to %s: %s", dest.ID, err) cleanup() - r.handleError(s, pbv2.Status_CONNECTION_FAILED) + r.handleErrorAndTrackMetrics(s, pbv2.HopMessage_CONNECT, pbv2.Status_CONNECTION_FAILED, "") return } - fail = func(status pbv2.Status) { + fail = func(status pbv2.Status, rejectionReason string) { bs.Reset() cleanup() - r.handleError(s, status) + r.handleErrorAndTrackMetrics(s, pbv2.HopMessage_CONNECT, status, rejectionReason) } if err := bs.Scope().SetService(ServiceName); err != nil { log.Debugf("error attaching stream to relay service: %s", err) - fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED) + fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED, rejectionReasonResourceLimitExceeded) return } // handshake if err := bs.Scope().ReserveMemory(maxMessageSize, network.ReservationPriorityAlways); err != nil { - log.Debugf("erro reserving memory for stream: %s", err) - fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED) + log.Debugf("error reserving memory for stream: %s", err) + fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED, rejectionReasonResourceLimitExceeded) return } defer bs.Scope().ReleaseMemory(maxMessageSize) @@ -345,7 +384,7 @@ func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) { err = wr.WriteMsg(&stopmsg) if err != nil { log.Debugf("error writing stop handshake") - fail(pbv2.Status_CONNECTION_FAILED) + fail(pbv2.Status_CONNECTION_FAILED, "") return } @@ -354,19 +393,19 @@ func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) { err = rd.ReadMsg(&stopmsg) if err != nil { log.Debugf("error reading stop response: %s", err.Error()) - fail(pbv2.Status_CONNECTION_FAILED) + fail(pbv2.Status_CONNECTION_FAILED, "") return } if t := stopmsg.GetType(); t != pbv2.StopMessage_STATUS { log.Debugf("unexpected stop response; not a status message (%d)", t) - fail(pbv2.Status_CONNECTION_FAILED) + fail(pbv2.Status_CONNECTION_FAILED, "") return } if status := stopmsg.GetStatus(); status != pbv2.Status_OK { log.Debugf("relay stop failure: %d", status) - fail(pbv2.Status_CONNECTION_FAILED) + fail(pbv2.Status_CONNECTION_FAILED, "") return } @@ -382,6 +421,9 @@ func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) { bs.Reset() s.Reset() cleanup() + if r.metricsTracer != nil { + r.metricsTracer.ConnectionRequestHandled(requestStatusError, "") + } return } @@ -411,6 +453,10 @@ func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) { go r.relayUnlimited(s, bs, src, dest.ID, done) go r.relayUnlimited(bs, s, dest.ID, src, done) } + + if r.metricsTracer != nil { + r.metricsTracer.ConnectionRequestHandled(requestStatusOK, "") + } } func (r *Relay) addConn(p peer.ID) { @@ -441,7 +487,7 @@ func (r *Relay) relayLimited(src, dest network.Stream, srcID, destID peer.ID, li limitedSrc := io.LimitReader(src, limit) - count, err := io.CopyBuffer(dest, limitedSrc, buf) + count, err := r.copyWithBuffer(dest, limitedSrc, buf) if err != nil { log.Debugf("relay copy error: %s", err) // Reset both. @@ -465,7 +511,7 @@ func (r *Relay) relayUnlimited(src, dest network.Stream, srcID, destID peer.ID, buf := pool.Get(r.rc.BufferSize) defer pool.Put(buf) - count, err := io.CopyBuffer(dest, src, buf) + count, err := r.copyWithBuffer(dest, src, buf) if err != nil { log.Debugf("relay copy error: %s", err) // Reset both. @@ -479,6 +525,47 @@ func (r *Relay) relayUnlimited(src, dest network.Stream, srcID, destID peer.ID, log.Debugf("relayed %d bytes from %s to %s", count, srcID, destID) } +// errInvalidWrite means that a write returned an impossible count. +// copied from io.errInvalidWrite +var errInvalidWrite = errors.New("invalid write result") + +// copyWithBuffer copies from src to dst using the provided buf until either EOF is reached +// on src or an error occurs. It reports the number of bytes transferred to metricsTracer. +// The implementation is a modified form of io.CopyBuffer to support metrics tracking. +func (r *Relay) copyWithBuffer(dst io.Writer, src io.Reader, buf []byte) (written int64, err error) { + for { + nr, er := src.Read(buf) + if nr > 0 { + nw, ew := dst.Write(buf[0:nr]) + if nw < 0 || nr < nw { + nw = 0 + if ew == nil { + ew = errInvalidWrite + } + } + written += int64(nw) + if ew != nil { + err = ew + break + } + if nr != nw { + err = io.ErrShortWrite + break + } + if r.metricsTracer != nil { + r.metricsTracer.BytesTransferred(nr + nw) + } + } + if er != nil { + if er != io.EOF { + err = er + } + break + } + } + return written, err +} + func (r *Relay) handleError(s network.Stream, status pbv2.Status) { log.Debugf("relay error: %s (%d)", pbv2.Status_name[int32(status)], status) err := r.writeResponse(s, status, nil, nil) @@ -490,6 +577,34 @@ func (r *Relay) handleError(s network.Stream, status pbv2.Status) { } } +func (r *Relay) handleErrorAndTrackMetrics(s network.Stream, reqType pbv2.HopMessage_Type, status pbv2.Status, + rejectionReason string) { + r.handleError(s, status) + if r.metricsTracer != nil { + var reqStatus string + switch status { + case pbv2.Status_RESERVATION_REFUSED, + pbv2.Status_RESOURCE_LIMIT_EXCEEDED, + pbv2.Status_PERMISSION_DENIED, + pbv2.Status_NO_RESERVATION, + pbv2.Status_MALFORMED_MESSAGE: + + reqStatus = requestStatusRejected + case pbv2.Status_UNEXPECTED_MESSAGE, pbv2.Status_CONNECTION_FAILED: + reqStatus = requestStatusError + default: + reqStatus = "unknown" + } + + switch reqType { + case pbv2.HopMessage_CONNECT: + r.metricsTracer.ConnectionRequestHandled(reqStatus, rejectionReason) + case pbv2.HopMessage_RESERVE: + r.metricsTracer.ReservationRequestHandled(reqStatus, rejectionReason) + } + } +} + func (r *Relay) writeResponse(s network.Stream, status pbv2.Status, rsvp *pbv2.Reservation, limit *pbv2.Limit) error { wr := util.NewDelimitedWriter(s) @@ -580,13 +695,17 @@ func (r *Relay) gc() { defer r.mx.Unlock() now := time.Now() - + cnt := 0 for p, expire := range r.rsvp { if r.closed || expire.Before(now) { delete(r.rsvp, p) r.host.ConnManager().UntagPeer(p, "relay-reservation") + cnt++ } } + if r.metricsTracer != nil { + r.metricsTracer.ReservationClosed(cnt) + } for p, count := range r.conns { if count == 0 { @@ -602,9 +721,12 @@ func (r *Relay) disconnected(n network.Network, c network.Conn) { } r.mx.Lock() - defer r.mx.Unlock() + _, ok := r.rsvp[p] + r.mx.Unlock() - delete(r.rsvp, p) + if ok && r.metricsTracer != nil { + r.metricsTracer.ReservationClosed(1) + } } func isRelayAddr(a ma.Multiaddr) bool { From 82b6363754818315fae1e392b70ea1f0e27974e8 Mon Sep 17 00:00:00 2001 From: sukun Date: Wed, 1 Mar 2023 19:44:51 +0530 Subject: [PATCH 2/8] add dashboard and changelog --- CHANGELOG.md | 10 + dashboards/relaysvc/relaysvc.json | 1007 +++++++++++++++++++++++++++++ 2 files changed, 1017 insertions(+) create mode 100644 dashboards/relaysvc/relaysvc.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 012815d332..2a45657279 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,16 @@ This patch release fixes two bugs: **Full Changelog**: https://github.com/libp2p/go-libp2p/compare/v0.26.0...v0.26.1 +# [v0.27.0](https://github.com/libp2p/go-libp2p/releases/tag/v0.27.0) + +## 🔦 Highlights + +### Additional metrics +Since the last release, we've added metrics for: +* [Relay Service](https://github.com/libp2p/go-libp2p/pull/2154): RequestStatus, RequestCounts, RejectionReasons for Reservation and Connection Requests, +ConnectionDuration, BytesTransferred, Relay Service Status. + + # [v0.26.0](https://github.com/libp2p/go-libp2p/releases/tag/v0.26.0) ## 🔦 Highlights diff --git a/dashboards/relaysvc/relaysvc.json b/dashboards/relaysvc/relaysvc.json new file mode 100644 index 0000000000..ff82b25acc --- /dev/null +++ b/dashboards/relaysvc/relaysvc.json @@ -0,0 +1,1007 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.3.6" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "state-timeline", + "name": "State timeline", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "custom": { + "fillOpacity": 70, + "lineWidth": 0, + "spanNulls": false + }, + "mappings": [ + { + "options": { + "0": { + "color": "purple", + "index": 0, + "text": "no" + }, + "1": { + "color": "green", + "index": 1, + "text": "yes" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 2, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "mergeValues": true, + "rowHeight": 0.9, + "showValue": "auto", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "libp2p_relaysvc_status", + "legendFormat": "service active", + "range": true, + "refId": "A" + } + ], + "title": "Panel Title", + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "Bps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "bandwidth" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "bandwidth" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 7 + }, + "id": 16, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "rate(libp2p_relaysvc_bytes_transferred_total[$__rate_interval])", + "legendFormat": "bandwidth", + "range": true, + "refId": "A" + } + ], + "title": "Bandwidth Used", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "index": 0, + "text": "0" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 7 + }, + "id": 4, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.3.6", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "libp2p_relaysvc_reservation_total{type=\"opened\"} - ignoring(type) libp2p_relaysvc_reservation_total{type=\"closed\"}", + "legendFormat": "active reservations", + "range": true, + "refId": "A" + } + ], + "title": "Active Reservations", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "index": 0, + "text": "0" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 7 + }, + "id": 6, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.3.6", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "libp2p_relaysvc_connection_total{type=\"opened\"} - ignoring(type) libp2p_relaysvc_connection_total{type=\"closed\"}", + "legendFormat": "active connections", + "range": true, + "refId": "A" + } + ], + "title": "Active Connections", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "error" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "ok" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 15 + }, + "id": 8, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "increase(libp2p_relaysvc_reservation_request_status_total[$__rate_interval])", + "legendFormat": "{{status}}", + "range": true, + "refId": "A" + } + ], + "title": "Reservation Request Status", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "error" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "error" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "ok" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 15 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "increase(libp2p_relaysvc_connection_request_status_total[$__rate_interval])", + "legendFormat": "{{status}}", + "range": true, + "refId": "A" + } + ], + "title": "Connection Request Status", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 23 + }, + "id": 12, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "increase(libp2p_relaysvc_reservation_rejected_total[$__rate_interval])", + "legendFormat": "{{reason}}", + "range": true, + "refId": "A" + } + ], + "title": "Reservation Request Rejected", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 23 + }, + "id": 14, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "increase(libp2p_relaysvc_connection_rejected_total[$__rate_interval])", + "legendFormat": "{{reason}}", + "range": true, + "refId": "A" + } + ], + "title": "Connection Request Rejected", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 31 + }, + "id": 18, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.5, sum(rate(libp2p_relaysvc_connection_duration_seconds_bucket[$__rate_interval])) by (le))", + "legendFormat": "50th percentile", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(libp2p_relaysvc_connection_duration_seconds_bucket[$__rate_interval])) by (le))", + "hide": false, + "legendFormat": "99th percentile", + "range": true, + "refId": "C" + } + ], + "title": "Connection Duration", + "type": "timeseries" + } + ], + "schemaVersion": 37, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Relay Service", + "uid": "C6RUfAx4z", + "version": 25, + "weekStart": "" +} \ No newline at end of file From e168433086262c65bf11daee01a1f339c4b4c34c Mon Sep 17 00:00:00 2001 From: sukun Date: Wed, 1 Mar 2023 20:00:11 +0530 Subject: [PATCH 3/8] bugfix --- p2p/protocol/circuitv2/relay/relay.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/p2p/protocol/circuitv2/relay/relay.go b/p2p/protocol/circuitv2/relay/relay.go index 63d46ad2a8..8e98281368 100644 --- a/p2p/protocol/circuitv2/relay/relay.go +++ b/p2p/protocol/circuitv2/relay/relay.go @@ -722,6 +722,9 @@ func (r *Relay) disconnected(n network.Network, c network.Conn) { r.mx.Lock() _, ok := r.rsvp[p] + if ok { + delete(r.rsvp, p) + } r.mx.Unlock() if ok && r.metricsTracer != nil { From d98e565c3812690136bb92e9ed5aad07cb3a190c Mon Sep 17 00:00:00 2001 From: sukun Date: Wed, 1 Mar 2023 20:15:28 +0530 Subject: [PATCH 4/8] add metrics tests --- p2p/protocol/circuitv2/relay/metrics.go | 56 ++++++++++++++++---- p2p/protocol/circuitv2/relay/metrics_test.go | 37 +++++++++++++ 2 files changed, 83 insertions(+), 10 deletions(-) create mode 100644 p2p/protocol/circuitv2/relay/metrics_test.go diff --git a/p2p/protocol/circuitv2/relay/metrics.go b/p2p/protocol/circuitv2/relay/metrics.go index 63961b17e5..9b9ada7aca 100644 --- a/p2p/protocol/circuitv2/relay/metrics.go +++ b/p2p/protocol/circuitv2/relay/metrics.go @@ -183,41 +183,77 @@ func (mt *metricsTracer) RelayStatus(enabled bool) { } func (mt *metricsTracer) ConnectionRequestReceived() { - connectionTotal.WithLabelValues(typeReceived).Add(1) + tags := metricshelper.GetStringSlice() + defer metricshelper.PutStringSlice(tags) + *tags = append(*tags, typeReceived) + + connectionTotal.WithLabelValues(*tags...).Add(1) } func (mt *metricsTracer) ConnectionOpened() { - connectionTotal.WithLabelValues(typeOpened).Add(1) + tags := metricshelper.GetStringSlice() + defer metricshelper.PutStringSlice(tags) + *tags = append(*tags, typeOpened) + + connectionTotal.WithLabelValues(*tags...).Add(1) } func (mt *metricsTracer) ConnectionClosed(d time.Duration) { - connectionTotal.WithLabelValues(typeClosed).Add(1) + tags := metricshelper.GetStringSlice() + defer metricshelper.PutStringSlice(tags) + *tags = append(*tags, typeClosed) + + connectionTotal.WithLabelValues(*tags...).Add(1) connectionDurationSeconds.Observe(d.Seconds()) } func (mt *metricsTracer) ConnectionRequestHandled(status string, rejectionReason string) { - connectionRequestStatusTotal.WithLabelValues(status).Add(1) + tags := metricshelper.GetStringSlice() + defer metricshelper.PutStringSlice(tags) + *tags = append(*tags, status) + + connectionRequestStatusTotal.WithLabelValues(*tags...).Add(1) if status == requestStatusRejected { - connectionRejectionTotal.WithLabelValues(rejectionReason).Add(1) + *tags = (*tags)[:0] + *tags = append(*tags, rejectionReason) + connectionRejectionTotal.WithLabelValues(*tags...).Add(1) } } func (mt *metricsTracer) ReservationRequestReceived() { - reservationTotal.WithLabelValues(typeReceived).Add(1) + tags := metricshelper.GetStringSlice() + defer metricshelper.PutStringSlice(tags) + *tags = append(*tags, typeReceived) + + reservationTotal.WithLabelValues(*tags...).Add(1) } func (mt *metricsTracer) ReservationOpened() { - reservationTotal.WithLabelValues(typeOpened).Add(1) + tags := metricshelper.GetStringSlice() + defer metricshelper.PutStringSlice(tags) + *tags = append(*tags, typeOpened) + + reservationTotal.WithLabelValues(*tags...).Add(1) } func (mt *metricsTracer) ReservationClosed(cnt int) { - reservationTotal.WithLabelValues(typeClosed).Add(float64(cnt)) + tags := metricshelper.GetStringSlice() + defer metricshelper.PutStringSlice(tags) + *tags = append(*tags, typeClosed) + + reservationTotal.WithLabelValues(*tags...).Add(float64(cnt)) } func (mt *metricsTracer) ReservationRequestHandled(status string, rejectionReason string) { - reservationRequestStatusTotal.WithLabelValues(status).Add(1) + tags := metricshelper.GetStringSlice() + defer metricshelper.PutStringSlice(tags) + *tags = append(*tags, status) + + reservationRequestStatusTotal.WithLabelValues(*tags...).Add(1) if status == requestStatusRejected { - reservationRejectedTotal.WithLabelValues(rejectionReason).Add(1) + *tags = (*tags)[:0] + *tags = append(*tags, rejectionReason) + reservationRejectedTotal.WithLabelValues(*tags...).Add(1) } } diff --git a/p2p/protocol/circuitv2/relay/metrics_test.go b/p2p/protocol/circuitv2/relay/metrics_test.go new file mode 100644 index 0000000000..2c9de6c415 --- /dev/null +++ b/p2p/protocol/circuitv2/relay/metrics_test.go @@ -0,0 +1,37 @@ +//go:build nocover + +package relay + +import ( + "math/rand" + "testing" + "time" +) + +func TestNoCoverNoAlloc(t *testing.T) { + statuses := []string{requestStatusOK, requestStatusRejected, requestStatusError} + rejectionReason := []string{"", rejectionReasonAttemptOverRelay, rejectionReasonBadRequest, rejectionReasonDisallowed} + mt := NewMetricsTracer() + tests := map[string]func(){ + "RelayStatus": func() { mt.RelayStatus(rand.Intn(2) == 1) }, + "ConnectionRequestReceived": func() { mt.ConnectionRequestReceived() }, + "ConnectionOpened": func() { mt.ConnectionOpened() }, + "ConnectionClosed": func() { mt.ConnectionClosed(time.Duration(rand.Intn(10)) * time.Second) }, + "ConnectionRequestHandled": func() { + mt.ConnectionRequestHandled(statuses[rand.Intn(len(statuses))], rejectionReason[rand.Intn(len(rejectionReason))]) + }, + "ReservationRequestReceived": func() { mt.ReservationRequestReceived() }, + "ReservationOpened": func() { mt.ReservationOpened() }, + "ReservationClosed": func() { mt.ReservationClosed(rand.Intn(10)) }, + "ReservationRequestHandled": func() { + mt.ReservationRequestHandled(statuses[rand.Intn(len(statuses))], rejectionReason[rand.Intn(len(rejectionReason))]) + }, + "BytesTransferred": func() { mt.BytesTransferred(rand.Intn(1000)) }, + } + for method, f := range tests { + allocs := testing.AllocsPerRun(1000, f) + if allocs > 0 { + t.Fatalf("Alloc Test: %s, got: %0.2f, expected: 0 allocs", method, allocs) + } + } +} From 4cdffdd297cc2888b2c073d197366bf82222de0d Mon Sep 17 00:00:00 2001 From: sukun Date: Fri, 3 Mar 2023 11:45:18 +0530 Subject: [PATCH 5/8] address review comments --- dashboards/relaysvc/relaysvc.json | 573 +++++++++++++------ p2p/protocol/circuitv2/relay/metrics.go | 182 +++--- p2p/protocol/circuitv2/relay/metrics_test.go | 26 +- p2p/protocol/circuitv2/relay/relay.go | 163 ++---- 4 files changed, 557 insertions(+), 387 deletions(-) diff --git a/dashboards/relaysvc/relaysvc.json b/dashboards/relaysvc/relaysvc.json index ff82b25acc..ac07eb3db2 100644 --- a/dashboards/relaysvc/relaysvc.json +++ b/dashboards/relaysvc/relaysvc.json @@ -71,6 +71,19 @@ "links": [], "liveNow": false, "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 20, + "panels": [], + "title": "Relay Service", + "type": "row" + }, { "datasource": { "type": "prometheus", @@ -119,7 +132,7 @@ "h": 7, "w": 24, "x": 0, - "y": 0 + "y": 1 }, "id": 2, "options": { @@ -145,14 +158,99 @@ }, "editorMode": "code", "expr": "libp2p_relaysvc_status", - "legendFormat": "service active", + "legendFormat": "active", "range": true, "refId": "A" } ], - "title": "Panel Title", + "title": "Status", "type": "state-timeline" }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 8 + }, + "id": 22, + "panels": [], + "title": "Reservations", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "index": 0, + "text": "0" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 9 + }, + "id": 4, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.3.6", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "libp2p_relaysvc_reservations_total{type=\"opened\"} - ignoring(type) libp2p_relaysvc_reservations_total{type=\"closed\"}", + "legendFormat": "active reservations", + "range": true, + "refId": "A" + } + ], + "title": "Active Reservations", + "type": "stat" + }, { "datasource": { "type": "prometheus", @@ -200,60 +298,146 @@ { "color": "green", "value": null + }, + { + "color": "red", + "value": 80 } ] - }, - "unit": "Bps" + } }, "overrides": [ { "matcher": { "id": "byName", - "options": "bandwidth" + "options": "error" }, "properties": [ { "id": "color", "value": { - "fixedColor": "blue", + "fixedColor": "purple", "mode": "fixed" } } ] }, { - "__systemRef": "hideSeriesFrom", "matcher": { - "id": "byNames", - "options": { - "mode": "exclude", - "names": [ - "bandwidth" - ], - "prefix": "All except:", - "readOnly": true - } + "id": "byName", + "options": "ok" }, "properties": [ { - "id": "custom.hideFrom", + "id": "color", "value": { - "legend": false, - "tooltip": false, - "viz": true + "fixedColor": "green", + "mode": "fixed" } } ] } ] }, + "gridPos": { + "h": 8, + "w": 18, + "x": 6, + "y": 9 + }, + "id": 8, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "increase(libp2p_relaysvc_reservation_request_response_status_total[$__rate_interval])", + "legendFormat": "{{status}}", + "range": true, + "refId": "A" + } + ], + "title": "Reservation Request Response Status", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, "gridPos": { "h": 8, "w": 12, "x": 0, - "y": 7 + "y": 17 }, - "id": 16, + "id": 26, "options": { "legend": { "calcs": [], @@ -273,13 +457,25 @@ "uid": "${DS_PROMETHEUS}" }, "editorMode": "code", - "expr": "rate(libp2p_relaysvc_bytes_transferred_total[$__rate_interval])", - "legendFormat": "bandwidth", + "expr": "increase(libp2p_relaysvc_reservations_total{type=\"opened\"}[$__rate_interval])", + "legendFormat": "new", "range": true, "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "increase(libp2p_relaysvc_reservations_total{type=\"renewed\"}[$__rate_interval])", + "hide": false, + "legendFormat": "renewed", + "range": true, + "refId": "B" } ], - "title": "Bandwidth Used", + "title": "Reservation Requests: New vs Renewal", "type": "timeseries" }, { @@ -287,29 +483,53 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "description": "", "fieldConfig": { "defaults": { "color": { - "mode": "thresholds" + "mode": "palette-classic" }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "index": 0, - "text": "0" - } - }, - "type": "special" + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" } - ], + }, + "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null + }, + { + "color": "red", + "value": 80 } ] } @@ -318,26 +538,23 @@ }, "gridPos": { "h": 8, - "w": 6, + "w": 12, "x": 12, - "y": 7 + "y": 17 }, - "id": 4, + "id": 12, "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true }, - "textMode": "auto" + "tooltip": { + "mode": "single", + "sort": "none" + } }, - "pluginVersion": "9.3.6", "targets": [ { "datasource": { @@ -345,57 +562,64 @@ "uid": "${DS_PROMETHEUS}" }, "editorMode": "code", - "expr": "libp2p_relaysvc_reservation_total{type=\"opened\"} - ignoring(type) libp2p_relaysvc_reservation_total{type=\"closed\"}", - "legendFormat": "active reservations", + "expr": "increase(libp2p_relaysvc_reservation_rejections_total[$__rate_interval])", + "legendFormat": "{{reason}}", "range": true, "refId": "A" } ], - "title": "Active Reservations", - "type": "stat" + "title": "Reservation Request Rejected", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 25 + }, + "id": 24, + "panels": [], + "title": "Connections", + "type": "row" }, { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "description": "", "fieldConfig": { "defaults": { "color": { - "fixedColor": "blue", - "mode": "fixed" + "mode": "thresholds" }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "index": 0, - "text": "0" - } - }, - "type": "special" - } - ], + "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null + }, + { + "color": "red", + "value": 80 } ] - } + }, + "unit": "decbytes" }, "overrides": [] }, "gridPos": { "h": 8, "w": 6, - "x": 18, - "y": 7 + "x": 0, + "y": 26 }, - "id": 6, + "id": 28, "options": { "colorMode": "value", "graphMode": "area", @@ -418,13 +642,13 @@ "uid": "${DS_PROMETHEUS}" }, "editorMode": "code", - "expr": "libp2p_relaysvc_connection_total{type=\"opened\"} - ignoring(type) libp2p_relaysvc_connection_total{type=\"closed\"}", - "legendFormat": "active connections", + "expr": "increase(libp2p_relaysvc_data_transferred_bytes_total[$__range])", + "legendFormat": "__auto", "range": true, "refId": "A" } ], - "title": "Active Connections", + "title": "Total Data Transferred", "type": "stat" }, { @@ -435,105 +659,55 @@ "fieldConfig": { "defaults": { "color": { - "mode": "palette-classic" + "fixedColor": "blue", + "mode": "fixed" }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" + "mappings": [ + { + "options": { + "match": "null", + "result": { + "index": 0, + "text": "0" + } + }, + "type": "special" } - }, - "mappings": [], + ], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null - }, - { - "color": "red", - "value": 80 } ] } }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "error" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "ok" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - } - ] + "overrides": [] }, "gridPos": { "h": 8, - "w": 12, - "x": 0, - "y": 15 + "w": 6, + "x": 6, + "y": 26 }, - "id": 8, + "id": 6, "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false }, - "tooltip": { - "mode": "single", - "sort": "none" - } + "textMode": "auto" }, + "pluginVersion": "9.3.6", "targets": [ { "datasource": { @@ -541,14 +715,14 @@ "uid": "${DS_PROMETHEUS}" }, "editorMode": "code", - "expr": "increase(libp2p_relaysvc_reservation_request_status_total[$__rate_interval])", - "legendFormat": "{{status}}", + "expr": "libp2p_relaysvc_connections_total{type=\"opened\"} - ignoring(type) libp2p_relaysvc_connections_total{type=\"closed\"}", + "legendFormat": "active connections", "range": true, "refId": "A" } ], - "title": "Reservation Request Status", - "type": "timeseries" + "title": "Active Connections", + "type": "stat" }, { "datasource": { @@ -666,7 +840,7 @@ "h": 8, "w": 12, "x": 12, - "y": 15 + "y": 26 }, "id": 10, "options": { @@ -688,13 +862,13 @@ "uid": "${DS_PROMETHEUS}" }, "editorMode": "code", - "expr": "increase(libp2p_relaysvc_connection_request_status_total[$__rate_interval])", + "expr": "increase(libp2p_relaysvc_connection_request_response_status_total[$__rate_interval])", "legendFormat": "{{status}}", "range": true, "refId": "A" } ], - "title": "Connection Request Status", + "title": "Connection Request Response Status", "type": "timeseries" }, { @@ -702,7 +876,6 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "description": "", "fieldConfig": { "defaults": { "color": { @@ -745,23 +918,60 @@ { "color": "green", "value": null - }, + } + ] + }, + "unit": "Bps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "bandwidth" + }, + "properties": [ { - "color": "red", - "value": 80 + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "bandwidth" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } } ] } - }, - "overrides": [] + ] }, "gridPos": { "h": 8, "w": 12, "x": 0, - "y": 23 + "y": 34 }, - "id": 12, + "id": 16, "options": { "legend": { "calcs": [], @@ -781,13 +991,13 @@ "uid": "${DS_PROMETHEUS}" }, "editorMode": "code", - "expr": "increase(libp2p_relaysvc_reservation_rejected_total[$__rate_interval])", - "legendFormat": "{{reason}}", + "expr": "2 * rate(libp2p_relaysvc_data_transferred_bytes_total[$__rate_interval])", + "legendFormat": "bandwidth", "range": true, "refId": "A" } ], - "title": "Reservation Request Rejected", + "title": "Bandwidth Used", "type": "timeseries" }, { @@ -851,7 +1061,7 @@ "h": 8, "w": 12, "x": 12, - "y": 23 + "y": 34 }, "id": 14, "options": { @@ -873,7 +1083,7 @@ "uid": "${DS_PROMETHEUS}" }, "editorMode": "code", - "expr": "increase(libp2p_relaysvc_connection_rejected_total[$__rate_interval])", + "expr": "increase(libp2p_relaysvc_connection_rejections_total[$__rate_interval])", "legendFormat": "{{reason}}", "range": true, "refId": "A" @@ -944,7 +1154,7 @@ "h": 8, "w": 12, "x": 12, - "y": 31 + "y": 42 }, "id": 18, "options": { @@ -988,6 +1198,7 @@ "type": "timeseries" } ], + "refresh": "1m", "schemaVersion": 37, "style": "dark", "tags": [], @@ -995,13 +1206,13 @@ "list": [] }, "time": { - "from": "now-15m", + "from": "now-1h", "to": "now" }, "timepicker": {}, "timezone": "", "title": "Relay Service", "uid": "C6RUfAx4z", - "version": 25, + "version": 2, "weekStart": "" } \ No newline at end of file diff --git a/p2p/protocol/circuitv2/relay/metrics.go b/p2p/protocol/circuitv2/relay/metrics.go index 9b9ada7aca..7786459133 100644 --- a/p2p/protocol/circuitv2/relay/metrics.go +++ b/p2p/protocol/circuitv2/relay/metrics.go @@ -4,6 +4,7 @@ import ( "time" "github.com/libp2p/go-libp2p/p2p/metricshelper" + pbv2 "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/pb" "github.com/prometheus/client_golang/prometheus" ) @@ -14,55 +15,55 @@ var ( prometheus.GaugeOpts{ Namespace: metricNamespace, Name: "status", - Help: "Relay Current Status", + Help: "Relay Status", }, ) - reservationTotal = prometheus.NewCounterVec( + reservationsTotal = prometheus.NewCounterVec( prometheus.CounterOpts{ Namespace: metricNamespace, - Name: "reservation_total", + Name: "reservations_total", Help: "Relay Reservation Request", }, []string{"type"}, ) - reservationRequestStatusTotal = prometheus.NewCounterVec( + reservationRequestResponseStatusTotal = prometheus.NewCounterVec( prometheus.CounterOpts{ Namespace: metricNamespace, - Name: "reservation_request_status_total", - Help: "Relay Reservation Request Status", + Name: "reservation_request_response_status_total", + Help: "Relay Reservation Request Response Status", }, []string{"status"}, ) - reservationRejectedTotal = prometheus.NewCounterVec( + reservationRejectionsTotal = prometheus.NewCounterVec( prometheus.CounterOpts{ Namespace: metricNamespace, - Name: "reservation_rejected_total", + Name: "reservation_rejections_total", Help: "Relay Reservation Rejected Reason", }, []string{"reason"}, ) - connectionTotal = prometheus.NewCounterVec( + connectionsTotal = prometheus.NewCounterVec( prometheus.CounterOpts{ Namespace: metricNamespace, - Name: "connection_total", + Name: "connections_total", Help: "Relay Connection Total", }, []string{"type"}, ) - connectionRequestStatusTotal = prometheus.NewCounterVec( + connectionRequestResponseStatusTotal = prometheus.NewCounterVec( prometheus.CounterOpts{ Namespace: metricNamespace, - Name: "connection_request_status_total", + Name: "connection_request_response_status_total", Help: "Relay Connection Request Status", }, []string{"status"}, ) - connectionRejectionTotal = prometheus.NewCounterVec( + connectionRejectionsTotal = prometheus.NewCounterVec( prometheus.CounterOpts{ Namespace: metricNamespace, - Name: "connection_rejected_total", + Name: "connection_rejections_total", Help: "Relay Connection Rejected Reason", }, []string{"reason"}, @@ -75,24 +76,24 @@ var ( }, ) - bytesTransferredTotal = prometheus.NewCounter( + dataTransferredBytesTotal = prometheus.NewCounter( prometheus.CounterOpts{ Namespace: metricNamespace, - Name: "bytes_transferred_total", + Name: "data_transferred_bytes_total", Help: "Bytes Transferred Total", }, ) collectors = []prometheus.Collector{ status, - reservationTotal, - reservationRequestStatusTotal, - reservationRejectedTotal, - connectionTotal, - connectionRequestStatusTotal, - connectionRejectionTotal, + reservationsTotal, + reservationRequestResponseStatusTotal, + reservationRejectionsTotal, + connectionsTotal, + connectionRequestResponseStatusTotal, + connectionRejectionsTotal, connectionDurationSeconds, - bytesTransferredTotal, + dataTransferredBytesTotal, } ) @@ -102,48 +103,26 @@ const ( requestStatusError = "error" ) -const ( - typeReceived = "received" - typeOpened = "opened" - typeClosed = "closed" -) - -const ( - rejectionReasonAttemptOverRelay = "attempt over relay" - rejectionReasonDisallowed = "disallowed" - rejectionReasonIPConstraintViolation = "ip constraint violation" - rejectionReasonResourceLimitExceeded = "resource limit exceeded" - rejectionReasonBadRequest = "bad request" - rejectionReasonNoReservation = "no reservation" - rejectionReasonClosed = "closed" -) - // MetricsTracer is the interface for tracking metrics for relay service type MetricsTracer interface { // RelayStatus tracks whether the service is currently active RelayStatus(enabled bool) - // ConnectionRequestReceived tracks a new relay connect request - ConnectionRequestReceived() // ConnectionOpened tracks metrics on opening a relay connection ConnectionOpened() // ConnectionClosed tracks metrics on closing a relay connection ConnectionClosed(d time.Duration) // ConnectionRequestHandled tracks metrics on handling a relay connection request - // rejectionReason is ignored for status other than `requestStatusRejected` - ConnectionRequestHandled(status string, rejectionReason string) + ConnectionRequestHandled(status pbv2.Status) - // ReservationRequestReceived tracks a new relay reservation request - ReservationRequestReceived() - // ReservationOpened tracks metrics on Opening a relay reservation - ReservationOpened() + // ReservationAllowed tracks metrics on opening or renewing a relay reservation + ReservationAllowed(isRenewal bool) // ReservationRequestClosed tracks metrics on closing a relay reservation ReservationClosed(cnt int) // ReservationRequestHandled tracks metrics on handling a relay reservation request - // rejectionReason is ignored for status other than `requestStatusRejected` - ReservationRequestHandled(status string, rejectionReason string) + ReservationRequestHandled(status pbv2.Status) - // BytesTransferred tracks the total bytes transferred(incoming + outgoing) by the relay service + // BytesTransferred tracks the total bytes transferred by the relay service BytesTransferred(cnt int) } @@ -182,81 +161,108 @@ func (mt *metricsTracer) RelayStatus(enabled bool) { } } -func (mt *metricsTracer) ConnectionRequestReceived() { - tags := metricshelper.GetStringSlice() - defer metricshelper.PutStringSlice(tags) - *tags = append(*tags, typeReceived) - - connectionTotal.WithLabelValues(*tags...).Add(1) -} - func (mt *metricsTracer) ConnectionOpened() { tags := metricshelper.GetStringSlice() defer metricshelper.PutStringSlice(tags) - *tags = append(*tags, typeOpened) + *tags = append(*tags, "opened") - connectionTotal.WithLabelValues(*tags...).Add(1) + connectionsTotal.WithLabelValues(*tags...).Add(1) } func (mt *metricsTracer) ConnectionClosed(d time.Duration) { tags := metricshelper.GetStringSlice() defer metricshelper.PutStringSlice(tags) - *tags = append(*tags, typeClosed) + *tags = append(*tags, "closed") - connectionTotal.WithLabelValues(*tags...).Add(1) + connectionsTotal.WithLabelValues(*tags...).Add(1) connectionDurationSeconds.Observe(d.Seconds()) } -func (mt *metricsTracer) ConnectionRequestHandled(status string, rejectionReason string) { +func (mt *metricsTracer) ConnectionRequestHandled(status pbv2.Status) { tags := metricshelper.GetStringSlice() defer metricshelper.PutStringSlice(tags) - *tags = append(*tags, status) - connectionRequestStatusTotal.WithLabelValues(*tags...).Add(1) - if status == requestStatusRejected { + respStatus := getResponseStatus(status) + + *tags = append(*tags, respStatus) + connectionRequestResponseStatusTotal.WithLabelValues(*tags...).Add(1) + if respStatus == requestStatusRejected { *tags = (*tags)[:0] - *tags = append(*tags, rejectionReason) - connectionRejectionTotal.WithLabelValues(*tags...).Add(1) + *tags = append(*tags, getRejectionReason(status)) + connectionRejectionsTotal.WithLabelValues(*tags...).Add(1) } } -func (mt *metricsTracer) ReservationRequestReceived() { - tags := metricshelper.GetStringSlice() - defer metricshelper.PutStringSlice(tags) - *tags = append(*tags, typeReceived) - - reservationTotal.WithLabelValues(*tags...).Add(1) -} - -func (mt *metricsTracer) ReservationOpened() { +func (mt *metricsTracer) ReservationAllowed(isRenewal bool) { tags := metricshelper.GetStringSlice() defer metricshelper.PutStringSlice(tags) - *tags = append(*tags, typeOpened) + if isRenewal { + *tags = append(*tags, "renewed") + } else { + *tags = append(*tags, "opened") + } - reservationTotal.WithLabelValues(*tags...).Add(1) + reservationsTotal.WithLabelValues(*tags...).Add(1) } func (mt *metricsTracer) ReservationClosed(cnt int) { tags := metricshelper.GetStringSlice() defer metricshelper.PutStringSlice(tags) - *tags = append(*tags, typeClosed) + *tags = append(*tags, "closed") - reservationTotal.WithLabelValues(*tags...).Add(float64(cnt)) + reservationsTotal.WithLabelValues(*tags...).Add(float64(cnt)) } -func (mt *metricsTracer) ReservationRequestHandled(status string, rejectionReason string) { +func (mt *metricsTracer) ReservationRequestHandled(status pbv2.Status) { tags := metricshelper.GetStringSlice() defer metricshelper.PutStringSlice(tags) - *tags = append(*tags, status) - reservationRequestStatusTotal.WithLabelValues(*tags...).Add(1) - if status == requestStatusRejected { + respStatus := getResponseStatus(status) + + *tags = append(*tags, respStatus) + reservationRequestResponseStatusTotal.WithLabelValues(*tags...).Add(1) + if respStatus == requestStatusRejected { *tags = (*tags)[:0] - *tags = append(*tags, rejectionReason) - reservationRejectedTotal.WithLabelValues(*tags...).Add(1) + *tags = append(*tags, getRejectionReason(status)) + reservationRejectionsTotal.WithLabelValues(*tags...).Add(1) } } func (mt *metricsTracer) BytesTransferred(cnt int) { - bytesTransferredTotal.Add(float64(cnt)) + dataTransferredBytesTotal.Add(float64(cnt)) +} + +func getResponseStatus(status pbv2.Status) string { + responseStatus := "unknown" + switch status { + case pbv2.Status_RESERVATION_REFUSED, + pbv2.Status_RESOURCE_LIMIT_EXCEEDED, + pbv2.Status_PERMISSION_DENIED, + pbv2.Status_NO_RESERVATION, + pbv2.Status_MALFORMED_MESSAGE: + + responseStatus = requestStatusRejected + case pbv2.Status_UNEXPECTED_MESSAGE, pbv2.Status_CONNECTION_FAILED: + responseStatus = requestStatusError + case pbv2.Status_OK: + responseStatus = requestStatusOK + } + return responseStatus +} + +func getRejectionReason(status pbv2.Status) string { + reason := "unknown" + switch status { + case pbv2.Status_RESERVATION_REFUSED: + reason = "ip constraint violation" + case pbv2.Status_RESOURCE_LIMIT_EXCEEDED: + reason = "resource limit exceeded" + case pbv2.Status_PERMISSION_DENIED: + reason = "permission denied" + case pbv2.Status_NO_RESERVATION: + reason = "no reservation" + case pbv2.Status_MALFORMED_MESSAGE: + reason = "malformed message" + } + return reason } diff --git a/p2p/protocol/circuitv2/relay/metrics_test.go b/p2p/protocol/circuitv2/relay/metrics_test.go index 2c9de6c415..9af23fec75 100644 --- a/p2p/protocol/circuitv2/relay/metrics_test.go +++ b/p2p/protocol/circuitv2/relay/metrics_test.go @@ -6,27 +6,27 @@ import ( "math/rand" "testing" "time" + + pbv2 "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/pb" ) func TestNoCoverNoAlloc(t *testing.T) { - statuses := []string{requestStatusOK, requestStatusRejected, requestStatusError} - rejectionReason := []string{"", rejectionReasonAttemptOverRelay, rejectionReasonBadRequest, rejectionReasonDisallowed} + statuses := []pbv2.Status{ + pbv2.Status_OK, + pbv2.Status_NO_RESERVATION, + pbv2.Status_RESOURCE_LIMIT_EXCEEDED, + pbv2.Status_PERMISSION_DENIED, + } mt := NewMetricsTracer() tests := map[string]func(){ "RelayStatus": func() { mt.RelayStatus(rand.Intn(2) == 1) }, - "ConnectionRequestReceived": func() { mt.ConnectionRequestReceived() }, "ConnectionOpened": func() { mt.ConnectionOpened() }, "ConnectionClosed": func() { mt.ConnectionClosed(time.Duration(rand.Intn(10)) * time.Second) }, - "ConnectionRequestHandled": func() { - mt.ConnectionRequestHandled(statuses[rand.Intn(len(statuses))], rejectionReason[rand.Intn(len(rejectionReason))]) - }, - "ReservationRequestReceived": func() { mt.ReservationRequestReceived() }, - "ReservationOpened": func() { mt.ReservationOpened() }, - "ReservationClosed": func() { mt.ReservationClosed(rand.Intn(10)) }, - "ReservationRequestHandled": func() { - mt.ReservationRequestHandled(statuses[rand.Intn(len(statuses))], rejectionReason[rand.Intn(len(rejectionReason))]) - }, - "BytesTransferred": func() { mt.BytesTransferred(rand.Intn(1000)) }, + "ConnectionRequestHandled": func() { mt.ConnectionRequestHandled(statuses[rand.Intn(len(statuses))]) }, + "ReservationAllowed": func() { mt.ReservationAllowed(rand.Intn(2) == 1) }, + "ReservationClosed": func() { mt.ReservationClosed(rand.Intn(10)) }, + "ReservationRequestHandled": func() { mt.ReservationRequestHandled(statuses[rand.Intn(len(statuses))]) }, + "BytesTransferred": func() { mt.BytesTransferred(rand.Intn(1000)) }, } for method, f := range tests { allocs := testing.AllocsPerRun(1000, f) diff --git a/p2p/protocol/circuitv2/relay/relay.go b/p2p/protocol/circuitv2/relay/relay.go index 8e98281368..81857827bf 100644 --- a/p2p/protocol/circuitv2/relay/relay.go +++ b/p2p/protocol/circuitv2/relay/relay.go @@ -162,41 +162,37 @@ func (r *Relay) handleStream(s network.Stream) { } // reset stream deadline as message has been read s.SetReadDeadline(time.Time{}) - switch msg.GetType() { case pbv2.HopMessage_RESERVE: - r.handleReserve(s) - + status := r.handleReserve(s) + if r.metricsTracer != nil { + r.metricsTracer.ReservationRequestHandled(status) + } case pbv2.HopMessage_CONNECT: - r.handleConnect(s, &msg) - + status := r.handleConnect(s, &msg) + if r.metricsTracer != nil { + r.metricsTracer.ConnectionRequestHandled(status) + } default: r.handleError(s, pbv2.Status_MALFORMED_MESSAGE) } } -func (r *Relay) handleReserve(s network.Stream) { +func (r *Relay) handleReserve(s network.Stream) pbv2.Status { defer s.Close() - - if r.metricsTracer != nil { - r.metricsTracer.ReservationRequestReceived() - } - p := s.Conn().RemotePeer() a := s.Conn().RemoteMultiaddr() if isRelayAddr(a) { log.Debugf("refusing relay reservation for %s; reservation attempt over relay connection") - r.handleErrorAndTrackMetrics(s, pbv2.HopMessage_RESERVE, pbv2.Status_PERMISSION_DENIED, - rejectionReasonAttemptOverRelay) - return + r.handleError(s, pbv2.Status_PERMISSION_DENIED) + return pbv2.Status_PERMISSION_DENIED } if r.acl != nil && !r.acl.AllowReserve(p, a) { log.Debugf("refusing relay reservation for %s; permission denied", p) - r.handleErrorAndTrackMetrics(s, pbv2.HopMessage_RESERVE, pbv2.Status_PERMISSION_DENIED, - rejectionReasonDisallowed) - return + r.handleError(s, pbv2.Status_PERMISSION_DENIED) + return pbv2.Status_PERMISSION_DENIED } r.mx.Lock() @@ -206,6 +202,7 @@ func (r *Relay) handleReserve(s network.Stream) { r.mx.Unlock() log.Debugf("refusing relay reservation for %s; relay closed", p) r.handleError(s, pbv2.Status_PERMISSION_DENIED) + return pbv2.Status_PERMISSION_DENIED } now := time.Now() @@ -214,9 +211,8 @@ func (r *Relay) handleReserve(s network.Stream) { if err := r.constraints.AddReservation(p, a); err != nil { r.mx.Unlock() log.Debugf("refusing relay reservation for %s; IP constraint violation: %s", p, err) - r.handleErrorAndTrackMetrics(s, pbv2.HopMessage_RESERVE, pbv2.Status_RESERVATION_REFUSED, - rejectionReasonIPConstraintViolation) - return + r.handleError(s, pbv2.Status_RESERVATION_REFUSED) + return pbv2.Status_RESERVATION_REFUSED } } @@ -224,8 +220,8 @@ func (r *Relay) handleReserve(s network.Stream) { r.rsvp[p] = expire r.host.ConnManager().TagPeer(p, "relay-reservation", ReservationTagWeight) r.mx.Unlock() - if !exists && r.metricsTracer != nil { - r.metricsTracer.ReservationOpened() + if r.metricsTracer != nil { + r.metricsTracer.ReservationAllowed(exists) } log.Debugf("reserving relay slot for %s", p) @@ -236,60 +232,50 @@ func (r *Relay) handleReserve(s network.Stream) { if err := r.writeResponse(s, pbv2.Status_OK, r.makeReservationMsg(p, expire), r.makeLimitMsg(p)); err != nil { log.Debugf("error writing reservation response; retracting reservation for %s", p) s.Reset() - if r.metricsTracer != nil { - r.metricsTracer.ReservationRequestHandled(requestStatusError, "") - } - } - - if r.metricsTracer != nil { - r.metricsTracer.ReservationRequestHandled(requestStatusOK, "") + return pbv2.Status_CONNECTION_FAILED } + return pbv2.Status_OK } -func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) { - if r.metricsTracer != nil { - r.metricsTracer.ConnectionRequestReceived() - } - +func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) pbv2.Status { src := s.Conn().RemotePeer() a := s.Conn().RemoteMultiaddr() span, err := r.scope.BeginSpan() if err != nil { log.Debugf("failed to begin relay transaction: %s", err) - r.handleErrorAndTrackMetrics(s, pbv2.HopMessage_CONNECT, pbv2.Status_RESOURCE_LIMIT_EXCEEDED, - rejectionReasonResourceLimitExceeded) - return + r.handleError(s, pbv2.Status_RESOURCE_LIMIT_EXCEEDED) + return pbv2.Status_RESOURCE_LIMIT_EXCEEDED } - fail := func(status pbv2.Status, rejectionReason string) { + fail := func(status pbv2.Status) { span.Done() - r.handleErrorAndTrackMetrics(s, pbv2.HopMessage_CONNECT, status, rejectionReason) + r.handleError(s, status) } // reserve buffers for the relay if err := span.ReserveMemory(2*r.rc.BufferSize, network.ReservationPriorityHigh); err != nil { log.Debugf("error reserving memory for relay: %s", err) - fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED, rejectionReasonResourceLimitExceeded) - return + fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED) + return pbv2.Status_RESOURCE_LIMIT_EXCEEDED } if isRelayAddr(a) { log.Debugf("refusing connection from %s; connection attempt over relay connection") - fail(pbv2.Status_PERMISSION_DENIED, rejectionReasonAttemptOverRelay) - return + fail(pbv2.Status_PERMISSION_DENIED) + return pbv2.Status_PERMISSION_DENIED } dest, err := util.PeerToPeerInfoV2(msg.GetPeer()) if err != nil { - fail(pbv2.Status_MALFORMED_MESSAGE, rejectionReasonBadRequest) - return + fail(pbv2.Status_MALFORMED_MESSAGE) + return pbv2.Status_MALFORMED_MESSAGE } if r.acl != nil && !r.acl.AllowConnect(src, s.Conn().RemoteMultiaddr(), dest.ID) { log.Debugf("refusing connection from %s to %s; permission denied", src, dest.ID) - fail(pbv2.Status_PERMISSION_DENIED, rejectionReasonDisallowed) - return + fail(pbv2.Status_PERMISSION_DENIED) + return pbv2.Status_PERMISSION_DENIED } r.mx.Lock() @@ -297,24 +283,24 @@ func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) { if !rsvp { r.mx.Unlock() log.Debugf("refusing connection from %s to %s; no reservation", src, dest.ID) - fail(pbv2.Status_NO_RESERVATION, rejectionReasonNoReservation) - return + fail(pbv2.Status_NO_RESERVATION) + return pbv2.Status_NO_RESERVATION } srcConns := r.conns[src] if srcConns >= r.rc.MaxCircuits { r.mx.Unlock() log.Debugf("refusing connection from %s to %s; too many connections from %s", src, dest.ID, src) - fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED, rejectionReasonResourceLimitExceeded) - return + fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED) + return pbv2.Status_RESOURCE_LIMIT_EXCEEDED } destConns := r.conns[dest.ID] if destConns >= r.rc.MaxCircuits { r.mx.Unlock() log.Debugf("refusing connection from %s to %s; too many connecitons to %s", src, dest.ID, dest.ID) - fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED, rejectionReasonResourceLimitExceeded) - return + fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED) + return pbv2.Status_RESOURCE_LIMIT_EXCEEDED } r.addConn(src) @@ -346,27 +332,27 @@ func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) { if err != nil { log.Debugf("error opening relay stream to %s: %s", dest.ID, err) cleanup() - r.handleErrorAndTrackMetrics(s, pbv2.HopMessage_CONNECT, pbv2.Status_CONNECTION_FAILED, "") - return + r.handleError(s, pbv2.Status_CONNECTION_FAILED) + return pbv2.Status_CONNECTION_FAILED } - fail = func(status pbv2.Status, rejectionReason string) { + fail = func(status pbv2.Status) { bs.Reset() cleanup() - r.handleErrorAndTrackMetrics(s, pbv2.HopMessage_CONNECT, status, rejectionReason) + r.handleError(s, status) } if err := bs.Scope().SetService(ServiceName); err != nil { log.Debugf("error attaching stream to relay service: %s", err) - fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED, rejectionReasonResourceLimitExceeded) - return + fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED) + return pbv2.Status_RESOURCE_LIMIT_EXCEEDED } // handshake if err := bs.Scope().ReserveMemory(maxMessageSize, network.ReservationPriorityAlways); err != nil { log.Debugf("error reserving memory for stream: %s", err) - fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED, rejectionReasonResourceLimitExceeded) - return + fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED) + return pbv2.Status_RESOURCE_LIMIT_EXCEEDED } defer bs.Scope().ReleaseMemory(maxMessageSize) @@ -384,8 +370,8 @@ func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) { err = wr.WriteMsg(&stopmsg) if err != nil { log.Debugf("error writing stop handshake") - fail(pbv2.Status_CONNECTION_FAILED, "") - return + fail(pbv2.Status_CONNECTION_FAILED) + return pbv2.Status_CONNECTION_FAILED } stopmsg.Reset() @@ -393,20 +379,20 @@ func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) { err = rd.ReadMsg(&stopmsg) if err != nil { log.Debugf("error reading stop response: %s", err.Error()) - fail(pbv2.Status_CONNECTION_FAILED, "") - return + fail(pbv2.Status_CONNECTION_FAILED) + return pbv2.Status_CONNECTION_FAILED } if t := stopmsg.GetType(); t != pbv2.StopMessage_STATUS { log.Debugf("unexpected stop response; not a status message (%d)", t) - fail(pbv2.Status_CONNECTION_FAILED, "") - return + fail(pbv2.Status_CONNECTION_FAILED) + return pbv2.Status_CONNECTION_FAILED } if status := stopmsg.GetStatus(); status != pbv2.Status_OK { log.Debugf("relay stop failure: %d", status) - fail(pbv2.Status_CONNECTION_FAILED, "") - return + fail(pbv2.Status_CONNECTION_FAILED) + return pbv2.Status_CONNECTION_FAILED } var response pbv2.HopMessage @@ -421,10 +407,7 @@ func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) { bs.Reset() s.Reset() cleanup() - if r.metricsTracer != nil { - r.metricsTracer.ConnectionRequestHandled(requestStatusError, "") - } - return + return pbv2.Status_CONNECTION_FAILED } // reset deadline @@ -454,9 +437,7 @@ func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) { go r.relayUnlimited(bs, s, dest.ID, src, done) } - if r.metricsTracer != nil { - r.metricsTracer.ConnectionRequestHandled(requestStatusOK, "") - } + return pbv2.Status_OK } func (r *Relay) addConn(p peer.ID) { @@ -553,7 +534,7 @@ func (r *Relay) copyWithBuffer(dst io.Writer, src io.Reader, buf []byte) (writte break } if r.metricsTracer != nil { - r.metricsTracer.BytesTransferred(nr + nw) + r.metricsTracer.BytesTransferred(nw) } } if er != nil { @@ -577,34 +558,6 @@ func (r *Relay) handleError(s network.Stream, status pbv2.Status) { } } -func (r *Relay) handleErrorAndTrackMetrics(s network.Stream, reqType pbv2.HopMessage_Type, status pbv2.Status, - rejectionReason string) { - r.handleError(s, status) - if r.metricsTracer != nil { - var reqStatus string - switch status { - case pbv2.Status_RESERVATION_REFUSED, - pbv2.Status_RESOURCE_LIMIT_EXCEEDED, - pbv2.Status_PERMISSION_DENIED, - pbv2.Status_NO_RESERVATION, - pbv2.Status_MALFORMED_MESSAGE: - - reqStatus = requestStatusRejected - case pbv2.Status_UNEXPECTED_MESSAGE, pbv2.Status_CONNECTION_FAILED: - reqStatus = requestStatusError - default: - reqStatus = "unknown" - } - - switch reqType { - case pbv2.HopMessage_CONNECT: - r.metricsTracer.ConnectionRequestHandled(reqStatus, rejectionReason) - case pbv2.HopMessage_RESERVE: - r.metricsTracer.ReservationRequestHandled(reqStatus, rejectionReason) - } - } -} - func (r *Relay) writeResponse(s network.Stream, status pbv2.Status, rsvp *pbv2.Reservation, limit *pbv2.Limit) error { wr := util.NewDelimitedWriter(s) From e24cfc7b2b94cb0af237b5142f866f37900f92f2 Mon Sep 17 00:00:00 2001 From: sukun Date: Mon, 6 Mar 2023 13:19:46 +0530 Subject: [PATCH 6/8] rename dashboard --- dashboards/relaysvc/relaysvc.json | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/dashboards/relaysvc/relaysvc.json b/dashboards/relaysvc/relaysvc.json index ac07eb3db2..058c1a9f6f 100644 --- a/dashboards/relaysvc/relaysvc.json +++ b/dashboards/relaysvc/relaysvc.json @@ -643,7 +643,7 @@ }, "editorMode": "code", "expr": "increase(libp2p_relaysvc_data_transferred_bytes_total[$__range])", - "legendFormat": "__auto", + "legendFormat": "data transferred", "range": true, "refId": "A" } @@ -1138,8 +1138,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -1211,8 +1210,8 @@ }, "timepicker": {}, "timezone": "", - "title": "Relay Service", + "title": "libp2p Relay Service", "uid": "C6RUfAx4z", - "version": 2, + "version": 3, "weekStart": "" } \ No newline at end of file From 97d18e5711d27dddf0d47479fd54a503d069149d Mon Sep 17 00:00:00 2001 From: sukun Date: Tue, 7 Mar 2023 12:38:53 +0530 Subject: [PATCH 7/8] address review comments --- dashboards/relaysvc/relaysvc.json | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/dashboards/relaysvc/relaysvc.json b/dashboards/relaysvc/relaysvc.json index 058c1a9f6f..fabeb50e3b 100644 --- a/dashboards/relaysvc/relaysvc.json +++ b/dashboards/relaysvc/relaysvc.json @@ -136,7 +136,7 @@ }, "id": 2, "options": { - "alignValue": "left", + "alignValue": "center", "legend": { "displayMode": "list", "placement": "bottom", @@ -1138,14 +1138,12 @@ "mode": "absolute", "steps": [ { - "color": "green" - }, - { - "color": "red", - "value": 80 + "color": "green", + "value": null } ] - } + }, + "unit": "s" }, "overrides": [] }, @@ -1175,22 +1173,11 @@ "uid": "${DS_PROMETHEUS}" }, "editorMode": "code", - "expr": "histogram_quantile(0.5, sum(rate(libp2p_relaysvc_connection_duration_seconds_bucket[$__rate_interval])) by (le))", - "legendFormat": "50th percentile", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.99, sum(rate(libp2p_relaysvc_connection_duration_seconds_bucket[$__rate_interval])) by (le))", + "expr": "rate(libp2p_relaysvc_connection_duration_seconds_sum[$__range])/rate(libp2p_relaysvc_connection_duration_seconds_count[$__range])\n", "hide": false, - "legendFormat": "99th percentile", + "legendFormat": "avg", "range": true, - "refId": "C" + "refId": "A" } ], "title": "Connection Duration", @@ -1212,6 +1199,6 @@ "timezone": "", "title": "libp2p Relay Service", "uid": "C6RUfAx4z", - "version": 3, + "version": 4, "weekStart": "" } \ No newline at end of file From 77cfebd1fcb21ceb99789e6c5d6a8d10848e8323 Mon Sep 17 00:00:00 2001 From: sukun Date: Tue, 7 Mar 2023 12:52:53 +0530 Subject: [PATCH 8/8] change label to rolling avg --- dashboards/relaysvc/relaysvc.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dashboards/relaysvc/relaysvc.json b/dashboards/relaysvc/relaysvc.json index fabeb50e3b..47dacc7c82 100644 --- a/dashboards/relaysvc/relaysvc.json +++ b/dashboards/relaysvc/relaysvc.json @@ -1175,7 +1175,7 @@ "editorMode": "code", "expr": "rate(libp2p_relaysvc_connection_duration_seconds_sum[$__range])/rate(libp2p_relaysvc_connection_duration_seconds_count[$__range])\n", "hide": false, - "legendFormat": "avg", + "legendFormat": "rolling average", "range": true, "refId": "A" } @@ -1199,6 +1199,6 @@ "timezone": "", "title": "libp2p Relay Service", "uid": "C6RUfAx4z", - "version": 4, + "version": 5, "weekStart": "" } \ No newline at end of file