]> arthur.barton.de Git - netdata.git/blob - python.d/dns_query_time.chart.py
dns_query_time plugin: replace "." with "_" in dimensions
[netdata.git] / python.d / dns_query_time.chart.py
1 # -*- coding: utf-8 -*-
2 # Description: dns_query_time netdata python.d module
3 # Author: l2isbad
4
5 try:
6     from time import monotonic as time
7 except ImportError:
8     from time import time
9 try:
10     import dns.message, dns.query, dns.name
11     DNS_PYTHON = True
12 except ImportError:
13     DNS_PYTHON = False
14 try:
15     from queue import Queue
16 except ImportError:
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
22
23
24 # default module values (can be overridden per job in `config`)
25 update_every = 5
26 priority = 60000
27 retries = 60
28
29
30 class Service(SimpleService):
31     def __init__(self, configuration=None, name=None):
32         SimpleService.__init__(self, configuration=configuration, name=name)
33         self.order = list()
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')
39
40     def check(self):
41         if not DNS_PYTHON:
42             self.error('\'python-dnspython\' package is needed to use dns_query_time.chart.py')
43             return False
44
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
47
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')
51             return False
52         else:
53             self.domains, self.server_list = self.domains.split(), self.server_list.split()
54
55         for ns in self.server_list:
56             if not check_ns(ns):
57                 self.info('Bad NS: %s' % ns)
58                 self.server_list.remove(ns)
59                 if not self.server_list:
60                     return False
61
62         data = self._get_data(timeout=1)
63
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:
70                 return False
71
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}))
75         return True
76
77     def _get_data(self, timeout=None):
78         return dns_request(self.server_list, timeout or self.timeout, self.domains)
79
80
81 def dns_request(server_list, timeout, domains):
82     threads = list()
83     que = Queue()
84     result = dict()
85
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)
89
90         try:
91             dns_start = time()
92             dns.query.udp(request, ns, timeout=t)
93             dns_end = time()
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})
98
99     for server in server_list:
100         th = Thread(target=dns_req, args=(server, timeout, que))
101         th.start()
102         threads.append(th)
103
104     for th in threads:
105         th.join()
106         result.update(que.get())
107
108     return result
109
110
111 def check_ns(ns):
112     try:
113         return gethostbyname(ns)
114     except gaierror:
115         return False
116
117
118 def create_charts(aggregate, server_list):
119     if aggregate:
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'])
125
126         return order, definitions
127     else:
128         order = [''.join(['dns_', ns.replace('.', '_')]) for ns in server_list]
129         definitions = dict()
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('.', '_')]),
134                                                                                ns, 'absolute']]}
135         return order, definitions