github.com/ethereum/go-ethereum@v1.16.1/p2p/metrics.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Contains the meters and timers used by the networking layer.
    18  
    19  package p2p
    20  
    21  import (
    22  	"errors"
    23  	"net"
    24  
    25  	"github.com/ethereum/go-ethereum/metrics"
    26  )
    27  
    28  const (
    29  	// HandleHistName is the prefix of the per-packet serving time histograms.
    30  	HandleHistName = "p2p/handle"
    31  
    32  	// ingressMeterName is the prefix of the per-packet inbound metrics.
    33  	ingressMeterName = "p2p/ingress"
    34  
    35  	// egressMeterName is the prefix of the per-packet outbound metrics.
    36  	egressMeterName = "p2p/egress"
    37  )
    38  
    39  var (
    40  	activePeerGauge         = metrics.NewRegisteredGauge("p2p/peers", nil)
    41  	activeInboundPeerGauge  = metrics.NewRegisteredGauge("p2p/peers/inbound", nil)
    42  	activeOutboundPeerGauge = metrics.NewRegisteredGauge("p2p/peers/outbound", nil)
    43  
    44  	ingressTrafficMeter = metrics.NewRegisteredMeter("p2p/ingress", nil)
    45  	egressTrafficMeter  = metrics.NewRegisteredMeter("p2p/egress", nil)
    46  
    47  	// general ingress/egress connection meters
    48  	serveMeter          = metrics.NewRegisteredMeter("p2p/serves", nil)
    49  	serveSuccessMeter   = metrics.NewRegisteredMeter("p2p/serves/success", nil)
    50  	dialMeter           = metrics.NewRegisteredMeter("p2p/dials", nil)
    51  	dialSuccessMeter    = metrics.NewRegisteredMeter("p2p/dials/success", nil)
    52  	dialConnectionError = metrics.NewRegisteredMeter("p2p/dials/error/connection", nil) // dial timeout; no route to host; connection refused; network is unreachable
    53  
    54  	// count peers that stayed connected for at least 1 min
    55  	serve1MinSuccessMeter = metrics.NewRegisteredMeter("p2p/serves/success/1min", nil)
    56  	dial1MinSuccessMeter  = metrics.NewRegisteredMeter("p2p/dials/success/1min", nil)
    57  
    58  	// handshake error meters
    59  	dialTooManyPeers        = metrics.NewRegisteredMeter("p2p/dials/error/saturated", nil)
    60  	dialAlreadyConnected    = metrics.NewRegisteredMeter("p2p/dials/error/known", nil)
    61  	dialSelf                = metrics.NewRegisteredMeter("p2p/dials/error/self", nil)
    62  	dialUselessPeer         = metrics.NewRegisteredMeter("p2p/dials/error/useless", nil)
    63  	dialUnexpectedIdentity  = metrics.NewRegisteredMeter("p2p/dials/error/id/unexpected", nil)
    64  	dialEncHandshakeError   = metrics.NewRegisteredMeter("p2p/dials/error/rlpx/enc", nil)   // EOF; connection reset during handshake; message too big; i/o timeout
    65  	dialProtoHandshakeError = metrics.NewRegisteredMeter("p2p/dials/error/rlpx/proto", nil) // EOF
    66  
    67  	// capture the rest of errors that are not handled by the above meters
    68  	dialOtherError = metrics.NewRegisteredMeter("p2p/dials/error/other", nil)
    69  
    70  	// handshake error meters for inbound connections
    71  	serveTooManyPeers        = metrics.NewRegisteredMeter("p2p/serves/error/saturated", nil)
    72  	serveAlreadyConnected    = metrics.NewRegisteredMeter("p2p/serves/error/known", nil)
    73  	serveSelf                = metrics.NewRegisteredMeter("p2p/serves/error/self", nil)
    74  	serveUselessPeer         = metrics.NewRegisteredMeter("p2p/serves/error/useless", nil)
    75  	serveUnexpectedIdentity  = metrics.NewRegisteredMeter("p2p/serves/error/id/unexpected", nil)
    76  	serveEncHandshakeError   = metrics.NewRegisteredMeter("p2p/serves/error/rlpx/enc", nil) //EOF; connection reset during handshake; (message too big?)
    77  	serveProtoHandshakeError = metrics.NewRegisteredMeter("p2p/serves/error/rlpx/proto", nil)
    78  
    79  	// capture the rest of errors that are not handled by the above meters
    80  	serveOtherError = metrics.NewRegisteredMeter("p2p/serves/error/other", nil)
    81  )
    82  
    83  // markDialError matches errors that occur while setting up a dial connection to the
    84  // corresponding meter. We don't maintain meters for evert possible error, just for
    85  // the most interesting ones.
    86  func markDialError(err error) {
    87  	if !metrics.Enabled() {
    88  		return
    89  	}
    90  
    91  	var reason DiscReason
    92  	var handshakeErr *protoHandshakeError
    93  	d := errors.As(err, &reason)
    94  	switch {
    95  	case d && reason == DiscTooManyPeers:
    96  		dialTooManyPeers.Mark(1)
    97  	case d && reason == DiscAlreadyConnected:
    98  		dialAlreadyConnected.Mark(1)
    99  	case d && reason == DiscSelf:
   100  		dialSelf.Mark(1)
   101  	case d && reason == DiscUselessPeer:
   102  		dialUselessPeer.Mark(1)
   103  	case d && reason == DiscUnexpectedIdentity:
   104  		dialUnexpectedIdentity.Mark(1)
   105  	case errors.As(err, &handshakeErr):
   106  		dialProtoHandshakeError.Mark(1)
   107  	case errors.Is(err, errEncHandshakeError):
   108  		dialEncHandshakeError.Mark(1)
   109  	default:
   110  		dialOtherError.Mark(1)
   111  	}
   112  }
   113  
   114  // markServeError matches errors that occur while serving an inbound connection
   115  // to the corresponding meter.
   116  func markServeError(err error) {
   117  	if !metrics.Enabled() {
   118  		return
   119  	}
   120  
   121  	var reason DiscReason
   122  	var handshakeErr *protoHandshakeError
   123  	d := errors.As(err, &reason)
   124  	switch {
   125  	case d && reason == DiscTooManyPeers:
   126  		serveTooManyPeers.Mark(1)
   127  	case d && reason == DiscAlreadyConnected:
   128  		serveAlreadyConnected.Mark(1)
   129  	case d && reason == DiscSelf:
   130  		serveSelf.Mark(1)
   131  	case d && reason == DiscUselessPeer:
   132  		serveUselessPeer.Mark(1)
   133  	case d && reason == DiscUnexpectedIdentity:
   134  		serveUnexpectedIdentity.Mark(1)
   135  	case errors.As(err, &handshakeErr):
   136  		serveProtoHandshakeError.Mark(1)
   137  	case errors.Is(err, errEncHandshakeError):
   138  		serveEncHandshakeError.Mark(1)
   139  	default:
   140  		serveOtherError.Mark(1)
   141  	}
   142  }
   143  
   144  // meteredConn is a wrapper around a net.Conn that meters both the
   145  // inbound and outbound network traffic.
   146  type meteredConn struct {
   147  	net.Conn
   148  }
   149  
   150  // newMeteredConn creates a new metered connection, bumps the ingress or egress
   151  // connection meter and also increases the metered peer count. If the metrics
   152  // system is disabled, function returns the original connection.
   153  func newMeteredConn(conn net.Conn) net.Conn {
   154  	if !metrics.Enabled() {
   155  		return conn
   156  	}
   157  	return &meteredConn{Conn: conn}
   158  }
   159  
   160  // Read delegates a network read to the underlying connection, bumping the common
   161  // and the peer ingress traffic meters along the way.
   162  func (c *meteredConn) Read(b []byte) (n int, err error) {
   163  	n, err = c.Conn.Read(b)
   164  	ingressTrafficMeter.Mark(int64(n))
   165  	return n, err
   166  }
   167  
   168  // Write delegates a network write to the underlying connection, bumping the common
   169  // and the peer egress traffic meters along the way.
   170  func (c *meteredConn) Write(b []byte) (n int, err error) {
   171  	n, err = c.Conn.Write(b)
   172  	egressTrafficMeter.Mark(int64(n))
   173  	return n, err
   174  }