blob: e59c8ebe7e66d27c3320715aed75ace42c53b234 [file] [log] [blame]
Mike Frysingere58c0e22017-10-04 15:43:30 -04001# -*- coding: utf-8 -*-
Allen Li325c0762017-03-02 15:00:19 -08002# Copyright 2017 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Network metrics."""
7
Allen Li13bdf0c2017-03-02 15:18:16 -08008from __future__ import absolute_import
9from __future__ import print_function
Allen Li13bdf0c2017-03-02 15:18:16 -080010
Allen Lieb107022017-05-04 13:19:17 -070011import collections
Allen Lib6bb5f82017-08-21 15:11:57 -070012import socket
Allen Lieb107022017-05-04 13:19:17 -070013
Allen Li325c0762017-03-02 15:00:19 -080014import psutil
Allen Li07196972018-05-08 13:49:08 -070015from infra_libs import ts_mon
Allen Li325c0762017-03-02 15:00:19 -080016
17from chromite.lib import cros_logging as logging
Allen Lia9c6e802017-07-11 15:42:47 -070018from chromite.lib import metrics
Allen Li325c0762017-03-02 15:00:19 -080019
20logger = logging.getLogger(__name__)
21
22_BOOT_TIME = psutil.boot_time()
23
Allen Lia9c6e802017-07-11 15:42:47 -070024_net_bytes_metric = metrics.CounterMetric(
Allen Lieb107022017-05-04 13:19:17 -070025 'dev/net/bytes', start_time=_BOOT_TIME,
Allen Li22989bd2017-07-12 10:34:37 -070026 description='Number of bytes up/down on interface.')
Allen Lia9c6e802017-07-11 15:42:47 -070027_net_packets_metric = metrics.CounterMetric(
Allen Lieb107022017-05-04 13:19:17 -070028 'dev/net/packets', start_time=_BOOT_TIME,
Allen Li22989bd2017-07-12 10:34:37 -070029 description='Number of packets up/down on interface.')
Allen Lia9c6e802017-07-11 15:42:47 -070030_net_errors_metric = metrics.CounterMetric(
Allen Lieb107022017-05-04 13:19:17 -070031 'dev/net/errors', start_time=_BOOT_TIME,
32 description='Total number of errors up/down on interface.')
Allen Lia9c6e802017-07-11 15:42:47 -070033_net_dropped_metric = metrics.CounterMetric(
Allen Lieb107022017-05-04 13:19:17 -070034 'dev/net/dropped', start_time=_BOOT_TIME,
35 description='Total number of dropped packages up/down on interface.')
36
Allen Lia9c6e802017-07-11 15:42:47 -070037_net_if_isup_metric = metrics.BooleanMetric(
Allen Li325c0762017-03-02 15:00:19 -080038 'dev/net/isup',
39 description='Whether interface is up or down.')
Allen Lia9c6e802017-07-11 15:42:47 -070040_net_if_duplex_metric = metrics.GaugeMetric(
Allen Li325c0762017-03-02 15:00:19 -080041 'dev/net/duplex',
42 description='Whether interface supports full or half duplex.')
Allen Lia9c6e802017-07-11 15:42:47 -070043_net_if_speed_metric = metrics.GaugeMetric(
Allen Li325c0762017-03-02 15:00:19 -080044 'dev/net/speed',
45 description='Network interface speed in Mb.')
Allen Lia9c6e802017-07-11 15:42:47 -070046_net_if_mtu_metric = metrics.GaugeMetric(
Allen Li325c0762017-03-02 15:00:19 -080047 'dev/net/mtu',
48 description='Network interface MTU in B.')
49
50
51def collect_net_info():
52 """Collect network metrics."""
Allen Lieb107022017-05-04 13:19:17 -070053 _collect_net_io_duplex_counters()
Allen Li325c0762017-03-02 15:00:19 -080054 _collect_net_if_stats()
Allen Lib6bb5f82017-08-21 15:11:57 -070055 _collect_fqdn()
Prathmesh Prabhu07f80872017-08-21 15:09:33 -070056 _collect_net_if_addrs()
Allen Li325c0762017-03-02 15:00:19 -080057
58
Allen Lieb107022017-05-04 13:19:17 -070059# Network IO metrics to collect
60_IOMetric = collections.namedtuple('_IOMetric', ['metric', 'up_counter_name',
61 'down_counter_name'])
62
63_net_io_duplex_metrics = (
Allen Li22989bd2017-07-12 10:34:37 -070064 _IOMetric(metric=_net_bytes_metric,
65 up_counter_name='bytes_sent',
66 down_counter_name='bytes_recv'),
67 _IOMetric(metric=_net_packets_metric,
68 up_counter_name='packets_sent',
69 down_counter_name='packets_recv'),
70 _IOMetric(metric=_net_errors_metric,
71 up_counter_name='errout',
72 down_counter_name='errin'),
73 _IOMetric(metric=_net_dropped_metric,
74 up_counter_name='dropout',
75 down_counter_name='dropin'),
Allen Lieb107022017-05-04 13:19:17 -070076)
77
78
79def _collect_net_io_duplex_counters():
80 """Collect metrics for network IO duplex counters."""
81 for nic, counters in _net_io_iter():
82 fields = {'interface': nic}
83 for metric, up_counter_name, down_counter_name in _net_io_duplex_metrics:
84 try:
85 metric.set(getattr(counters, up_counter_name),
86 fields=dict(direction='up', **fields))
87 metric.set(getattr(counters, down_counter_name),
88 fields=dict(direction='down', **fields))
Allen Li07196972018-05-08 13:49:08 -070089 except ts_mon.MonitoringDecreasingValueError as ex:
Allen Lieb107022017-05-04 13:19:17 -070090 # This normally shouldn't happen, but might if the network
91 # driver module is reloaded, so log an error and continue
92 # instead of raising an exception.
93 logger.warning(str(ex))
94
95
Allen Li4bb931f2017-05-04 13:11:56 -070096def _net_io_iter():
97 """Generate network IO information."""
98 nics = psutil.net_io_counters(pernic=True)
99 for nic, counters in nics.iteritems():
100 if _is_virtual_netif(nic):
101 continue
102 yield nic, counters
103
104
Allen Li325c0762017-03-02 15:00:19 -0800105_net_if_metrics = (
Allen Li22989bd2017-07-12 10:34:37 -0700106 (_net_if_isup_metric, 'isup'),
107 (_net_if_duplex_metric, 'duplex'),
108 (_net_if_speed_metric, 'speed'),
109 (_net_if_mtu_metric, 'mtu'),
Allen Li325c0762017-03-02 15:00:19 -0800110)
111
112
113def _collect_net_if_stats():
114 """Collect metrics for network interface stats."""
115 for nic, stats in psutil.net_if_stats().iteritems():
116 if _is_virtual_netif(nic):
117 continue
118 fields = {'interface': nic}
119 for metric, counter_name in _net_if_metrics:
120 metric.set(getattr(stats, counter_name), fields=fields)
121
122
Prathmesh Prabhu07f80872017-08-21 15:09:33 -0700123_net_if_addrs_metrics = metrics.StringMetric(
124 'dev/net/address',
125 description='Network address of physical network interfaces.')
126_family_field_strings = {
127 psutil.AF_LINK: 'AF_LINK',
128 socket.AF_INET: 'AF_INET',
129 socket.AF_INET6: 'AF_INET6',
130}
131
132
133def _collect_net_if_addrs():
134 """Collects network addresses as metrics."""
135 for nic, addresses in psutil.net_if_addrs().iteritems():
136 if _is_virtual_netif(nic):
137 continue
138 for address in addresses:
139 fields = {
140 'interface': nic,
141 'family': _family_field_strings.get(address.family, 'UNKNOWN'),
142 }
143 _net_if_addrs_metrics.set(address.address, fields)
144
145
Allen Li325c0762017-03-02 15:00:19 -0800146def _is_virtual_netif(nic):
Allen Li22989bd2017-07-12 10:34:37 -0700147 """Return whether the network interface is virtual."""
148 # TODO(ayatane): Use a different way of identifying virtual interfaces
149 return nic.startswith('veth')
Allen Lib6bb5f82017-08-21 15:11:57 -0700150
151
152_fqdn_metric = metrics.StringMetric('net/fqdn', description='FQDN')
153
154
155def _collect_fqdn():
156 fqdn = socket.getfqdn()
157 logging.debug('Got FQDN: %s', fqdn)
158 _fqdn_metric.set(fqdn)