mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-12 05:37:32 +00:00
util/clientmetrics: add new package to add metrics to the client
And annotate magicsock as a start. And add localapi and debug handlers with the Prometheus-format exporter. Updates #3307 Change-Id: I47c5d535fe54424741df143d052760387248f8d3 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:

committed by
Brad Fitzpatrick

parent
c5d572f371
commit
57b039c51d
@@ -51,6 +51,7 @@ import (
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/types/netmap"
|
||||
"tailscale.com/types/nettype"
|
||||
"tailscale.com/util/clientmetric"
|
||||
"tailscale.com/util/uniq"
|
||||
"tailscale.com/version"
|
||||
"tailscale.com/wgengine/monitor"
|
||||
@@ -1167,7 +1168,9 @@ var errNetworkDown = errors.New("magicsock: network down")
|
||||
func (c *Conn) networkDown() bool { return !c.networkUp.Get() }
|
||||
|
||||
func (c *Conn) Send(b []byte, ep conn.Endpoint) error {
|
||||
metricSendData.Add(1)
|
||||
if c.networkDown() {
|
||||
metricSendDataNetworkDown.Add(1)
|
||||
return errNetworkDown
|
||||
}
|
||||
return ep.(*endpoint).send(b)
|
||||
@@ -1191,9 +1194,14 @@ func (c *Conn) sendUDP(ipp netaddr.IPPort, b []byte) (sent bool, err error) {
|
||||
}
|
||||
ua := udpAddrPool.Get().(*net.UDPAddr)
|
||||
sent, err = c.sendUDPStd(ipp.UDPAddrAt(ua), b)
|
||||
if err == nil {
|
||||
if err != nil {
|
||||
metricSendUDPError.Add(1)
|
||||
} else {
|
||||
// Only return it to the pool on success; Issue 3122.
|
||||
udpAddrPool.Put(ua)
|
||||
if sent {
|
||||
metricSendUDP.Add(1)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1239,6 +1247,7 @@ func (c *Conn) sendAddr(addr netaddr.IPPort, pubKey key.NodePublic, b []byte) (s
|
||||
|
||||
ch := c.derpWriteChanOfAddr(addr, pubKey)
|
||||
if ch == nil {
|
||||
metricSendDERPErrorChan.Add(1)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
@@ -1252,10 +1261,13 @@ func (c *Conn) sendAddr(addr netaddr.IPPort, pubKey key.NodePublic, b []byte) (s
|
||||
|
||||
select {
|
||||
case <-c.donec:
|
||||
metricSendDERPErrorClosed.Add(1)
|
||||
return false, errConnClosed
|
||||
case ch <- derpWriteRequest{addr, pubKey, pkt}:
|
||||
metricSendDERPQueued.Add(1)
|
||||
return true, nil
|
||||
default:
|
||||
metricSendDERPErrorQueue.Add(1)
|
||||
// Too many writes queued. Drop packet.
|
||||
return false, errDropDerpPacket
|
||||
}
|
||||
@@ -1367,6 +1379,7 @@ func (c *Conn) derpWriteChanOfAddr(addr netaddr.IPPort, peer key.NodePublic) cha
|
||||
*ad.lastWrite = time.Now()
|
||||
ad.createTime = time.Now()
|
||||
c.activeDerp[regionID] = ad
|
||||
metricNumDERPConns.Set(int64(len(c.activeDerp)))
|
||||
c.logActiveDerpLocked()
|
||||
c.setPeerLastDerpLocked(peer, regionID, regionID)
|
||||
c.scheduleCleanStaleDerpLocked()
|
||||
@@ -1618,6 +1631,7 @@ func (c *Conn) receiveIPv6(b []byte) (int, conn.Endpoint, error) {
|
||||
return 0, nil, err
|
||||
}
|
||||
if ep, ok := c.receiveIP(b[:n], ipp, &c.ippEndpoint6); ok {
|
||||
metricRecvDataIPv6.Add(1)
|
||||
return n, ep, nil
|
||||
}
|
||||
}
|
||||
@@ -1633,6 +1647,7 @@ func (c *Conn) receiveIPv4(b []byte) (n int, ep conn.Endpoint, err error) {
|
||||
return 0, nil, err
|
||||
}
|
||||
if ep, ok := c.receiveIP(b[:n], ipp, &c.ippEndpoint4); ok {
|
||||
metricRecvDataIPv4.Add(1)
|
||||
return n, ep, nil
|
||||
}
|
||||
}
|
||||
@@ -1691,6 +1706,7 @@ func (c *connBind) receiveDERP(b []byte) (n int, ep conn.Endpoint, err error) {
|
||||
// No data read occurred. Wait for another packet.
|
||||
continue
|
||||
}
|
||||
metricRecvDataDERP.Add(1)
|
||||
return n, ep, nil
|
||||
}
|
||||
return 0, nil, net.ErrClosed
|
||||
@@ -1762,6 +1778,13 @@ func (c *Conn) sendDiscoMessage(dst netaddr.IPPort, dstKey key.NodePublic, dstDi
|
||||
di := c.discoInfoLocked(dstDisco)
|
||||
c.mu.Unlock()
|
||||
|
||||
isDERP := dst.IP() == derpMagicIPAddr
|
||||
if isDERP {
|
||||
metricSendDiscoDERP.Add(1)
|
||||
} else {
|
||||
metricSendDiscoUDP.Add(1)
|
||||
}
|
||||
|
||||
box := di.sharedKey.Seal(m.AppendMarshal(nil))
|
||||
pkt = append(pkt, box...)
|
||||
sent, err = c.sendAddr(dst, dstKey, pkt)
|
||||
@@ -1773,6 +1796,11 @@ func (c *Conn) sendDiscoMessage(dst netaddr.IPPort, dstKey key.NodePublic, dstDi
|
||||
}
|
||||
c.logf("[v1] magicsock: disco: %v->%v (%v, %v) sent %v", c.discoShort, dstDisco.ShortString(), node, derpStr(dst.String()), disco.MessageSummary(m))
|
||||
}
|
||||
if isDERP {
|
||||
metricSentDiscoDERP.Add(1)
|
||||
} else {
|
||||
metricSentDiscoUDP.Add(1)
|
||||
}
|
||||
} else if err == nil {
|
||||
// Can't send. (e.g. no IPv6 locally)
|
||||
} else {
|
||||
@@ -1833,6 +1861,7 @@ func (c *Conn) handleDiscoMessage(msg []byte, src netaddr.IPPort, derpNodeSrc ke
|
||||
}
|
||||
|
||||
if !c.peerMap.anyEndpointForDiscoKey(sender) {
|
||||
metricRecvDiscoBadPeer.Add(1)
|
||||
if debugDisco {
|
||||
c.logf("magicsock: disco: ignoring disco-looking frame, don't know endpoint for %v", sender.ShortString())
|
||||
}
|
||||
@@ -1860,7 +1889,7 @@ func (c *Conn) handleDiscoMessage(msg []byte, src netaddr.IPPort, derpNodeSrc ke
|
||||
if debugDisco {
|
||||
c.logf("magicsock: disco: failed to open naclbox from %v (wrong rcpt?)", sender)
|
||||
}
|
||||
// TODO(bradfitz): add some counter for this that logs rarely
|
||||
metricRecvDiscoBadKey.Add(1)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1874,14 +1903,23 @@ func (c *Conn) handleDiscoMessage(msg []byte, src netaddr.IPPort, derpNodeSrc ke
|
||||
// newer version of Tailscale that we don't
|
||||
// understand. Not even worth logging about, lest it
|
||||
// be too spammy for old clients.
|
||||
// TODO(bradfitz): add some counter for this that logs rarely
|
||||
metricRecvDiscoBadParse.Add(1)
|
||||
return
|
||||
}
|
||||
|
||||
isDERP := src.IP() == derpMagicIPAddr
|
||||
if isDERP {
|
||||
metricRecvDiscoDERP.Add(1)
|
||||
} else {
|
||||
metricRecvDiscoUDP.Add(1)
|
||||
}
|
||||
|
||||
switch dm := dm.(type) {
|
||||
case *disco.Ping:
|
||||
metricRecvDiscoPing.Add(1)
|
||||
c.handlePingLocked(dm, src, di, derpNodeSrc)
|
||||
case *disco.Pong:
|
||||
metricRecvDiscoPong.Add(1)
|
||||
// There might be multiple nodes for the sender's DiscoKey.
|
||||
// Ask each to handle it, stopping once one reports that
|
||||
// the Pong's TxID was theirs.
|
||||
@@ -1892,7 +1930,8 @@ func (c *Conn) handleDiscoMessage(msg []byte, src netaddr.IPPort, derpNodeSrc ke
|
||||
}
|
||||
})
|
||||
case *disco.CallMeMaybe:
|
||||
if src.IP() != derpMagicIPAddr || derpNodeSrc.IsZero() {
|
||||
metricRecvDiscoCallMeMaybe.Add(1)
|
||||
if !isDERP || derpNodeSrc.IsZero() {
|
||||
// CallMeMaybe messages should only come via DERP.
|
||||
c.logf("[unexpected] CallMeMaybe packets should only come via DERP")
|
||||
return
|
||||
@@ -1900,6 +1939,7 @@ func (c *Conn) handleDiscoMessage(msg []byte, src netaddr.IPPort, derpNodeSrc ke
|
||||
nodeKey := derpNodeSrc
|
||||
ep, ok := c.peerMap.endpointForNodeKey(nodeKey)
|
||||
if !ok {
|
||||
metricRecvDiscoCallMeMaybeBadNode.Add(1)
|
||||
c.logf("magicsock: disco: ignoring CallMeMaybe from %v; %v is unknown", sender.ShortString(), derpNodeSrc.ShortString())
|
||||
return
|
||||
}
|
||||
@@ -1907,6 +1947,7 @@ func (c *Conn) handleDiscoMessage(msg []byte, src netaddr.IPPort, derpNodeSrc ke
|
||||
return
|
||||
}
|
||||
if ep.discoKey != di.discoKey {
|
||||
metricRecvDiscoCallMeMaybeBadDisco.Add(1)
|
||||
c.logf("[unexpected] CallMeMaybe from peer via DERP whose netmap discokey != disco source")
|
||||
return
|
||||
}
|
||||
@@ -2244,6 +2285,8 @@ func (c *Conn) SetNetworkMap(nm *netmap.NetworkMap) {
|
||||
}
|
||||
}
|
||||
|
||||
metricNumPeers.Set(int64(len(nm.Peers)))
|
||||
|
||||
c.logf("[v1] magicsock: got updated network map; %d peers", len(nm.Peers))
|
||||
if numNoDisco != 0 {
|
||||
c.logf("[v1] magicsock: %d DERP-only peers (no discokey)", numNoDisco)
|
||||
@@ -2347,6 +2390,7 @@ func (c *Conn) closeDerpLocked(node int, why string) {
|
||||
go ad.c.Close()
|
||||
ad.cancel()
|
||||
delete(c.activeDerp, node)
|
||||
metricNumDERPConns.Set(int64(len(c.activeDerp)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3998,3 +4042,41 @@ func (di *discoInfo) setNodeKey(nk key.NodePublic) {
|
||||
di.lastNodeKey = nk
|
||||
di.lastNodeKeyTime = time.Now()
|
||||
}
|
||||
|
||||
var (
|
||||
metricNumPeers = clientmetric.NewGauge("magicsock_netmap_num_peers")
|
||||
metricNumDERPConns = clientmetric.NewGauge("magicsock_num_derp_conns")
|
||||
|
||||
// Sends (data or disco)
|
||||
metricSendDERPQueued = clientmetric.NewCounter("magicsock_send_derp_queued")
|
||||
metricSendDERPErrorChan = clientmetric.NewCounter("magicsock_send_derp_error_chan")
|
||||
metricSendDERPErrorClosed = clientmetric.NewCounter("magicsock_send_derp_error_closed")
|
||||
metricSendDERPErrorQueue = clientmetric.NewCounter("magicsock_send_derp_error_queue")
|
||||
metricSendUDP = clientmetric.NewCounter("magicsock_send_udp")
|
||||
metricSendUDPError = clientmetric.NewCounter("magicsock_send_udp_error")
|
||||
|
||||
// Data packets (non-disco)
|
||||
metricSendData = clientmetric.NewCounter("magicsock_send_data")
|
||||
metricSendDataNetworkDown = clientmetric.NewCounter("magicsock_send_data_network_down")
|
||||
metricRecvData = clientmetric.NewCounter("magicsock_recv_data")
|
||||
metricRecvDataDERP = clientmetric.NewCounter("magicsock_recv_data_derp")
|
||||
metricRecvDataIPv4 = clientmetric.NewCounter("magicsock_recv_data_ipv4")
|
||||
metricRecvDataIPv6 = clientmetric.NewCounter("magicsock_recv_data_ipv6")
|
||||
|
||||
// Disco packets
|
||||
metricSendDiscoUDP = clientmetric.NewCounter("magicsock_disco_send_udp")
|
||||
metricSendDiscoDERP = clientmetric.NewCounter("magicsock_disco_send_derp")
|
||||
metricSentDiscoUDP = clientmetric.NewCounter("magicsock_disco_sent_udp")
|
||||
metricSentDiscoDERP = clientmetric.NewCounter("magicsock_disco_sent_derp")
|
||||
metricRecvDiscoBadPeer = clientmetric.NewCounter("magicsock_disco_recv_bad_peer")
|
||||
metricRecvDiscoBadKey = clientmetric.NewCounter("magicsock_disco_recv_bad_key")
|
||||
metricRecvDiscoBadParse = clientmetric.NewCounter("magicsock_disco_recv_bad_parse")
|
||||
|
||||
metricRecvDiscoUDP = clientmetric.NewCounter("magicsock_disco_recv_udp")
|
||||
metricRecvDiscoDERP = clientmetric.NewCounter("magicsock_disco_recv_derp")
|
||||
metricRecvDiscoPing = clientmetric.NewCounter("magicsock_disco_recv_ping")
|
||||
metricRecvDiscoPong = clientmetric.NewCounter("magicsock_disco_recv_pong")
|
||||
metricRecvDiscoCallMeMaybe = clientmetric.NewCounter("magicsock_disco_recv_callmemaybe")
|
||||
metricRecvDiscoCallMeMaybeBadNode = clientmetric.NewCounter("magicsock_disco_recv_callmemaybe_bad_node")
|
||||
metricRecvDiscoCallMeMaybeBadDisco = clientmetric.NewCounter("magicsock_disco_recv_callmemaybe_bad_disco")
|
||||
)
|
||||
|
Reference in New Issue
Block a user