blob: e5768773b05aaafe09cd51f553861c65f9143843 [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
8from __future__ import print_function
Allen Li13bdf0c2017-03-02 15:18:16 -08009
Allen Lieb107022017-05-04 13:19:17 -070010import collections
Allen Lib6bb5f82017-08-21 15:11:57 -070011import socket
Allen Lieb107022017-05-04 13:19:17 -070012
Allen Li325c0762017-03-02 15:00:19 -080013import psutil
14
15from chromite.lib import cros_logging as logging
Allen Lia9c6e802017-07-11 15:42:47 -070016from chromite.lib import metrics
Allen Li325c0762017-03-02 15:00:19 -080017
18logger = logging.getLogger(__name__)
19
20_BOOT_TIME = psutil.boot_time()
21
Allen Lia9c6e802017-07-11 15:42:47 -070022_net_bytes_metric = metrics.CounterMetric(
Allen Lieb107022017-05-04 13:19:17 -070023 'dev/net/bytes', start_time=_BOOT_TIME,
Allen Li22989bd2017-07-12 10:34:37 -070024 description='Number of bytes up/down on interface.')
Allen Lia9c6e802017-07-11 15:42:47 -070025_net_packets_metric = metrics.CounterMetric(
Allen Lieb107022017-05-04 13:19:17 -070026 'dev/net/packets', start_time=_BOOT_TIME,
Allen Li22989bd2017-07-12 10:34:37 -070027 description='Number of packets up/down on interface.')
Allen Lia9c6e802017-07-11 15:42:47 -070028_net_errors_metric = metrics.CounterMetric(
Allen Lieb107022017-05-04 13:19:17 -070029 'dev/net/errors', start_time=_BOOT_TIME,
30 description='Total number of errors up/down on interface.')
Allen Lia9c6e802017-07-11 15:42:47 -070031_net_dropped_metric = metrics.CounterMetric(
Allen Lieb107022017-05-04 13:19:17 -070032 'dev/net/dropped', start_time=_BOOT_TIME,
33 description='Total number of dropped packages up/down on interface.')
34
Allen Lia9c6e802017-07-11 15:42:47 -070035_net_if_isup_metric = metrics.BooleanMetric(
Allen Li325c0762017-03-02 15:00:19 -080036 'dev/net/isup',
37 description='Whether interface is up or down.')
Allen Lia9c6e802017-07-11 15:42:47 -070038_net_if_duplex_metric = metrics.GaugeMetric(
Allen Li325c0762017-03-02 15:00:19 -080039 'dev/net/duplex',
40 description='Whether interface supports full or half duplex.')
Allen Lia9c6e802017-07-11 15:42:47 -070041_net_if_speed_metric = metrics.GaugeMetric(
Allen Li325c0762017-03-02 15:00:19 -080042 'dev/net/speed',
43 description='Network interface speed in Mb.')
Allen Lia9c6e802017-07-11 15:42:47 -070044_net_if_mtu_metric = metrics.GaugeMetric(
Allen Li325c0762017-03-02 15:00:19 -080045 'dev/net/mtu',
46 description='Network interface MTU in B.')
47
48
49def collect_net_info():
50 """Collect network metrics."""
Allen Lieb107022017-05-04 13:19:17 -070051 _collect_net_io_duplex_counters()
Allen Li325c0762017-03-02 15:00:19 -080052 _collect_net_if_stats()
Allen Lib6bb5f82017-08-21 15:11:57 -070053 _collect_fqdn()
Prathmesh Prabhu07f80872017-08-21 15:09:33 -070054 _collect_net_if_addrs()
Allen Li325c0762017-03-02 15:00:19 -080055
56
Allen Lieb107022017-05-04 13:19:17 -070057# Network IO metrics to collect
58_IOMetric = collections.namedtuple('_IOMetric', ['metric', 'up_counter_name',
59 'down_counter_name'])
60
61_net_io_duplex_metrics = (
Allen Li22989bd2017-07-12 10:34:37 -070062 _IOMetric(metric=_net_bytes_metric,
63 up_counter_name='bytes_sent',
64 down_counter_name='bytes_recv'),
65 _IOMetric(metric=_net_packets_metric,
66 up_counter_name='packets_sent',
67 down_counter_name='packets_recv'),
68 _IOMetric(metric=_net_errors_metric,
69 up_counter_name='errout',
70 down_counter_name='errin'),
71 _IOMetric(metric=_net_dropped_metric,
72 up_counter_name='dropout',
73 down_counter_name='dropin'),
Allen Lieb107022017-05-04 13:19:17 -070074)
75
76
77def _collect_net_io_duplex_counters():
78 """Collect metrics for network IO duplex counters."""
79 for nic, counters in _net_io_iter():
80 fields = {'interface': nic}
81 for metric, up_counter_name, down_counter_name in _net_io_duplex_metrics:
82 try:
83 metric.set(getattr(counters, up_counter_name),
84 fields=dict(direction='up', **fields))
85 metric.set(getattr(counters, down_counter_name),
86 fields=dict(direction='down', **fields))
Allen Lia9c6e802017-07-11 15:42:47 -070087 except metrics.MonitoringDecreasingValueError as ex:
Allen Lieb107022017-05-04 13:19:17 -070088 # This normally shouldn't happen, but might if the network
89 # driver module is reloaded, so log an error and continue
90 # instead of raising an exception.
91 logger.warning(str(ex))
92
93
Allen Li4bb931f2017-05-04 13:11:56 -070094def _net_io_iter():
95 """Generate network IO information."""
96 nics = psutil.net_io_counters(pernic=True)
97 for nic, counters in nics.iteritems():
98 if _is_virtual_netif(nic):
99 continue
100 yield nic, counters
101
102
Allen Li325c0762017-03-02 15:00:19 -0800103_net_if_metrics = (
Allen Li22989bd2017-07-12 10:34:37 -0700104 (_net_if_isup_metric, 'isup'),
105 (_net_if_duplex_metric, 'duplex'),
106 (_net_if_speed_metric, 'speed'),
107 (_net_if_mtu_metric, 'mtu'),
Allen Li325c0762017-03-02 15:00:19 -0800108)
109
110
111def _collect_net_if_stats():
112 """Collect metrics for network interface stats."""
113 for nic, stats in psutil.net_if_stats().iteritems():
114 if _is_virtual_netif(nic):
115 continue
116 fields = {'interface': nic}
117 for metric, counter_name in _net_if_metrics:
118 metric.set(getattr(stats, counter_name), fields=fields)
119
120
Prathmesh Prabhu07f80872017-08-21 15:09:33 -0700121_net_if_addrs_metrics = metrics.StringMetric(
122 'dev/net/address',
123 description='Network address of physical network interfaces.')
124_family_field_strings = {
125 psutil.AF_LINK: 'AF_LINK',
126 socket.AF_INET: 'AF_INET',
127 socket.AF_INET6: 'AF_INET6',
128}
129
130
131def _collect_net_if_addrs():
132 """Collects network addresses as metrics."""
133 for nic, addresses in psutil.net_if_addrs().iteritems():
134 if _is_virtual_netif(nic):
135 continue
136 for address in addresses:
137 fields = {
138 'interface': nic,
139 'family': _family_field_strings.get(address.family, 'UNKNOWN'),
140 }
141 _net_if_addrs_metrics.set(address.address, fields)
142
143
Allen Li325c0762017-03-02 15:00:19 -0800144def _is_virtual_netif(nic):
Allen Li22989bd2017-07-12 10:34:37 -0700145 """Return whether the network interface is virtual."""
146 # TODO(ayatane): Use a different way of identifying virtual interfaces
147 return nic.startswith('veth')
Allen Lib6bb5f82017-08-21 15:11:57 -0700148
149
150_fqdn_metric = metrics.StringMetric('net/fqdn', description='FQDN')
151
152
153def _collect_fqdn():
154 fqdn = socket.getfqdn()
155 logging.debug('Got FQDN: %s', fqdn)
156 _fqdn_metric.set(fqdn)