Class: UI

Inherits:
Object
  • Object
show all
Defined in:
lib/ui.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config) ⇒ UI

Returns a new instance of UI.



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/ui.rb', line 8

def initialize(config)
  @config = config

  @stat_cols    = %w[ calls req/s kB/s hitratio ]
  @stat_col_width = 15
  @key_col_width  = 30
  @avg_period = @config[:avg_period]
  @sort_mode = :reqps
  @sort_order = :desc
  @show_percent = false

  @commands = {
    'B' => "sort by bandwidth",
    'C' => "sort by call number",
    'H' => "sort by hitratio",
    'K' => "sort by key",
    'P' => "display percentages",
    'Q' => "quit",
    'R' => "sort by request rate",
    'T' => "toggle sort order (asc|desc)"
  }

  init_screen
  cbreak
  curs_set(0)

  # set keyboard input timeout - sneaky way to manage refresh rate
  Curses.timeout = @config[:refresh_rate]

  if can_change_color?
    start_color
    init_pair(0, COLOR_WHITE, COLOR_BLACK)
    init_pair(1, COLOR_WHITE, COLOR_BLUE)
    init_pair(2, COLOR_WHITE, COLOR_RED)
  end
end

Instance Attribute Details

#show_percentObject

Returns the value of attribute show_percent.



6
7
8
# File 'lib/ui.rb', line 6

def show_percent
  @show_percent
end

#sort_modeObject

Returns the value of attribute sort_mode.



6
7
8
# File 'lib/ui.rb', line 6

def sort_mode
  @sort_mode
end

#sort_orderObject

Returns the value of attribute sort_order.



6
7
8
# File 'lib/ui.rb', line 6

def sort_order
  @sort_order
end

Instance Method Details



57
58
59
60
61
62
# File 'lib/ui.rb', line 57

def footer
  footer_text = @commands.map { |k,v| "#{k}:#{v}" }.join(' | ')
  setpos(lines - 1, 0)
  attrset(color_pair(2))
  addstr(sprintf "%-#{cols}s", footer_text)
end

#headerObject



45
46
47
48
49
50
51
52
53
54
55
# File 'lib/ui.rb', line 45

def header
  # pad stat columns to @stat_col_width
  @stat_cols = @stat_cols.map { |c| sprintf("%#{@stat_col_width}s", c) }

  @url_col_width = cols - @key_col_width - (@stat_cols.length * @stat_col_width)

  attrset(color_pair(1))
  setpos(0,0)
  
  addstr(sprintf "%-#{@key_col_width}s%-#{@url_col_width}s%s", (@config[:host_mode]) ? "hostname" : "request pattern", "last url", @stat_cols.join)
end

#input_handlerObject



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/ui.rb', line 173

def input_handler
  # Curses.getch has a bug in 1.8.x causing non-blocking
  # calls to block reimplemented using IO.select
  if RUBY_VERSION =~ /^1.8/
    refresh_secs = @config[:refresh_rate].to_f / 1000

    if IO.select([STDIN], nil, nil, refresh_secs)
      c = getch
      c.chr
    else
      nil
    end
  else
    getch
  end
end

#render_stats(pipe) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/ui.rb', line 64

def render_stats(pipe)
  render_start_t = Time.now.to_f * 1000

  # subtract header + footer lines
  maxlines = lines - 3
  offset = 1

  # construct and render footer stats line
  setpos(lines - 2, 0)
  attrset(color_pair(2))
  header_summary = sprintf "%-24s %-14s %-14s %-14s %-14s",
    "sort mode: #{@sort_mode.to_s} (#{@sort_order.to_s})",
    "| requests: #{pipe.stats[:total_reqs]}",
    "| bytes out: #{pipe.stats[:total_bytes]}",
    "| duration: #{Time.now.to_i - pipe.start_time.to_i}s",
    "| samples: #{@avg_period}"
  addstr(sprintf "%-#{cols}s", header_summary)

  # reset colours for main key display
  attrset(color_pair(0))

  top = []
  totals = {}

  pipe.semaphore.synchronize do
    # we may have seen no packets received on the pipe thread
    return if pipe.start_time.nil?

    time_since_start = Time.now.to_f - pipe.start_time
    elapsed = time_since_start < @avg_period ? time_since_start : @avg_period

    # calculate hits+misses, request rate, bandwidth and hitratio
    pipe.stats[:requests].each do |key,values|
      total_hits = values[:hit].inject(:+)
      total_calls = total_hits + values[:miss].inject(:+)
      total_bytes = values[:bytes].inject(:+)

      pipe.stats[:calls][key] = total_calls
      pipe.stats[:reqps][key] = total_calls.to_f / elapsed
      pipe.stats[:bps][key] = total_bytes.to_f / elapsed
      pipe.stats[:hitratio][key] = total_hits.to_f * 100 / total_calls
    end

    if @sort_mode == :key
      top = pipe.stats[:requests].sort { |a,b| a[0] <=> b[0] }
    else
      top = pipe.stats[@sort_mode].sort { |a,b| a[1] <=> b[1] }
    end

    totals = {
      :calls => pipe.stats[:calls].values.inject(:+),
      :reqps => pipe.stats[:reqps].values.inject(:+),
      :bps => pipe.stats[:bps].values.inject(:+)
    }
  end

  unless @sort_order == :asc
    top.reverse!
  end

  for i in 0..maxlines-1
    if i < top.length
      k = top[i][0]

      # if the key is too wide for the column truncate it and add an ellipsis
      display_key = k.length > @key_col_width ? "#{k[0..@key_col_width-4]}..." : k
      display_url = pipe.stats[:requests][k][:last]
      display_url = display_url.length > @url_col_width ? "#{display_url[0..@url_col_width-4]}..." : display_url

      # render each key
      if @show_percent
        line = sprintf "%-#{@key_col_width}s%-#{@url_col_width}s %14.2f %14.2f %14.2f %14.2f",
                 display_key, display_url,
                 pipe.stats[:calls][k].to_f / totals[:calls] * 100,
                 pipe.stats[:reqps][k] / totals[:reqps] * 100,
                 pipe.stats[:bps][k] / totals[:bps] * 100,
                 pipe.stats[:hitratio][k]
      else
        line = sprintf "%-#{@key_col_width}s%-#{@url_col_width}s %14.d %14.2f %14.2f %14.2f",
                 display_key, display_url,
                 pipe.stats[:calls][k],
                 pipe.stats[:reqps][k],
                 pipe.stats[:bps][k] / 1000,
                 pipe.stats[:hitratio][k]
      end
    else
      # clear remaining lines
      line = " "*cols
    end

    setpos(1 + i, 0)
    addstr(line)
  end

  # Display column totals
  unless @show_percent
    setpos(top.length + 2, 0)
    line = sprintf "%-#{@key_col_width + @url_col_width}s %14.d %14.2f %14.2f",
             "TOTAL", totals[:calls].to_i, totals[:reqps].to_f, totals[:bps].to_f / 1000
    addstr(line)
  end

  # print render time in status bar
  runtime = (Time.now.to_f * 1000) - render_start_t
  attrset(color_pair(2))
  setpos(lines - 2, cols - 24)
  addstr(sprintf "render time: %4.3f (ms)", runtime)
end

#stopObject



190
191
192
193
# File 'lib/ui.rb', line 190

def stop
  nocbreak
  close_screen
end