curses_display.py 6.8 KB
Newer Older
Mario Hock's avatar
Mario Hock committed
1
2
3
4
5
6
7
8
9
10
11
# -*- coding:utf-8 -*-

'''
Curses display for »cpunetlog«.

This code is inspired and partially copied from »bwtop« written by
"Mahmoud Adel <mahmoud.adel2@gmail.com>" and distributed under the MIT license.
'''

import curses
import time
Mario Hock's avatar
Mario Hock committed
12
import helpers
Mario Hock's avatar
Mario Hock committed
13
14
15
16
17
18
19
20

## XXX disable colors
disablecolorskipped = True

stdscr = None

## some "constants"/preferences
nics = None
Mario Hock's avatar
Mario Hock committed
21
nic_speeds = None
Mario Hock's avatar
Mario Hock committed
22
divisor = 1000000.0
Mario Hock's avatar
Mario Hock committed
23
rounding_digits = 2
Mario Hock's avatar
Mario Hock committed
24
unit = "MBits"
Mario Hock's avatar
Mario Hock committed
25

Mario Hock's avatar
Mario Hock committed
26
## GUI, positions of fields
Mario Hock's avatar
Mario Hock committed
27
28
29
LABEL_CPU_UTIL = 18
LABEL_CPU_USER = 48
LABEL_CPU_SYSTEM = 64
Mario Hock's avatar
Mario Hock committed
30
31
32
LABEL_Sent = LABEL_CPU_UTIL
LABEL_Received = LABEL_CPU_USER

Mario Hock's avatar
..    
Mario Hock committed
33
34
35
36
37
38
## TODO ideas..
#   - total (GB transferred)
#   - other (CPU usage)

## TODO idea: smoothing..?

Mario Hock's avatar
Mario Hock committed
39
40
41
42
43

def _format_net_speed(speed):
    return str( round(speed / divisor, rounding_digits) )


Mario Hock's avatar
Mario Hock committed
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
def _display_cpu_bar(y, x, cpu):
    # Constants
    CPU_BAR_COLORS = ( curses.color_pair(3) | curses.A_REVERSE,    # user
                       curses.color_pair(4) | curses.A_REVERSE,    # system
                       curses.color_pair(5) | curses.A_REVERSE,    # other
                       curses.color_pair(3) )                      # idle

    # Calculate proportions
    cpu_util = 100-cpu.idle
    other = 100 - sum( (cpu.user, cpu.system, cpu.idle) )
    proportions = [cpu.user, cpu.system, other, cpu.idle]

    # Prepare text.
    text = '{0:.2%}'.format((cpu_util)/100.0)
    split_text = helpers.split_proprtionally(text, proportions, 20)

    # Write text on screen (curses).
    stdscr.move(y,x)
    for s, options in zip(split_text, CPU_BAR_COLORS):
        stdscr.addstr(s, options)



Mario Hock's avatar
Mario Hock committed
67
68
69

def init():
    global stdscr
Mario Hock's avatar
Mario Hock committed
70
71
72
73
    global nic_speeds

    if not nic_speeds:
        nic_speeds = helpers.get_nic_speeds()
Mario Hock's avatar
Mario Hock committed
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89

    stdscr = curses.initscr()
    curses.noecho()
    curses.cbreak()
    stdscr.keypad(True)
    curses.curs_set(False)
    stdscr.nodelay(True)

    curses.start_color()
    curses.use_default_colors()
    if not disablecolorskipped:
        curses.init_pair(1, -1, -1)
        curses.init_pair(2, -1, -1)
        curses.init_pair(3, -1, -1)
        curses.init_pair(4, -1, -1)
    else:
Mario Hock's avatar
Mario Hock committed
90
91
92
93
94
95
        curses.init_pair(1, curses.COLOR_MAGENTA, -1)         # "CPUX", "ethX"
        curses.init_pair(2, curses.COLOR_BLUE, -1)            # "util", "sent", "received", ...
        curses.init_pair(3, curses.COLOR_GREEN, -1)           # <values>
        curses.init_pair(4, curses.COLOR_YELLOW, -1)          # "Total", (<cpu-system> ?)
        curses.init_pair(5, curses.COLOR_CYAN, -1)            # <cpu-system> / <cpu-other>
        curses.init_pair(6, curses.COLOR_WHITE, -1)           # <cpu-system> / <cpu-other>
Mario Hock's avatar
Mario Hock committed
96
97
98
99
100
101
102
103
104
105

    ## Show some output to avoid upsetting the user
    stdscr.addstr(3, 3, "loading ...", curses.A_BOLD)
    stdscr.refresh()



def display(measurement):
    global stdscr

Mario Hock's avatar
Mario Hock committed
106
    ## Press 'q' to quit.
Mario Hock's avatar
Mario Hock committed
107
108
109
110
    pressedkey = stdscr.getch()
    if pressedkey == ord('q'):
        return False

Mario Hock's avatar
Mario Hock committed
111
    ## Header
Mario Hock's avatar
Mario Hock committed
112
113
114
    stdscr.clear()
    stdscr.border(0)
    timenow = time.strftime("%H:%M:%S")
Mario Hock's avatar
Mario Hock committed
115
116
117
    stdscr.addstr(1, 1, 'CPUnetLOG', curses.A_BOLD)
    stdscr.addstr(1, LABEL_Sent, 'Time: {}'.format(timenow,), curses.A_BOLD)
    stdscr.addstr(1, LABEL_Received, 'Interval: {}s'.format(round(measurement.timespan, 1)), curses.A_BOLD)
Mario Hock's avatar
Mario Hock committed
118
119
    stdscr.refresh()

Mario Hock's avatar
Mario Hock committed
120
121
122
123
124
    y = 3

    ## CPU ##
    num=1
    for cpu in measurement.cpu_times_percent:
Mario Hock's avatar
Mario Hock committed
125
        # static labels
Mario Hock's avatar
Mario Hock committed
126
        stdscr.addstr(y, 1, 'CPU{0}'.format( num ), curses.color_pair(1))
Mario Hock's avatar
Mario Hock committed
127
        stdscr.addstr(y, LABEL_CPU_UTIL, 'util: ', curses.color_pair(2))
Mario Hock's avatar
Mario Hock committed
128
        stdscr.addstr(y, LABEL_CPU_UTIL+26, '|', curses.color_pair(2))
Mario Hock's avatar
Mario Hock committed
129
130
        stdscr.addstr(y, LABEL_CPU_USER, 'user: ', curses.color_pair(2))
        stdscr.addstr(y, LABEL_CPU_SYSTEM, 'system: ', curses.color_pair(2))
Mario Hock's avatar
Mario Hock committed
131
132

        # CPU bar
Mario Hock's avatar
Mario Hock committed
133
        _display_cpu_bar( y, LABEL_CPU_UTIL+6, cpu )
Mario Hock's avatar
Mario Hock committed
134
135

        # user/system
Mario Hock's avatar
Mario Hock committed
136
137
        stdscr.addstr(y, LABEL_CPU_USER+6, '{0:.2%}'.format( cpu.user/100.0 ), curses.color_pair(3))
        stdscr.addstr(y, LABEL_CPU_SYSTEM+8, '{0:.2%}'.format( cpu.system/100.0 ), curses.color_pair(3))
Mario Hock's avatar
Mario Hock committed
138
139
140
141
142
143
144
145
146
147

        num += 1
        y += 1




    ## Network ##

    y += 1
Mario Hock's avatar
Mario Hock committed
148
    stdscr.hline(y, 1, "-", 78)
Mario Hock's avatar
Mario Hock committed
149
150
    y += 1

Mario Hock's avatar
Mario Hock committed
151
152
153
154
155
156
157
158
159
160
161
162
163
    # display all nics (if not set otherwise)
    if nics:
        active_nics = nics
    else:
        active_nics = measurement.net_io.keys()

    sum_sending = 0
    sum_receiving = 0

    ## display the values
    for nic in active_nics:
        values = measurement.net_io[nic]

Mario Hock's avatar
Mario Hock committed
164
165
        _send = values.ratio["bytes_sent"] * 8  # Bits/s
        _recv = values.ratio["bytes_recv"] * 8  # Bits/s
Mario Hock's avatar
Mario Hock committed
166
        sending = _format_net_speed( _send )
Mario Hock's avatar
Mario Hock committed
167
        send_ratio = _send/nic_speeds[nic]
Mario Hock's avatar
Mario Hock committed
168
        receiving = _format_net_speed( _recv )
Mario Hock's avatar
Mario Hock committed
169
        receive_ratio = _recv/nic_speeds[nic]
Mario Hock's avatar
Mario Hock committed
170
171
172

        sum_sending += _send
        sum_receiving += _recv
Mario Hock's avatar
Mario Hock committed
173
174

        stdscr.addstr(y, 1, '{0}'.format(nic), curses.color_pair(1))
Mario Hock's avatar
Mario Hock committed
175
        stdscr.addstr(y, LABEL_Sent, 'Sent: ', curses.color_pair(2))
Mario Hock's avatar
Mario Hock committed
176
        stdscr.addstr(y, LABEL_Sent+26, "|", curses.color_pair(2))
Mario Hock's avatar
Mario Hock committed
177
        stdscr.addstr(y, LABEL_Received, 'Received: ', curses.color_pair(2))
Mario Hock's avatar
Mario Hock committed
178
        stdscr.addstr(y, LABEL_Received+30, "|", curses.color_pair(2))
Mario Hock's avatar
Mario Hock committed
179

Mario Hock's avatar
Mario Hock committed
180
        ## TODO rewrite in nice ^^
Mario Hock's avatar
Mario Hock committed
181
182
183
184
        ## XXX prototypical "inline"-coloring
        _snd_str = '{0} {1}/s'.format(sending, unit, send_ratio)
        _snd_str += " " * (20-len(_snd_str))
        _load_len = int(send_ratio * 20)
Mario Hock's avatar
Mario Hock committed
185
186
        stdscr.addstr(y, LABEL_Sent+6, _snd_str[0:_load_len], curses.color_pair(3)|curses.A_REVERSE)
        stdscr.addstr(y, LABEL_Sent+6+_load_len, _snd_str[_load_len:], curses.color_pair(3))
Mario Hock's avatar
Mario Hock committed
187
188
189
190

        _recv_str = '{0} {1}/s'.format(receiving, unit, send_ratio)
        _recv_str += " " * (20-len(_recv_str))
        _load_len = int(receive_ratio * 20)
Mario Hock's avatar
Mario Hock committed
191
192
        stdscr.addstr(y, LABEL_Received+10, _recv_str[0:_load_len], curses.color_pair(3)|curses.A_REVERSE)
        stdscr.addstr(y, LABEL_Received+10+_load_len, _recv_str[_load_len:], curses.color_pair(3))
Mario Hock's avatar
Mario Hock committed
193

Mario Hock's avatar
Mario Hock committed
194
        ## XXX TESTING
Mario Hock's avatar
Mario Hock committed
195
196
197
198
199
        #y += 1
        #stdscr.addstr(y, 25, "|" + " "*20 + "|", curses.color_pair(2))
        #stdscr.addstr(y, 26, " " * int(send_ratio * 20), curses.color_pair(3)|curses.A_REVERSE)
        #stdscr.addstr(y, 59, "|" + " "*20 + "|", curses.color_pair(2))
        #stdscr.addstr(y, 60, " " * int(receive_ratio * 20), curses.color_pair(3)|curses.A_REVERSE)
Mario Hock's avatar
Mario Hock committed
200

Mario Hock's avatar
Mario Hock committed
201
202
203
204
205
        y += 1

    ## Total
    y+=1
    stdscr.addstr(y, 1, 'Total:', curses.color_pair(4))
Mario Hock's avatar
Mario Hock committed
206
207
208
209
    stdscr.addstr(y, LABEL_Sent, 'Sent:', curses.color_pair(2))
    stdscr.addstr(y, LABEL_Sent+6, '{0} {1}/s'.format(_format_net_speed(sum_sending), unit), curses.color_pair(3))
    stdscr.addstr(y, LABEL_Received, 'Received:', curses.color_pair(2))
    stdscr.addstr(y, LABEL_Received+10, '{0} {1}/s'.format(_format_net_speed(sum_receiving),unit), curses.color_pair(3))
Mario Hock's avatar
Mario Hock committed
210
211
212
213
214
215
216
217
218
219
220
221
222
223

    stdscr.refresh()

    return True


def close():
    global stdscr

    curses.nocbreak()
    stdscr.keypad(False)
    curses.echo()
    curses.curs_set(True)
    curses.endwin()