blob: 1e89e0adca086e4844c46b7f3959c0be9cc0dbd3 [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
11
Allen Li325c0762017-03-02 15:00:19 -080012import psutil
13
14from chromite.lib import cros_logging as logging
15from infra_libs import ts_mon
16
17logger = logging.getLogger(__name__)
18
19_BOOT_TIME = psutil.boot_time()
20
21_net_up_metric = ts_mon.CounterMetric(
22 'dev/net/bytes/up', start_time=_BOOT_TIME,
23 description='Number of bytes sent on interface.',
24 units=ts_mon.MetricsDataUnits.BYTES)
25_net_down_metric = ts_mon.CounterMetric(
26 'dev/net/bytes/down', start_time=_BOOT_TIME,
27 description='Number of Bytes received on '
28 'interface.',
29 units=ts_mon.MetricsDataUnits.BYTES)
30_net_err_up_metric = ts_mon.CounterMetric(
31 'dev/net/err/up', start_time=_BOOT_TIME,
32 description='Total number of errors when '
33 'sending (per interface).')
34_net_err_down_metric = ts_mon.CounterMetric(
35 'dev/net/err/down', start_time=_BOOT_TIME,
36 description='Total number of errors when '
37 'receiving (per interface).')
38_net_drop_up_metric = ts_mon.CounterMetric(
39 'dev/net/drop/up', start_time=_BOOT_TIME,
40 description='Total number of outgoing '
41 'packets that have been dropped.')
42_net_drop_down_metric = ts_mon.CounterMetric(
43 'dev/net/drop/down', start_time=_BOOT_TIME,
44 description='Total number of incoming '
45 'packets that have been dropped.')
46
Allen Lieb107022017-05-04 13:19:17 -070047_net_bytes_metric = ts_mon.CounterMetric(
48 'dev/net/bytes', start_time=_BOOT_TIME,
49 description='Number of bytes up/down on interface.',
50 units=ts_mon.MetricsDataUnits.BYTES)
51_net_packets_metric = ts_mon.CounterMetric(
52 'dev/net/packets', start_time=_BOOT_TIME,
53 description='Number of packets up/down on interface.',
54 units=ts_mon.MetricsDataUnits.BYTES)
55_net_errors_metric = ts_mon.CounterMetric(
56 'dev/net/errors', start_time=_BOOT_TIME,
57 description='Total number of errors up/down on interface.')
58_net_dropped_metric = ts_mon.CounterMetric(
59 'dev/net/dropped', start_time=_BOOT_TIME,
60 description='Total number of dropped packages up/down on interface.')
61
Allen Li325c0762017-03-02 15:00:19 -080062_net_if_isup_metric = ts_mon.BooleanMetric(
63 'dev/net/isup',
64 description='Whether interface is up or down.')
65_net_if_duplex_metric = ts_mon.GaugeMetric(
66 'dev/net/duplex',
67 description='Whether interface supports full or half duplex.')
68_net_if_speed_metric = ts_mon.GaugeMetric(
69 'dev/net/speed',
70 description='Network interface speed in Mb.')
71_net_if_mtu_metric = ts_mon.GaugeMetric(
72 'dev/net/mtu',
73 description='Network interface MTU in B.')
74
75
76def collect_net_info():
77 """Collect network metrics."""
78 _collect_net_io_counters()
Allen Lieb107022017-05-04 13:19:17 -070079 _collect_net_io_duplex_counters()
Allen Li325c0762017-03-02 15:00:19 -080080 _collect_net_if_stats()
81
82
Allen Lieb107022017-05-04 13:19:17 -070083# Network IO metrics to collect
84_IOMetric = collections.namedtuple('_IOMetric', ['metric', 'up_counter_name',
85 'down_counter_name'])
86
87_net_io_duplex_metrics = (
88 _IOMetric(metric=_net_bytes_metric,
89 up_counter_name='bytes_sent',
90 down_counter_name='bytes_recv'),
91 _IOMetric(metric=_net_packets_metric,
92 up_counter_name='packets_sent',
93 down_counter_name='packets_recv'),
94 _IOMetric(metric=_net_errors_metric,
95 up_counter_name='errout',
96 down_counter_name='errin'),
Allen Lif90a22e2017-05-19 18:24:25 -070097 _IOMetric(metric=_net_dropped_metric,
Allen Lieb107022017-05-04 13:19:17 -070098 up_counter_name='dropout',
99 down_counter_name='dropin'),
100)
101
102
103def _collect_net_io_duplex_counters():
104 """Collect metrics for network IO duplex counters."""
105 for nic, counters in _net_io_iter():
106 fields = {'interface': nic}
107 for metric, up_counter_name, down_counter_name in _net_io_duplex_metrics:
108 try:
109 metric.set(getattr(counters, up_counter_name),
110 fields=dict(direction='up', **fields))
111 metric.set(getattr(counters, down_counter_name),
112 fields=dict(direction='down', **fields))
113 except ts_mon.MonitoringDecreasingValueError as ex:
114 # This normally shouldn't happen, but might if the network
115 # driver module is reloaded, so log an error and continue
116 # instead of raising an exception.
117 logger.warning(str(ex))
118
119
Allen Li325c0762017-03-02 15:00:19 -0800120_net_io_metrics = (
121 (_net_up_metric, 'bytes_sent'),
122 (_net_down_metric, 'bytes_recv'),
123 (_net_err_up_metric, 'errout'),
124 (_net_err_down_metric, 'errin'),
125 (_net_drop_up_metric, 'dropout'),
126 (_net_drop_down_metric, 'dropin'),
127)
128
129
130def _collect_net_io_counters():
131 """Collect metrics for network IO counters."""
Allen Li4bb931f2017-05-04 13:11:56 -0700132 for nic, counters in _net_io_iter():
Allen Li325c0762017-03-02 15:00:19 -0800133 fields = {'interface': nic}
134 for metric, counter_name in _net_io_metrics:
135 try:
136 metric.set(getattr(counters, counter_name), fields=fields)
137 except ts_mon.MonitoringDecreasingValueError as ex:
138 # This normally shouldn't happen, but might if the network
139 # driver module is reloaded, so log an error and continue
140 # instead of raising an exception.
141 logger.warning(str(ex))
142
143
Allen Li4bb931f2017-05-04 13:11:56 -0700144def _net_io_iter():
145 """Generate network IO information."""
146 nics = psutil.net_io_counters(pernic=True)
147 for nic, counters in nics.iteritems():
148 if _is_virtual_netif(nic):
149 continue
150 yield nic, counters
151
152
Allen Li325c0762017-03-02 15:00:19 -0800153_net_if_metrics = (
154 (_net_if_isup_metric, 'isup'),
155 (_net_if_duplex_metric, 'duplex'),
156 (_net_if_speed_metric, 'speed'),
157 (_net_if_mtu_metric, 'mtu'),
158)
159
160
161def _collect_net_if_stats():
162 """Collect metrics for network interface stats."""
163 for nic, stats in psutil.net_if_stats().iteritems():
164 if _is_virtual_netif(nic):
165 continue
166 fields = {'interface': nic}
167 for metric, counter_name in _net_if_metrics:
168 metric.set(getattr(stats, counter_name), fields=fields)
169
170
171def _is_virtual_netif(nic):
172 """Return whether the network interface is virtual."""
173 # TODO(ayatane): Use a different way of identifying virtual interfaces
174 return nic.startswith('veth')