1#!/usr/bin/env python3
2
3"""Implementation of Processes widget."""
4
5
6
7
8from datetime import timedelta
9from collections import OrderedDict
10
11from chart.db.connection import db_connect
12from chart.reports.widget import Widget
13from chart.common.prettyprint import Table
14
15db_conn = db_connect('PROCESSES')
16
17
18def compute_performance_stats(start_time, stop_time):
19 """Calculate per-worker statistics showing number of processes executed and
20 total time spent in execution."""
21
22 # procs = {} # process id indexed to dictionary of name, job count, busy
23 # worker name indexed to dictionary of process id
24 # indexed to 'busy', 'processes', 'jobs'
25 # for proc_id, in db.query('SELECT process_id FROM jobs WHERE
26 # gen_time>=:start_time AND gen_time<:stop_time
27
28 procs = {} # worker name against dictionary of process count, busy
29 for worker, busy in db_conn.query('SELECT worker, execute_stop-execute_start '
30 'FROM processes '
31 'WHERE execute_start>=:start_time AND execute_stop<:stop_time',
32 start_time=start_time, stop_time=stop_time):
33
34 proc = procs.get(worker)
35 if proc is None:
36 proc = {'count': 0,
37 'busy': timedelta()}
38
39 procs[worker] = proc
40
41 proc['count'] += 1
42 proc['busy'] += busy
43
44 return procs
45
46
47class Processes(Widget):
48 """Daily digest report widget.
49 Displays the load of each worker process. """
50
51 name = 'digest-processes'
52
53 document_options = OrderedDict([
54 ('sensing_start', {'type': 'datetime'}),
55 ('sensing_stop', {'type': 'datetime'})])
56
57 def __init__(self):
58 super(Processes, self).__init__()
59
60 def html(self, document):
61 dc = document.config
62 html = document.html
63
64 t = Table(headings=('Worker', 'Processes', 'Busy'))
65 for worker, info in compute_performance_stats(dc['sensing-start'],
66 dc['sensing-stop']).items():
67 t.append((worker, info['count'], info['busy']))
68
69 t.write_html(html)
70
71
72def main():
73 """Command line entry point."""
74 import io
75 from chart.common.args import ArgumentParser
76 parser = ArgumentParser()
77
78 parser.add_argument('--start',
79 type=ArgumentParser.start_time,
80 metavar='TIME',
81 help='Begin search at TIME.')
82 parser.add_argument('--stop',
83 type=ArgumentParser.stop_time,
84 metavar='TIME',
85 help='End search at TIME.')
86 args = parser.parse_args()
87
88 widget = Processes()
89
90 class Document:
91 """Fake document object"""
92 def __init__(self):
93 self.config = None
94 self.html = io.StringIO()
95
96 document = Document()
97 document.config = {'sensing_start': args.start,
98 'sensing_stop': args.stop}
99
100 widget.html(document)
101
102 def html_to_console(html):
103 """Convert HTML to console text"""
104 return html.replace(
105 '<br>', '\n').replace(
106 ' ', ' ').replace(
107 '<h2>', '').replace(
108 '</h2>', '\n')
109
110 print(html_to_console(document.html.getvalue()))
111
112if __name__ == '__main__':
113 main()