1 # -*- coding: utf-8 -*-
2 # Description: dns_query_time netdata python.d module
6 from time import monotonic as time
10 import dns.message, dns.query, dns.name
15 from queue import Queue
17 from Queue import Queue
18 from random import choice
19 from threading import Thread
20 from socket import gethostbyname, gaierror
21 from base import SimpleService
24 # default module values (can be overridden per job in `config`)
30 class Service(SimpleService):
31 def __init__(self, configuration=None, name=None):
32 SimpleService.__init__(self, configuration=configuration, name=name)
34 self.definitions = dict()
35 self.timeout = self.configuration.get('response_timeout', 4)
36 self.aggregate = self.configuration.get('aggregate', True)
37 self.domains = self.configuration.get('domains')
38 self.server_list = self.configuration.get('dns_servers')
42 self.error('\'python-dnspython\' package is needed to use dns_query_time.chart.py')
45 self.timeout = self.timeout if isinstance(self.timeout, int) else 4
46 self.update_every = self.timeout + 1 if self.update_every <= self.timeout else self.update_every
48 if not all([self.domains, self.server_list,
49 isinstance(self.server_list, str), isinstance(self.domains, str)]):
50 self.error('server_list and domain_list can\'t be empty')
53 self.domains, self.server_list = self.domains.split(), self.server_list.split()
55 for ns in self.server_list:
57 self.info('Bad NS: %s' % ns)
58 self.server_list.remove(ns)
59 if not self.server_list:
62 data = self._get_data(timeout=1)
64 down_servers = [s for s in data if data[s] == -100]
65 for down in down_servers:
66 down = down[3:].replace('_', '.')
67 self.info('Removed due to non response %s' % down)
68 self.server_list.remove(down)
69 if not self.server_list:
72 self._data_from_check = data
73 self.order, self.definitions = create_charts(aggregate=self.aggregate, server_list=self.server_list)
74 self.info(str({'domains': len(self.domains), 'servers': self.server_list}))
77 def _get_data(self, timeout=None):
78 return dns_request(self.server_list, timeout or self.timeout, self.domains)
81 def dns_request(server_list, timeout, domains):
86 def dns_req(ns, t, q):
87 domain = dns.name.from_text(choice(domains))
88 request = dns.message.make_query(domain, dns.rdatatype.A)
92 dns.query.udp(request, ns, timeout=t)
94 query_time = round((dns_end - dns_start) * 1000)
95 q.put({'_'.join(['ns', ns.replace('.', '_')]): query_time})
96 except dns.exception.Timeout:
97 q.put({'_'.join(['ns', ns.replace('.', '_')]): -100})
99 for server in server_list:
100 th = Thread(target=dns_req, args=(server, timeout, que))
106 result.update(que.get())
113 return gethostbyname(ns)
118 def create_charts(aggregate, server_list):
120 order = ['dns_group']
121 definitions = {'dns_group': {'options': [None, 'DNS Response Time', 'ms', 'name servers',
122 'dns_query_time.response_time', 'line'], 'lines': []}}
123 for ns in server_list:
124 definitions['dns_group']['lines'].append(['_'.join(['ns', ns.replace('.', '_')]), ns, 'absolute'])
126 return order, definitions
128 order = [''.join(['dns_', ns.replace('.', '_')]) for ns in server_list]
130 for ns in server_list:
131 definitions[''.join(['dns_', ns.replace('.', '_')])] = {'options': [None, 'DNS Response Time', 'ms', ns,
132 'dns_query_time.response_time', 'area'],
133 'lines': [['_'.join(['ns', ns.replace('.', '_')]),
135 return order, definitions