3 # Plugin to monitor the types of requsts made to the API
10 # autoconf (optional - used by munin-config)
16 from datetime import datetime, timedelta
18 CONFIG="""graph_title Requests by API call
19 graph_args --base 1000 -l 0
20 graph_vlabel requests per minute
21 graph_category nominatim
25 z2.label search (successful)
28 z3.label search (no result)
38 ENTRY_REGEX = re.compile(r'\[[^]]+\] (?P<dur>[0-9.]+) (?P<numres>\d+) (?P<type>[a-z]+) ')
39 TIME_REGEX = re.compile(r'\[(?P<t_year>\d\d\d\d)-(?P<t_month>\d\d)-(?P<t_day>\d\d) (?P<t_hour>\d\d):(?P<t_min>\d\d):(?P<t_sec>\d\d)[0-9.]*\] ')
43 """ A query log file, unpacked. """
45 def __init__(self, filename):
46 self.fd = open(filename, encoding='utf-8', errors='replace')
47 self.len = os.path.getsize(filename)
52 def seek_next(self, abstime):
55 l = self.fd.readline()
56 e = TIME_REGEX.match(l)
60 return datetime(int(e['t_year']), int(e['t_month']), int(e['t_day']),
61 int(e['t_hour']), int(e['t_min']), int(e['t_sec']))
63 def seek_to_date(self, target):
64 # start position for binary search
66 fromdate = self.seek_next(0)
69 # end position for binary search
71 while -toseek < self.len:
72 todate = self.seek_next(self.len + toseek)
73 if todate is not None:
76 if todate is None or todate < target:
78 toseek = self.len + toseek
82 bps = (toseek - fromseek) / (todate - fromdate).total_seconds()
83 newseek = fromseek + int((target - fromdate).total_seconds() * bps)
84 newdate = self.seek_next(newseek)
87 error = abs((target - newdate).total_seconds())
93 oldfromseek = fromseek
94 fromseek = toseek - error * bps
96 if fromseek <= oldfromseek:
97 fromseek = oldfromseek
98 fromdate = self.seek_next(fromseek)
100 fromdate = self.seek_next(fromseek)
101 if fromdate < target:
104 fromseek -= error * bps
109 toseek = fromseek + error * bps
111 if toseek > oldtoseek:
113 todate = self.seek_next(toseek)
115 todate = self.seek_next(toseek)
119 toseek += error * bps
120 if toseek - fromseek < 500:
126 e = ENTRY_REGEX.match(l)
131 if __name__ == '__main__':
133 if len(sys.argv) > 1 and sys.argv[1] == 'config':
142 if 'NOMINATIM_QUERYLOG' in os.environ:
143 lf = LogFile(os.environ['NOMINATIM_QUERYLOG'])
144 if lf.seek_to_date(datetime.now() - timedelta(minutes=5)):
145 for l in lf.loglines():
146 if l['type'] == 'reverse':
148 elif l['type'] == 'search':
149 if l['numres'] == '0':
153 elif l['type'] == 'place':
159 print('z1.value', reverse/5)
160 print('z2.value', searchy/5)
161 print('z3.value', searchn/5)
162 print('z4.value', lookup/5)
163 print('z4.value', details/5)