dbtop 0.0.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (6) hide show
  1. data/.gitignore +1 -0
  2. data/bin/dbtop +170 -22
  3. data/dbtop-0.0.0.gem +0 -0
  4. data/dbtop.gemspec +35 -0
  5. data/version.txt +1 -1
  6. metadata +7 -4
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ pkg/*
data/bin/dbtop CHANGED
@@ -11,7 +11,11 @@
11
11
  # ------------------------------------------------------------------------------
12
12
  # filename: dbtop.rb
13
13
  # author: alfred.moreno@zumba.com
14
- # purpose: Process monitor for MySQL Databases; ignores 'Sleep' processes.
14
+ #
15
+ # TODO: Add scrolling to the process window.
16
+ #
17
+ # TODO: VIM style navigation for the processlist. (5j, 5k) 5up, 5down
18
+ #
15
19
  # ------------------------------------------------------------------------------
16
20
  require 'curses'
17
21
  require 'terminal-table'
@@ -27,15 +31,40 @@ class MysqlTop
27
31
  #############################################################################
28
32
  def initialize(options)
29
33
 
34
+ Curses.noecho # Don't echo characters to the screen.
35
+
30
36
  @user = options[:user] || ENV['MYSQL_USER']
31
37
  @pass = options[:pass] || ENV['MYSQL_PASSWORD']
32
38
  @host = options[:host] || ENV['MYSQL_HOST']
33
39
  @db = options[:db] || ENV['MYSQL_DATABASE']
34
40
  @port = 3306 || ENV['MYSQL_PORT']
35
41
  @interval = options[:interval] || 5
42
+
43
+ @page_tracker = {
44
+ top_row: 4,
45
+ bottom_row: Curses.lines - 1,
46
+ current_page: 1,
47
+ total_pages: 0
48
+ }
49
+
50
+ @process_list = {
51
+ x: 3,
52
+ y: 0
53
+ }
54
+
55
+ @current_pos = {
56
+ x: 0,
57
+ y: 0
58
+ }
59
+
60
+ @state = 'FREE'
61
+ @show_sleep = false
62
+ @freeze_screen = nil
63
+
36
64
  validate
37
65
 
38
- tbl = Terminal::Table.new headings: [
66
+ @tbl = Terminal::Table.new headings: [
67
+ 'PID',
39
68
  'Time',
40
69
  'User',
41
70
  'Host',
@@ -48,32 +77,137 @@ class MysqlTop
48
77
  Curses.timeout=0
49
78
  loop do
50
79
 
80
+ # Listen for key input..
51
81
  case getch
52
82
  when 'q'
53
83
  exit
54
- end
84
+ # Line Feed (Code 10)
85
+ when 10
86
+ exit
87
+ when 'S'
88
+ @show_sleep = !@show_sleep
89
+ when 'K'
90
+ @state = "KILL_MODE"
91
+ @freeze_screen = @tbl.clone unless (@freeze_screen == @tbl) || @tbl.rows.count == 0
92
+ Curses.setpos(@process_list[:x],0)
93
+ nav_key = 0
94
+ while nav_key != 10
95
+ break if nav_key == 27
96
+ # Position tracker for navigating the list
97
+ process_list_nav = {x: 0, y: 0}
98
+
99
+ # Draw the frozen process table
100
+ @freeze_screen.to_s.each_line do |line|
101
+
102
+ break if process_list_nav[:x] == Curses.lines - 1
103
+ Curses.setpos(process_list_nav[:x],process_list_nav[:y])
104
+
105
+ # While drawing the frozen table, we check our process_list_nav
106
+ # position against the position we're controlling via @process_list.
107
+ #
108
+ # If the current row we're drawing is the row we've incremented or
109
+ # decremented to, it's the current selected row -- hilight it!
110
+ #
111
+ if process_list_nav[:x] == @process_list[:x]
112
+ Curses.start_color
113
+ Curses.init_pair(COLOR_RED,COLOR_RED,COLOR_WHITE)
114
+ Curses.attron(color_pair(COLOR_RED)|A_UNDERLINE) {
115
+ Curses.addstr(line)
116
+ }
117
+ Curses.attrset(A_NORMAL)
118
+ else
119
+ Curses.addstr(line)
120
+ end
121
+
122
+ process_list_nav[:x] += 1
123
+ end
55
124
 
56
- %x[mysql -A -u #@user -p#@pass -h #@host #@db -e "show processlist"].lines.each do |line|
57
- next if line.include?('Sleep')
125
+ # Poll for key input (j,k) that we'll use to navigate the
126
+ # list of processes in the DB process table.
127
+ #
128
+ nav_key = getch
58
129
 
59
- line = line.split(' ')
130
+ # Logic should follow the drawn table (i.e. dimensions of
131
+ # navigable content are: (4 => lines.count-2)
132
+ #
133
+ if @process_list[:x] > 3 && nav_key.eql?('k')
60
134
 
61
- row = {
62
- id: line[0],
63
- user: line[1],
64
- host: line[2],
65
- db: line[3],
66
- cmd: line[4],
67
- time: line[5],
68
- state: line[6],
69
- info: line[7]
135
+ # Going up!
136
+ @process_list[:x] -= 1
137
+ elsif nav_key.eql?('j') && @process_list[:x] < (@freeze_screen.to_s.lines.count-2)
138
+
139
+ # Going down!
140
+ @process_list[:x] += 1
141
+ end
142
+
143
+ Curses.setpos(@process_list[:x],0)
144
+ end
145
+ kill_pid = @freeze_screen.rows[@process_list[:x]-3][0]
146
+ Thread.new {
147
+ %x[mysql -A -u #@user -p#@pass -h #@host #@db -e "KILL #{kill_pid}"]
70
148
  }
71
- tbl << [line[5], line[1], line[2], line[3], line[6], line[4]]
149
+ write(0,0,@freeze_screen.to_s)
150
+ @state = "FREE"
151
+ when '?'
152
+ @state = "HELP"
153
+ @freeze_screen = @tbl.clone unless (@freeze_screen == @tbl) || @tbl.rows.count == 0
154
+
155
+ Curses.clear
156
+ help_xy = {x: 0, y: 0}
157
+ Curses.setpos(0,0)
158
+ Curses.attrset(A_UNDERLINE)
159
+ Curses.start_color
160
+ Curses.init_pair(COLOR_GREEN,COLOR_RED,COLOR_BLACK)
161
+ Curses.attron(color_pair(COLOR_GREEN)|A_UNDERLINE) {
162
+ Curses.addstr("State\tCommand\t\tDescription\n")
163
+ }
164
+ Curses.attrset(A_NORMAL)
165
+
166
+ help_cmds = [
167
+ "\tS\t\tInclude 'Sleep' processes\n",
168
+ "\tp\t\tPause the process monitor\n",
169
+ "\tk\t\tEnter kill mode -- navigate to kill a process\n"
170
+ ]
171
+ help_cmds.each do |help_cmd|
172
+ help_xy[:x] += 1
173
+ Curses.addstr(help_cmd)
174
+ end
175
+
176
+ Curses.setpos(Curses.lines-1,0)
177
+ Curses.addstr("Press any key to continue...")
178
+
179
+ while !getch
180
+
181
+ end
182
+ write(0,0,@freeze_screen.to_s)
183
+ @state = 'FREE'
72
184
  end
73
185
 
74
- write(0,0,tbl.to_s)
75
- tbl.rows = tbl.rows.clear
186
+ # Connect to the MySQL DB and retrieve the process list
187
+ # This will change soon as I add support for other DB's
188
+ #
189
+ Thread.new {
190
+ %x[mysql -A -u #@user -p#@pass -h #@host #@db -e "show processlist"].lines.each_with_index do |line,index|
191
+ next if line.include?('Sleep') && !@show_sleep || !@state.eql?('FREE') || index == 0
192
+
193
+ line = line.split(' ')
194
+
195
+ row = {
196
+ id: line[0],
197
+ user: line[1],
198
+ host: line[2],
199
+ db: line[3],
200
+ cmd: line[4],
201
+ time: line[5],
202
+ state: line[6],
203
+ info: line[7]
204
+ }
205
+ @tbl << [line[0], line[5], line[1], line[2], line[3], line[6], line[4]]
206
+ end
207
+ write(0,0,@tbl.to_s) if @tbl.rows.count > 0
76
208
  sleep @interval
209
+ @tbl.rows = @tbl.rows.clear
210
+ } unless Thread.list.size > 1 || !@state.eql?('FREE')
77
211
 
78
212
  end
79
213
  ensure
@@ -95,7 +229,7 @@ class MysqlTop
95
229
 
96
230
  #############################################################################
97
231
  # Public: Initializes the screen buffer with specified options.
98
- #
232
+ #
99
233
  # Returns: nothing
100
234
  #############################################################################
101
235
  def init_screen
@@ -122,13 +256,27 @@ class MysqlTop
122
256
  #############################################################################
123
257
  def write(x,y,text)
124
258
  Curses.setpos(x,y)
125
- Curses.addstr(text)
259
+ text.each_line do |line|
260
+ break if x == Curses.lines-1
261
+ Curses.addstr(line)
262
+ x += 1
263
+ end
126
264
  for x in 1..Curses.lines
127
265
  Curses.deleteln
128
266
  end
129
267
  Curses.setpos(text.lines.count-1,0)
130
- Curses.addstr(text.lines.take(3)[2])
131
- Curses.refresh
268
+ Curses.addstr(text.lines.take(3)[2]) unless text.lines.take(3)[2].nil?
269
+ Curses.setpos(text.lines.count-1,0)
270
+ end
271
+
272
+ def page(nav,text)
273
+ if @tbl.rows.count > Curses.lines
274
+
275
+ end
276
+ Curses.setpos(0,0)
277
+ for x in 0..3
278
+ Curses.addstr
279
+ end
132
280
  end
133
281
 
134
282
  end
data/dbtop-0.0.0.gem ADDED
Binary file
data/dbtop.gemspec ADDED
@@ -0,0 +1,35 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{dbtop}
5
+ s.version = "0.1.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = [%q{Alfred Moreno}]
9
+ s.date = %q{2012-06-02}
10
+ s.description = %q{Similar to the Unix 'top' tool, this Ruby gem will provide process
11
+ monitoring for your MySQL database instance.}
12
+ s.email = %q{kryptek@kryptek.org}
13
+ s.executables = [%q{dbtop}]
14
+ s.extra_rdoc_files = [%q{History.txt}, %q{bin/dbtop}]
15
+ s.files = [%q{.bnsignore}, %q{.gitignore}, %q{Gemfile}, %q{Gemfile.lock}, %q{History.txt}, %q{README.md}, %q{Rakefile}, %q{bin/dbtop}, %q{dbtop-0.0.0.gem}, %q{dbtop.gemspec}, %q{lib/dbtop.rb}, %q{spec/dbtop_spec.rb}, %q{spec/spec_helper.rb}, %q{test/test_dbtop.rb}, %q{version.txt}]
16
+ s.homepage = %q{http://github.com/kryptek}
17
+ s.rdoc_options = [%q{--main}, %q{README.md}]
18
+ s.require_paths = [%q{lib}]
19
+ s.rubyforge_project = %q{dbtop}
20
+ s.rubygems_version = %q{1.8.6}
21
+ s.summary = %q{Similar to the Unix 'top' tool, this Ruby gem will provide process monitoring for your MySQL database instance.}
22
+ s.test_files = [%q{test/test_dbtop.rb}]
23
+
24
+ if s.respond_to? :specification_version then
25
+ s.specification_version = 3
26
+
27
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
28
+ s.add_development_dependency(%q<bones>, [">= 3.8.0"])
29
+ else
30
+ s.add_dependency(%q<bones>, [">= 3.8.0"])
31
+ end
32
+ else
33
+ s.add_dependency(%q<bones>, [">= 3.8.0"])
34
+ end
35
+ end
data/version.txt CHANGED
@@ -1 +1 @@
1
- 0.0.0
1
+ 0.1.0
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dbtop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-24 00:00:00.000000000Z
12
+ date: 2012-06-02 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bones
16
- requirement: &70169320893340 !ruby/object:Gem::Requirement
16
+ requirement: &70339907623660 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: 3.8.0
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70169320893340
24
+ version_requirements: *70339907623660
25
25
  description: ! 'Similar to the Unix ''top'' tool, this Ruby gem will provide process
26
26
 
27
27
  monitoring for your MySQL database instance.'
@@ -34,12 +34,15 @@ extra_rdoc_files:
34
34
  - bin/dbtop
35
35
  files:
36
36
  - .bnsignore
37
+ - .gitignore
37
38
  - Gemfile
38
39
  - Gemfile.lock
39
40
  - History.txt
40
41
  - README.md
41
42
  - Rakefile
42
43
  - bin/dbtop
44
+ - dbtop-0.0.0.gem
45
+ - dbtop.gemspec
43
46
  - lib/dbtop.rb
44
47
  - spec/dbtop_spec.rb
45
48
  - spec/spec_helper.rb