curses_display.py 6.55 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
27
28
29
30
31
## TODO ideas..
#   - total (GB transferred)
#   - other (CPU usage)

## TODO idea: smoothing..?

Mario Hock's avatar
Mario Hock committed
32
33
34
35
36

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


Mario Hock's avatar
Mario Hock committed
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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
60
61
62

def init():
    global stdscr
Mario Hock's avatar
Mario Hock committed
63
64
65
66
    global nic_speeds

    if not nic_speeds:
        nic_speeds = helpers.get_nic_speeds()
Mario Hock's avatar
Mario Hock committed
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82

    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
83
84
85
86
87
88
        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
89
90
91
92
93
94
95
96
97
98

    ## 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
99
    ## Press 'q' to quit.
Mario Hock's avatar
Mario Hock committed
100
101
102
103
    pressedkey = stdscr.getch()
    if pressedkey == ord('q'):
        return False

Mario Hock's avatar
Mario Hock committed
104
    ## Header
Mario Hock's avatar
Mario Hock committed
105
106
107
    stdscr.clear()
    stdscr.border(0)
    timenow = time.strftime("%H:%M:%S")
Mario Hock's avatar
Mario Hock committed
108
    stdscr.addstr(1, 1, 'CPUnetLOG          Time: {0}                Interval: {1}s'.format(timenow, round(measurement.timespan, 1)), curses.A_BOLD)
Mario Hock's avatar
Mario Hock committed
109
110
    stdscr.refresh()

Mario Hock's avatar
Mario Hock committed
111
112
113
114
115
    y = 3

    ## CPU ##
    num=1
    for cpu in measurement.cpu_times_percent:
Mario Hock's avatar
Mario Hock committed
116
        # static labels
Mario Hock's avatar
Mario Hock committed
117
118
        stdscr.addstr(y, 1, 'CPU{0}'.format( num ), curses.color_pair(1))
        stdscr.addstr(y, 20, 'util:', curses.color_pair(2))
119
        stdscr.addstr(y, 46, '|', curses.color_pair(2))
Mario Hock's avatar
Mario Hock committed
120
121
        stdscr.addstr(y, 50, 'user:', curses.color_pair(2))
        stdscr.addstr(y, 66, 'system:', curses.color_pair(2))
Mario Hock's avatar
Mario Hock committed
122
123
124
125
126
127

        # CPU bar
        _display_cpu_bar( y, 26, cpu )

        # user/system
        stdscr.addstr(y, 56, '{0:.2%}'.format( cpu.user/100.0 ), curses.color_pair(3))
Mario Hock's avatar
Mario Hock committed
128
129
130
131
132
133
134
135
136
137
138
139
140
141
        stdscr.addstr(y, 74, '{0:.2%}'.format( cpu.system/100.0 ), curses.color_pair(3))

        num += 1
        y += 1




    ## Network ##

    y += 1
    stdscr.hline(y, 1, "-", 85)
    y += 1

Mario Hock's avatar
Mario Hock committed
142
143
144
145
146
147
148
149
150
151
152
153
154
    # 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
155
156
        _send = values.ratio["bytes_sent"] * 8  # Bits/s
        _recv = values.ratio["bytes_recv"] * 8  # Bits/s
Mario Hock's avatar
Mario Hock committed
157
        sending = _format_net_speed( _send )
Mario Hock's avatar
Mario Hock committed
158
        send_ratio = _send/nic_speeds[nic]
Mario Hock's avatar
Mario Hock committed
159
        receiving = _format_net_speed( _recv )
Mario Hock's avatar
Mario Hock committed
160
        receive_ratio = _recv/nic_speeds[nic]
Mario Hock's avatar
Mario Hock committed
161
162
163

        sum_sending += _send
        sum_receiving += _recv
Mario Hock's avatar
Mario Hock committed
164
165

        stdscr.addstr(y, 1, '{0}'.format(nic), curses.color_pair(1))
Mario Hock's avatar
Mario Hock committed
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
        stdscr.addstr(y, 20, 'Sent: |', curses.color_pair(2))
        stdscr.addstr(y, 50, 'Received: |', curses.color_pair(2))
        stdscr.addstr(y, 47, "|", curses.color_pair(2))
        stdscr.addstr(y, 81, "|", curses.color_pair(2))

        ## 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)
        stdscr.addstr(y, 27, _snd_str[0:_load_len], curses.color_pair(3)|curses.A_REVERSE)
        stdscr.addstr(y, 27+_load_len, _snd_str[_load_len:], curses.color_pair(3))

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

Mario Hock's avatar
Mario Hock committed
184
        ## XXX TESTING
Mario Hock's avatar
Mario Hock committed
185
186
187
188
189
        #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
190

Mario Hock's avatar
Mario Hock committed
191
192
193
194
195
196
        y += 1

    ## Total
    y+=1
    stdscr.addstr(y, 1, 'Total:', curses.color_pair(4))
    stdscr.addstr(y, 20, 'Sent:', curses.color_pair(2))
Mario Hock's avatar
Mario Hock committed
197
198
    #stdscr.addstr(y, 26, '{0} {1}/s'.format(_format_net_speed(sum_sending), unit), curses.color_pair(3) | curses.A_STANDOUT)
    stdscr.addstr(y, 26, '{0} {1}/s'.format(_format_net_speed(sum_sending), unit), curses.color_pair(3))
Mario Hock's avatar
Mario Hock committed
199
    stdscr.addstr(y, 50, 'Received:', curses.color_pair(2))
Mario Hock's avatar
Mario Hock committed
200
201
    #stdscr.addstr(y, 60, '{0} {1}/s'.format(_format_net_speed(sum_receiving),unit), curses.color_pair(3) | curses.A_STANDOUT)
    stdscr.addstr(y, 60, '{0} {1}/s'.format(_format_net_speed(sum_receiving),unit), curses.color_pair(3))
Mario Hock's avatar
Mario Hock committed
202
203
204
205
206
207
208
209
210
211
212
213
214
215

    stdscr.refresh()

    return True


def close():
    global stdscr

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