Skip to content

Commit 124d256

Browse files
committed
Proc netstats python module added
It exports all you can find in /proc/net/netstat without any further processing.
1 parent 37b6214 commit 124d256

4 files changed

Lines changed: 240 additions & 70 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
.idea
22
*.pyc
3+
*.sublime-project
4+
*.sublime-workspace

network/netstats/README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
netstats
2+
=====
3+
4+
5+
Install
6+
-------
7+
8+
Copy netstats.py from python_modules to your python modules directory, e.g. :
9+
10+
- /usr/lib/ganglia/python_modules
11+
- /usr/lib64/ganglia/python_modules
12+
13+
Copy netstats.pyconf to the gmond conf.d directory, e.g. :
14+
15+
- /etc/ganglia/conf.d/
16+
17+
Tune the netstats.pyconf file to match your server interfaces and then restart gmond.
18+
19+
## AUTHOR
20+
21+
Author: Doychin Atanasov https://github.com/ironsmile
Lines changed: 0 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,7 @@
1-
#######################################################################
2-
# Use this config only if you interested in few metrics instead of
3-
# the 100 or so metrics possible
4-
#######################################################################
51

62
modules {
73
module {
84
name = "netstats"
95
language = "python"
106
}
117
}
12-
13-
collection_group {
14-
collect_every = 15
15-
time_threshold = 45
16-
17-
metric {
18-
name = "tcpext_tcploss_percentage"
19-
title = "TCP loss percentage"
20-
value_threshold = 1.0
21-
}
22-
23-
metric {
24-
name = "tcp_retrans_percentage"
25-
title = "TCP retransmit percentage"
26-
value_threshold = 1.0
27-
}
28-
29-
metric {
30-
name = "tcp_outsegs"
31-
title = "TCP segments sent"
32-
value_threshold = 1.0
33-
}
34-
35-
metric {
36-
name = "tcp_insegs"
37-
title = "TCP segments received"
38-
value_threshold = 1.0
39-
}
40-
41-
metric {
42-
name = "udp_indatagrams"
43-
title = "UDP packets in"
44-
value_threshold = 1.0
45-
}
46-
metric {
47-
name = "udp_outdatagrams"
48-
title = "UDP packets out"
49-
value_threshold = 1.0
50-
}
51-
metric {
52-
name = "udp_inerrors"
53-
title = "UDP packet receive errors"
54-
value_threshold = 1.0
55-
}
56-
57-
metric {
58-
name = "udp_rcvbuferrors"
59-
title = "UDP Receive buffer errors"
60-
value_threshold = 1.0
61-
}
62-
63-
64-
65-
metric {
66-
name = "tcpext_listendrops"
67-
title = "SYNs sent to LISTENing sockets ignored"
68-
value_threshold = 1.0
69-
}
70-
71-
metric {
72-
name = "tcp_attemptfails"
73-
title = "TCP Failed connection attempts"
74-
value_threshold = 1.0
75-
}
76-
77-
}
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
4+
import re
5+
import sys
6+
import traceback
7+
import os
8+
import threading
9+
import time
10+
11+
MODULE_NAME = "netstat"
12+
STATS_FILE = "/proc/net/netstat"
13+
14+
descriptors = list()
15+
Desc_Skel = {}
16+
_Worker_Thread = None
17+
_Lock = threading.Lock() # synchronization lock
18+
Debug = False
19+
20+
21+
def dprint(f, *v):
22+
if Debug:
23+
print >>sys.stderr, MODULE_NAME + ": " + f % v
24+
25+
26+
def floatable(str):
27+
try:
28+
float(str)
29+
return True
30+
except:
31+
return False
32+
33+
34+
class UpdateMetricThread(threading.Thread):
35+
def __init__(self, params):
36+
threading.Thread.__init__(self)
37+
38+
self.running = False
39+
self.shuttingdown = False
40+
self.refresh_rate = params["refresh_rate"]
41+
self.mp = params["metrix_prefix"]
42+
self.metric = {}
43+
self.last_metric = {}
44+
45+
def shutdown(self):
46+
self.shuttingdown = True
47+
48+
if not self.running:
49+
return
50+
51+
self.join()
52+
53+
def run(self):
54+
self.running = True
55+
56+
while not self.shuttingdown:
57+
_Lock.acquire()
58+
updated = self.update_metric()
59+
_Lock.release()
60+
61+
if not updated:
62+
time.sleep(0.2)
63+
else:
64+
if "time" in self.last_metric:
65+
dprint("metric delta period %.3f" % (
66+
self.metric['time'] -
67+
self.last_metric['time']))
68+
69+
self.running = False
70+
71+
def update_metric(self):
72+
if "time" in self.metric:
73+
if (time.time() - self.metric['time']) < self.refresh_rate:
74+
return False
75+
76+
dprint("updating metrics")
77+
78+
self.last_metric = self.metric.copy()
79+
80+
update_dict = {
81+
'time': time.time(),
82+
}
83+
84+
try:
85+
for stat_type, key, value in netstat_iterator():
86+
update_dict['%s_%s_%s' % (self.mp, stat_type, key)] = int(value)
87+
88+
except IOError:
89+
dprint("unable to open " + STATS_FILE)
90+
return False
91+
92+
self.metric.update(update_dict)
93+
94+
return True
95+
96+
def metric_delta(self, name):
97+
val = 0
98+
99+
if name in self.metric and name in self.last_metric:
100+
_Lock.acquire()
101+
if self.metric['time'] - self.last_metric['time'] != 0:
102+
val = (self.metric[name] - self.last_metric[name]) / (
103+
self.metric['time'] - self.last_metric['time'])
104+
_Lock.release()
105+
106+
return float(val)
107+
108+
109+
def metric_init(params):
110+
global descriptors, Desc_Skel, _Worker_Thread, Debug
111+
112+
# initialize skeleton of descriptors
113+
Desc_Skel = {
114+
'name': 'XXX',
115+
'call_back': metric_delta,
116+
'time_max': 60,
117+
'value_type': 'float',
118+
'format': '%d',
119+
'units': 'XXX',
120+
'slope': 'XXX', # zero|positive|negative|both
121+
'description': 'XXX',
122+
'groups': 'network'
123+
}
124+
125+
params["refresh_rate"] = params.get("refresh_rate", 15)
126+
params["metrix_prefix"] = params.get("metrix_prefix", MODULE_NAME)
127+
Debug = params.get("debug", False)
128+
129+
dprint("debugging has been turned on")
130+
131+
_Worker_Thread = UpdateMetricThread(params)
132+
_Worker_Thread.start()
133+
134+
mp = params["metrix_prefix"]
135+
136+
try:
137+
for stat_type, key, value in netstat_iterator():
138+
descriptors.append(create_desc(Desc_Skel, {
139+
"name": '%s_%s_%s' % (mp, stat_type, key),
140+
"units": "number",
141+
"slope": "both",
142+
"description": "Netstat %s metric %s" % (stat_type, key)
143+
}))
144+
except IOError:
145+
return
146+
147+
return descriptors
148+
149+
150+
def netstat_iterator():
151+
f = open(STATS_FILE, 'r')
152+
153+
line_number = -1
154+
labels = []
155+
labels_type = None
156+
157+
with f:
158+
for line in f:
159+
line_number += 1
160+
161+
if not re.search(':', line):
162+
continue
163+
164+
are_labels = (line_number % 2 == 0)
165+
166+
tokens = re.split('[:\s]+', line.strip())
167+
168+
if are_labels:
169+
labels_type = tokens[0].strip(':')
170+
labels = tokens[1:]
171+
continue
172+
173+
values_type = tokens[0].strip(':')
174+
175+
if values_type != labels_type:
176+
dprint("Expected values of type `%s` but they were `%s`" % (
177+
labels_type, values_type))
178+
continue
179+
180+
for ind, value in enumerate(tokens[1:]):
181+
yield values_type, labels[ind], value
182+
183+
184+
def create_desc(skel, prop):
185+
d = skel.copy()
186+
for k, v in prop.iteritems():
187+
d[k] = v
188+
return d
189+
190+
191+
def metric_delta(name):
192+
return _Worker_Thread.metric_delta(name)
193+
194+
195+
def metric_cleanup():
196+
_Worker_Thread.shutdown()
197+
198+
if __name__ == '__main__':
199+
params = {
200+
"debug": True,
201+
"refresh_rate": 15
202+
}
203+
204+
try:
205+
metric_init(params)
206+
207+
while True:
208+
time.sleep(params['refresh_rate'])
209+
for d in descriptors:
210+
v = d['call_back'](d['name'])
211+
print ('value for %s is ' + d['format']) % (d['name'], v)
212+
except KeyboardInterrupt:
213+
time.sleep(0.2)
214+
os._exit(1)
215+
except:
216+
traceback.print_exc()
217+
os._exit(1)

0 commit comments

Comments
 (0)