@cryptotaxi247 / netdata-1 / commits / 78f2feee9

add response_time histgram for web_log

Signed-off-by: Wing924 <weihe924stephen@gmail.com>

Wing924 committed Mar 19, 2018 at 11:53 UTC 78f2feee95f01429615a0027ab1efa0345a8f1ed
2 files changed +66 -5
conf.d/python.d/web_log.conf
+1
@@ -85,6 +85,7 @@
85 # custom_log_format: # define a custom log format
86 # pattern: '(?P<address>[\da-f.:]+) -.*?"(?P<method>[A-Z]+) (?P<url>.*?)" (?P<code>[1-9]\d{2}) (?P<bytes_sent>\d+) (?P<resp_length>\d+) (?P<resp_time>\d+\.\d+) '
87 # time_multiplier: 1000000 # type <int> - convert time to microseconds
88 +# histgram: [1,3,10,30,100, ...] # type list of int - Cumulative histogram of response time in milli seconds
89
90 # ----------------------------------------------------------------------
91 # WEB SERVER CONFIGURATION
python.d/web_log.chart.py
+65 -5
@@ -5,6 +5,7 @@
5 import bisect
6 import re
7 import os
8 +import sys
9
10 from collections import namedtuple, defaultdict
11 from copy import deepcopy
@@ -21,7 +22,8 @@ from bases.FrameworkServices.LogService import LogService
22
23 ORDER_APACHE_CACHE = ['apache_cache']
24
24 -ORDER_WEB = ['response_statuses', 'response_codes', 'bandwidth', 'response_time', 'response_time_upstream',
25 +ORDER_WEB = ['response_statuses', 'response_codes', 'bandwidth',
26 + 'response_time', 'response_time_hist', 'response_time_upstream', 'response_time_upstream_hist',
27 'requests_per_url', 'requests_per_user_defined', 'http_method', 'http_version',
28 'requests_per_ipproto', 'clients', 'clients_all']
29
@@ -55,6 +57,10 @@ CHARTS_WEB = {
57 ['resp_time_max', 'max', 'incremental', 1, 1000],
58 ['resp_time_avg', 'avg', 'incremental', 1, 1000]
59 ]},
60 + 'response_time_hist': {
61 + 'options': [None, 'Processing Time Histgram', 'requests/s', 'timings', 'web_log.response_time_hist', 'line'],
62 + 'lines': [
63 + ]},
64 'response_time_upstream': {
65 'options': [None, 'Processing Time Upstream', 'milliseconds', 'timings',
66 'web_log.response_time_upstream', 'area'],
@@ -63,6 +69,11 @@ CHARTS_WEB = {
69 ['resp_time_upstream_max', 'max', 'incremental', 1, 1000],
70 ['resp_time_upstream_avg', 'avg', 'incremental', 1, 1000]
71 ]},
72 + 'response_time_upstream_hist': {
73 + 'options': [None, 'Processing Time Histgram', 'requests/s', 'timings',
74 + 'web_log.response_time_upstream_hist', 'line'],
75 + 'lines': [
76 + ]},
77 'clients': {
78 'options': [None, 'Current Poll Unique Client IPs', 'unique ips', 'clients', 'web_log.clients', 'stacked'],
79 'lines': [
@@ -347,8 +358,30 @@ class Web:
358 """
359 if 'resp_time' not in match_dict:
360 self.order.remove('response_time')
361 + self.order.remove('response_time_hist')
362 if 'resp_time_upstream' not in match_dict:
363 self.order.remove('response_time_upstream')
364 + self.order.remove('response_time_upstream_hist')
365 +
366 + # Add 'response_time_hist' and 'response_time_upstream_hist' charts if is specified in the configuration
367 + histgram = self.configuration.get('histgram', None)
368 + if type(histgram) is list:
369 + self.storage['bucket_index'] = histgram[:]
370 + self.storage['bucket_index'].append(sys.maxint)
371 + self.storage['buckets'] = [0] * (len(histgram) + 1)
372 + self.storage['upstream_buckets'] = [0] * (len(histgram) + 1)
373 + hist_lines = self.definitions['response_time_hist']['lines']
374 + upstream_hist_lines = self.definitions['response_time_upstream_hist']['lines']
375 + for i, le in enumerate(histgram):
376 + hist_key = "response_time_hist_%d" % i
377 + upstream_hist_key = "response_time_upstream_hist_%d" % i
378 + hist_lines.append([hist_key, str(le), 'incremental', 1, 1])
379 + upstream_hist_lines.append([upstream_hist_key, str(le), 'incremental', 1, 1])
380 +
381 + hist_lines.append(["response_time_hist_%d" % len(histgram), '+Inf', 'incremental', 1, 1])
382 + upstream_hist_lines.append(["response_time_upstream_hist_%d" % len(histgram), '+Inf', 'incremental', 1, 1])
383 + elif histgram is not None:
384 + self.error("expect histgram list, but was {}".format(type(histgram)))
385
386 if not self.configuration.get('all_time', True):
387 self.order.remove('clients_all')
@@ -431,11 +464,15 @@ class Web:
464 resp_length = match_dict['resp_length'] if '-' not in match_dict['resp_length'] else 0
465 self.data['resp_length'] += int(resp_length)
466 if 'resp_time' in match_dict:
434 - get_timings(timings=timings['resp_time'],
435 - time=self.storage['func_resp_time'](float(match_dict['resp_time'])))
467 + resp_time = self.storage['func_resp_time'](float(match_dict['resp_time']))
468 + get_timings(timings=timings['resp_time'], time=resp_time)
469 + if 'bucket_index' in self.storage:
470 + get_hist(self.storage['bucket_index'], self.storage['buckets'], resp_time / 1000)
471 if 'resp_time_upstream' in match_dict and match_dict['resp_time_upstream'] != '-':
437 - get_timings(timings=timings['resp_time_upstream'],
438 - time=self.storage['func_resp_time'](float(match_dict['resp_time_upstream'])))
472 + resp_time_upstream = self.storage['func_resp_time'](float(match_dict['resp_time_upstream']))
473 + get_timings(timings=timings['resp_time_upstream'], time=resp_time_upstream)
474 + if 'bucket_index' in self.storage:
475 + get_hist(self.storage['bucket_index'], self.storage['upstream_buckets'], resp_time / 1000)
476 # requests per ip proto
477 proto = 'ipv6' if ':' in match_dict['address'] else 'ipv4'
478 self.data['req_' + proto] += 1
@@ -456,6 +493,17 @@ class Web:
493 self.data[elem + '_min'] += timings[elem]['minimum']
494 self.data[elem + '_avg'] += timings[elem]['summary'] / timings[elem]['count']
495 self.data[elem + '_max'] += timings[elem]['maximum']
496 +
497 + # histgram
498 + if 'bucket_index' in self.storage:
499 + buckets = self.storage['buckets']
500 + upstream_buckets = self.storage['upstream_buckets']
501 + for i, le in enumerate(self.storage['bucket_index']):
502 + hist_key = "response_time_hist_%d" % i
503 + upstream_hist_key = "response_time_upstream_hist_%d" % i
504 + self.data[hist_key] = buckets[i]
505 + self.data[upstream_hist_key] = upstream_buckets[i]
506 +
507 return self.data
508
509 def find_regex(self, last_line):
@@ -903,6 +951,18 @@ def get_timings(timings, time):
951 timings['summary'] += time
952 timings['count'] += 1
953
954 +def get_hist(index, buckets, time):
955 + """
956 + :param index: histgram index (Ex. [10, 50, 100, 150, ...])
957 + :param buckets: histgram buckets
958 + :param time: time
959 + :return: None
960 + """
961 + for i in xrange(len(index)-1, -1, -1):
962 + if time <= index[i]:
963 + buckets[i] += 1
964 + else:
965 + break
966
967 def address_not_in_pool(pool, address, pool_size):
968 """