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