Skip to content

Commit de5de6a

Browse files
committed
Add conntrack metrics
1 parent 6777c54 commit de5de6a

3 files changed

Lines changed: 319 additions & 0 deletions

File tree

network/conntrack/README.mkdn

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
conntrack
2+
===============
3+
4+
Python module for ganglia 3.1.
5+
6+
This module allows you to collect conntrack stats. These values that are collected by
7+
executing
8+
9+
conntrack -S
10+
11+
12+
Install
13+
===============
14+
15+
Copy conntrack.py from python_modules to your python modules directory e.g.
16+
17+
/usr/lib64/ganglia/python_modules
18+
19+
and conntrack.pyconf to
20+
21+
/etc/ganglia/conf.d/
22+
23+
If you would like only specific metrics emitted you will need to comment out the name_match section
24+
and replace it with a specific set of metrics e.g.
25+
26+
metric {
27+
name = "conntrack_entries"
28+
title = "Conntrack entries"
29+
value_threshold = 1.0
30+
}
31+
32+
Restart Gmond and you are done.
33+
34+
## AUTHOR
35+
36+
Author: Vladimir Vuksan https://github.com/vvuksan
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
modules {
2+
module {
3+
name = "conntrack"
4+
language = "python"
5+
}
6+
}
7+
8+
collection_group {
9+
collect_every = 15
10+
time_threshold = 45
11+
12+
metric {
13+
name_match = "conntrack_(.+)"
14+
value_threshold = 1.0
15+
}
16+
17+
}
Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
#
4+
# Conntrack gmond module for Ganglia
5+
#
6+
# Copyright (C) 2011 by Michael T. Conigliaro <mike [at] conigliaro [dot] org>.
7+
# All rights reserved.
8+
#
9+
# Permission is hereby granted, free of charge, to any person obtaining a copy
10+
# of this software and associated documentation files (the "Software"), to deal
11+
# in the Software without restriction, including without limitation the rights
12+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
# copies of the Software, and to permit persons to whom the Software is
14+
# furnished to do so, subject to the following conditions:
15+
#
16+
# The above copyright notice and this permission notice shall be included in
17+
# all copies or substantial portions of the Software.
18+
#
19+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
# THE SOFTWARE.
26+
#
27+
28+
import os
29+
import time
30+
31+
32+
NAME_PREFIX = 'conntrack_'
33+
PARAMS = {
34+
'stats_command' : '/usr/sbin/conntrack -S'
35+
}
36+
METRICS = {
37+
'time' : 0,
38+
'data' : {}
39+
}
40+
LAST_METRICS = dict(METRICS)
41+
METRICS_CACHE_MAX = 5
42+
43+
def create_desc(skel, prop):
44+
d = skel.copy()
45+
for k,v in prop.iteritems():
46+
d[k] = v
47+
return d
48+
49+
50+
def get_metrics():
51+
"""Return all metrics"""
52+
53+
global METRICS, LAST_METRICS
54+
55+
if (time.time() - METRICS['time']) > METRICS_CACHE_MAX:
56+
57+
# get raw metric data
58+
io = os.popen(PARAMS['stats_command'])
59+
60+
# convert to dict
61+
metrics = {}
62+
for line in io.readlines():
63+
values = line.split()[:2]
64+
try:
65+
metrics[values[0]] = int(values[1])
66+
except ValueError:
67+
metrics[values[0]] = 0
68+
69+
# update cache
70+
LAST_METRICS = dict(METRICS)
71+
METRICS = {
72+
'time': time.time(),
73+
'data': metrics
74+
}
75+
76+
return [METRICS, LAST_METRICS]
77+
78+
def get_value(name):
79+
"""Return a value for the requested metric"""
80+
81+
metrics = get_metrics()[0]
82+
83+
name = name[len(NAME_PREFIX):] # remove prefix from name
84+
try:
85+
result = metrics['data'][name]
86+
except StandardError:
87+
result = 0
88+
89+
return result
90+
91+
92+
def get_delta(name):
93+
"""Return change over time for the requested metric"""
94+
95+
# get metrics
96+
[curr_metrics, last_metrics] = get_metrics()
97+
98+
# get delta
99+
name = name[len(NAME_PREFIX):] # remove prefix from name
100+
try:
101+
delta = float(curr_metrics['data'][name] - last_metrics['data'][name])/(curr_metrics['time'] - last_metrics['time'])
102+
if delta < 0:
103+
print "Less than 0"
104+
delta = 0
105+
except StandardError:
106+
delta = 0
107+
108+
return delta
109+
110+
111+
def get_cache_hit_ratio(name):
112+
"""Return cache hit ratio"""
113+
114+
try:
115+
result = get_delta(NAME_PREFIX + 'cache_hit') / get_delta(NAME_PREFIX + 'client_req') * 100
116+
except ZeroDivisionError:
117+
result = 0
118+
119+
return result
120+
121+
122+
def metric_init(lparams):
123+
"""Initialize metric descriptors"""
124+
125+
global PARAMS, Desc_Skel
126+
127+
# set parameters
128+
for key in lparams:
129+
PARAMS[key] = lparams[key]
130+
131+
# define descriptors
132+
time_max = 60
133+
134+
Desc_Skel = {
135+
'name' : 'XXX',
136+
'call_back' : 'XXX',
137+
'time_max' : 60,
138+
'value_type' : 'float',
139+
'format' : '%f',
140+
'units' : 'XXX',
141+
'slope' : 'both', # zero|positive|negative|both
142+
'description' : 'XXX',
143+
'groups' : 'conntrack',
144+
}
145+
146+
descriptors = []
147+
descriptors.append( create_desc(Desc_Skel, {
148+
"name" : NAME_PREFIX + 'entries',
149+
"call_back" : get_value,
150+
"units" : "entries",
151+
"description": "",
152+
}))
153+
descriptors.append( create_desc(Desc_Skel, {
154+
"name" : NAME_PREFIX + 'searched',
155+
"call_back" : get_delta,
156+
"units" : "ops/s",
157+
"description": "",
158+
}))
159+
descriptors.append( create_desc(Desc_Skel, {
160+
"name" : NAME_PREFIX + 'found',
161+
"call_back" : get_delta,
162+
"units" : "ops/s",
163+
"description": "",
164+
}))
165+
descriptors.append( create_desc(Desc_Skel, {
166+
"name" : NAME_PREFIX + 'new',
167+
"call_back" : get_delta,
168+
"units" : "ops/s",
169+
"description": "",
170+
}))
171+
descriptors.append( create_desc(Desc_Skel, {
172+
"name" : NAME_PREFIX + 'invalid',
173+
"call_back" : get_delta,
174+
"units" : "ops/s",
175+
"description": "",
176+
}))
177+
descriptors.append( create_desc(Desc_Skel, {
178+
"name" : NAME_PREFIX + 'ignore',
179+
"call_back" : get_delta,
180+
"units" : "ops/s",
181+
"description": "",
182+
}))
183+
descriptors.append( create_desc(Desc_Skel, {
184+
"name" : NAME_PREFIX + 'delete',
185+
"call_back" : get_delta,
186+
"units" : "ops/s",
187+
"description": "",
188+
}))
189+
descriptors.append( create_desc(Desc_Skel, {
190+
"name" : NAME_PREFIX + 'delete_list',
191+
"call_back" : get_delta,
192+
"units" : "ops/s",
193+
"description": "",
194+
}))
195+
descriptors.append( create_desc(Desc_Skel, {
196+
"name" : NAME_PREFIX + 'insert',
197+
"call_back" : get_delta,
198+
"units" : "ops/s",
199+
"description": "",
200+
}))
201+
descriptors.append( create_desc(Desc_Skel, {
202+
"name" : NAME_PREFIX + 'insert_failed',
203+
"call_back" : get_delta,
204+
"units" : "ops/s",
205+
"description": "",
206+
}))
207+
descriptors.append( create_desc(Desc_Skel, {
208+
"name" : NAME_PREFIX + 'drop',
209+
"call_back" : get_delta,
210+
"units" : "ops/s",
211+
"description": "",
212+
}))
213+
descriptors.append( create_desc(Desc_Skel, {
214+
"name" : NAME_PREFIX + 'early_drop',
215+
"call_back" : get_delta,
216+
"units" : "ops/s",
217+
"description": "",
218+
}))
219+
descriptors.append( create_desc(Desc_Skel, {
220+
"name" : NAME_PREFIX + 'icmp_error',
221+
"call_back" : get_delta,
222+
"units" : "ops/s",
223+
"description": "",
224+
}))
225+
descriptors.append( create_desc(Desc_Skel, {
226+
"name" : NAME_PREFIX + 'expect_new',
227+
"call_back" : get_delta,
228+
"units" : "ops/s",
229+
"description": "",
230+
}))
231+
descriptors.append( create_desc(Desc_Skel, {
232+
"name" : NAME_PREFIX + 'expect_create',
233+
"call_back" : get_delta,
234+
"units" : "ops/s",
235+
"description": "",
236+
}))
237+
descriptors.append( create_desc(Desc_Skel, {
238+
"name" : NAME_PREFIX + 'expect_delete',
239+
"call_back" : get_delta,
240+
"units" : "ops/s",
241+
"description": "",
242+
}))
243+
descriptors.append( create_desc(Desc_Skel, {
244+
"name" : NAME_PREFIX + 'search_restart',
245+
"call_back" : get_delta,
246+
"units" : "ops/s",
247+
"description": "",
248+
}))
249+
250+
return descriptors
251+
252+
253+
def metric_cleanup():
254+
"""Cleanup"""
255+
256+
pass
257+
258+
259+
# the following code is for debugging and testing
260+
if __name__ == '__main__':
261+
descriptors = metric_init(PARAMS)
262+
while True:
263+
for d in descriptors:
264+
print (('%s = %s') % (d['name'], d['format'])) % (d['call_back'](d['name']))
265+
print 'Sleeping 15 seconds'
266+
time.sleep(15)

0 commit comments

Comments
 (0)