Skip to content

Commit

Permalink
Bind collector: Adding support for /server section of bind9
Browse files Browse the repository at this point in the history
for xml_v3 and json_v1
  • Loading branch information
Terry Hardie committed Dec 15, 2016
1 parent f4a523f commit f946865
Show file tree
Hide file tree
Showing 5 changed files with 5,546 additions and 0 deletions.
5 changes: 5 additions & 0 deletions docs/collectors/BindCollector.md
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ publish | resolver, server, zonemgmt, sockets, memory, | Available stats:<br>
| list
publish_view_bind | False | | bool
publish_view_meta | False | | bool
data_format | xml_v2 | Bind stats version:<br>
- xml_v2 (Original bind stats version from 9.5)<br>
- xml_v3 (New xml version)<br>
- json_v1 (JSON replacement for XML)<br>
| str

#### Example Output

Expand Down
106 changes: 106 additions & 0 deletions src/collectors/bind/bind.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ def get_default_config_help(self):
" - memory (Global memory usage)\n",
'publish_view_bind': "",
'publish_view_meta': "",
'data_format': "Bind stats version:\n" +
" - xml_v2 (Original bind stats version from 9.5)\n" +
" - xml_v3 (New xml version)\n" +
" - json_v1 (JSON replacement for XML)\n",
})
return config_help

Expand Down Expand Up @@ -63,6 +67,7 @@ def get_default_config(self):
# By default we don't publish these special views
'publish_view_bind': False,
'publish_view_meta': False,
'data_format': 'xml_v2',
})
return config

Expand All @@ -73,7 +78,62 @@ def clean_counter(self, name, value):
self.publish(name, value)

def collect(self):
if self.config['data_format'] == 'json_v1':
return self.collect_json_v1()
if self.config['data_format'] == 'xml_v3':
return self.collect_xml_v3()
if self.config['data_format'] == 'xml_v2':
return self.collect_xml_v2()

def collect_json_v1(self):
try:
# Try newest interface first (JSON has least impact)
import json
req = urllib2.urlopen('http://%s:%d/json/v1/status' % (
self.config['host'], int(self.config['port'])))
except Exception, e:
self.log.error('JSON v1 not supported: %s', e)
return {}

if 'server' in self.config['publish']:
try:
req = urllib2.urlopen('http://%s:%d/json/v1/server' % (
self.config['host'], int(self.config['port'])))
except Exception, e:
self.log.error('Couldnt connect to bind: %s', e)
return {}

response = json.load(req)
self.parse_json_v1_server(response)

def collect_xml_v3(self):
try:
# Try newer interface first
req = urllib2.urlopen('http://%s:%d/xml/v3/status' % (
self.config['host'], int(self.config['port'])))
except Exception, e:
self.log.error('XML v3 not supported: %s', e)
return {}

if 'server' in self.config['publish']:
try:
req = urllib2.urlopen('http://%s:%d/xml/v3/server' % (
self.config['host'], int(self.config['port'])))
except Exception, e:
self.log.error('Couldnt connect to bind: %s', e)
return {}
# Proceed with v3 parsing
tree = ElementTree.parse(req)

if not tree:
raise ValueError("Corrupt XML file, no statistics found")

self.parse_xml_v3_server(tree)

def collect_xml_v2(self):
try:
# NOTE: Querying this node on a large server can impact bind
# answering queriesfor sometimes hundreds of milliseconds.
req = urllib2.urlopen('http://%s:%d/' % (
self.config['host'], int(self.config['port'])))
except Exception, e:
Expand All @@ -87,6 +147,10 @@ def collect(self):

root = tree.find('bind/statistics')

if not root:
raise ValueError(
"Missing bind/statistics tree - Wrong data_format?")

if 'resolver' in self.config['publish']:
for view in root.findall('views/view'):
name = view.find('name').text
Expand Down Expand Up @@ -153,3 +217,45 @@ def collect(self):
'memory.%s' % counter.tag,
int(counter.text)
)

def parse_xml_v3_server(self, root):
for counters in root.findall('server/counters'):
for counter in counters:
self.clean_counter(
'server.counters.%s.%s' % (counters.attrib['type'],
counter.attrib['name']),
int(counter.text)
)

for view in root.findall('views/view'):
for counters in view.iter('counters'):
for counter in counters:
self.clean_counter(
'views.%s.counters.%s.%s' % (view.attrib['name'],
counters.attrib['type'],
counter.attrib['name']),
int(counter.text)
)

def parse_json_v1_server(self, response):
for counter_metric_name in [
'nsstat', 'opcode', 'qtype', 'rcode', 'zonestat'
]:
for counter in response[counter_metric_name+'s']:
self.clean_counter(
'server.counters.%s.%s' % (counter_metric_name, counter),
int(response[counter_metric_name+'s'][counter])
)

for view in response['views']:
for counters in response['views'][view]:
# This mapping maps from XML v3 layout to JSON v1
for section_name in response['views'][view]['resolver']:
for counter in \
response['views'][view]['resolver'][section_name]:
self.clean_counter(
'views.%s.counters.%s.%s' %
(view, section_name, counter),
int(response['views'][view]['resolver']
[section_name][counter])
)
Loading

0 comments on commit f946865

Please sign in to comment.