blob: a3f5d24ba683e11d8e067f71f41fe0be383b66ad [file] [log] [blame]
Allen Li325c0762017-03-02 15:00:19 -08001# Copyright 2017 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Network metrics."""
6
Allen Li13bdf0c2017-03-02 15:18:16 -08007from __future__ import absolute_import
Allen Li13bdf0c2017-03-02 15:18:16 -08008
Allen Lieb107022017-05-04 13:19:17 -07009import collections
Chris McDonald59650c32021-07-20 15:29:28 -060010import logging
Allen Lib6bb5f82017-08-21 15:11:57 -070011import socket
Allen Lieb107022017-05-04 13:19:17 -070012
Chris McDonald59650c32021-07-20 15:29:28 -060013from chromite.third_party.infra_libs import ts_mon
Mike Frysingercb56b642019-08-25 15:33:08 -040014import psutil # pylint: disable=import-error
Allen Li325c0762017-03-02 15:00:19 -080015
Allen Lia9c6e802017-07-11 15:42:47 -070016from chromite.lib import metrics
Mike Frysinger8d6a51d2021-02-12 07:40:03 -050017
Allen Li325c0762017-03-02 15:00:19 -080018
19logger = logging.getLogger(__name__)
20
21_BOOT_TIME = psutil.boot_time()
22
Allen Lia9c6e802017-07-11 15:42:47 -070023_net_bytes_metric = metrics.CounterMetric(
Allen Lieb107022017-05-04 13:19:17 -070024 'dev/net/bytes', start_time=_BOOT_TIME,
Allen Li22989bd2017-07-12 10:34:37 -070025 description='Number of bytes up/down on interface.')
Allen Lia9c6e802017-07-11 15:42:47 -070026_net_packets_metric = metrics.CounterMetric(
Allen Lieb107022017-05-04 13:19:17 -070027 'dev/net/packets', start_time=_BOOT_TIME,
Allen Li22989bd2017-07-12 10:34:37 -070028 description='Number of packets up/down on interface.')
Allen Lia9c6e802017-07-11 15:42:47 -070029_net_errors_metric = metrics.CounterMetric(
Allen Lieb107022017-05-04 13:19:17 -070030 'dev/net/errors', start_time=_BOOT_TIME,
31 description='Total number of errors up/down on interface.')
Allen Lia9c6e802017-07-11 15:42:47 -070032_net_dropped_metric = metrics.CounterMetric(
Allen Lieb107022017-05-04 13:19:17 -070033 'dev/net/dropped', start_time=_BOOT_TIME,
34 description='Total number of dropped packages up/down on interface.')
35
Allen Lia9c6e802017-07-11 15:42:47 -070036_net_if_isup_metric = metrics.BooleanMetric(
Allen Li325c0762017-03-02 15:00:19 -080037 'dev/net/isup',
38 description='Whether interface is up or down.')
Allen Lia9c6e802017-07-11 15:42:47 -070039_net_if_duplex_metric = metrics.GaugeMetric(
Allen Li325c0762017-03-02 15:00:19 -080040 'dev/net/duplex',
41 description='Whether interface supports full or half duplex.')
Allen Lia9c6e802017-07-11 15:42:47 -070042_net_if_speed_metric = metrics.GaugeMetric(
Allen Li325c0762017-03-02 15:00:19 -080043 'dev/net/speed',
44 description='Network interface speed in Mb.')
Allen Lia9c6e802017-07-11 15:42:47 -070045_net_if_mtu_metric = metrics.GaugeMetric(
Allen Li325c0762017-03-02 15:00:19 -080046 'dev/net/mtu',
47 description='Network interface MTU in B.')
48
49
50def collect_net_info():
51 """Collect network metrics."""
Allen Lieb107022017-05-04 13:19:17 -070052 _collect_net_io_duplex_counters()
Allen Li325c0762017-03-02 15:00:19 -080053 _collect_net_if_stats()
Allen Lib6bb5f82017-08-21 15:11:57 -070054 _collect_fqdn()
Prathmesh Prabhu07f80872017-08-21 15:09:33 -070055 _collect_net_if_addrs()
Allen Li325c0762017-03-02 15:00:19 -080056
57
Allen Lieb107022017-05-04 13:19:17 -070058# Network IO metrics to collect
59_IOMetric = collections.namedtuple('_IOMetric', ['metric', 'up_counter_name',
60 'down_counter_name'])
61
62_net_io_duplex_metrics = (
Allen Li22989bd2017-07-12 10:34:37 -070063 _IOMetric(metric=_net_bytes_metric,
64 up_counter_name='bytes_sent',
65 down_counter_name='bytes_recv'),
66 _IOMetric(metric=_net_packets_metric,
67 up_counter_name='packets_sent',
68 down_counter_name='packets_recv'),
69 _IOMetric(metric=_net_errors_metric,
70 up_counter_name='errout',
71 down_counter_name='errin'),
72 _IOMetric(metric=_net_dropped_metric,
73 up_counter_name='dropout',
74 down_counter_name='dropin'),
Allen Lieb107022017-05-04 13:19:17 -070075)
76
77
78def _collect_net_io_duplex_counters():
79 """Collect metrics for network IO duplex counters."""
80 for nic, counters in _net_io_iter():
81 fields = {'interface': nic}
82 for metric, up_counter_name, down_counter_name in _net_io_duplex_metrics:
83 try:
84 metric.set(getattr(counters, up_counter_name),
85 fields=dict(direction='up', **fields))
86 metric.set(getattr(counters, down_counter_name),
87 fields=dict(direction='down', **fields))
Allen Li07196972018-05-08 13:49:08 -070088 except ts_mon.MonitoringDecreasingValueError as ex:
Allen Lieb107022017-05-04 13:19:17 -070089 # This normally shouldn't happen, but might if the network
90 # driver module is reloaded, so log an error and continue
91 # instead of raising an exception.
92 logger.warning(str(ex))
93
94
Allen Li4bb931f2017-05-04 13:11:56 -070095def _net_io_iter():
96 """Generate network IO information."""
97 nics = psutil.net_io_counters(pernic=True)
Mike Frysinger0bdbc102019-06-13 15:27:29 -040098 for nic, counters in nics.items():
Allen Li4bb931f2017-05-04 13:11:56 -070099 if _is_virtual_netif(nic):
100 continue
101 yield nic, counters
102
103
Allen Li325c0762017-03-02 15:00:19 -0800104_net_if_metrics = (
Allen Li22989bd2017-07-12 10:34:37 -0700105 (_net_if_isup_metric, 'isup'),
106 (_net_if_duplex_metric, 'duplex'),
107 (_net_if_speed_metric, 'speed'),
108 (_net_if_mtu_metric, 'mtu'),
Allen Li325c0762017-03-02 15:00:19 -0800109)
110
111
112def _collect_net_if_stats():
113 """Collect metrics for network interface stats."""
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400114 for nic, stats in psutil.net_if_stats().items():
Allen Li325c0762017-03-02 15:00:19 -0800115 if _is_virtual_netif(nic):
116 continue
117 fields = {'interface': nic}
118 for metric, counter_name in _net_if_metrics:
119 metric.set(getattr(stats, counter_name), fields=fields)
120
121
Prathmesh Prabhu07f80872017-08-21 15:09:33 -0700122_net_if_addrs_metrics = metrics.StringMetric(
123 'dev/net/address',
124 description='Network address of physical network interfaces.')
125_family_field_strings = {
126 psutil.AF_LINK: 'AF_LINK',
127 socket.AF_INET: 'AF_INET',
128 socket.AF_INET6: 'AF_INET6',
129}
130
131
132def _collect_net_if_addrs():
133 """Collects network addresses as metrics."""
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400134 for nic, addresses in psutil.net_if_addrs().items():
Prathmesh Prabhu07f80872017-08-21 15:09:33 -0700135 if _is_virtual_netif(nic):
136 continue
137 for address in addresses:
138 fields = {
139 'interface': nic,
140 'family': _family_field_strings.get(address.family, 'UNKNOWN'),
141 }
142 _net_if_addrs_metrics.set(address.address, fields)
143
144
Allen Li325c0762017-03-02 15:00:19 -0800145def _is_virtual_netif(nic):
Allen Li22989bd2017-07-12 10:34:37 -0700146 """Return whether the network interface is virtual."""
147 # TODO(ayatane): Use a different way of identifying virtual interfaces
148 return nic.startswith('veth')
Allen Lib6bb5f82017-08-21 15:11:57 -0700149
150
151_fqdn_metric = metrics.StringMetric('net/fqdn', description='FQDN')
152
153
154def _collect_fqdn():
155 fqdn = socket.getfqdn()
156 logging.debug('Got FQDN: %s', fqdn)
157 _fqdn_metric.set(fqdn)