gltail 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +66 -0
- data/Manifest.txt +40 -0
- data/README +51 -0
- data/README.txt +376 -0
- data/Rakefile +19 -0
- data/TODO +9 -0
- data/bin/gl_tail +109 -0
- data/dist/config.yaml +101 -0
- data/lib/gl_tail.rb +68 -0
- data/lib/gl_tail/activity.rb +145 -0
- data/lib/gl_tail/blob_store.rb +43 -0
- data/lib/gl_tail/block.rb +130 -0
- data/lib/gl_tail/config.rb +187 -0
- data/lib/gl_tail/config/configurable.rb +51 -0
- data/lib/gl_tail/config/yaml_parser.rb +94 -0
- data/lib/gl_tail/element.rb +194 -0
- data/lib/gl_tail/engine.rb +266 -0
- data/lib/gl_tail/font.bin +0 -0
- data/lib/gl_tail/font_store.rb +165 -0
- data/lib/gl_tail/http_helper.rb +58 -0
- data/lib/gl_tail/item.rb +17 -0
- data/lib/gl_tail/parser.rb +46 -0
- data/lib/gl_tail/parsers/apache.rb +56 -0
- data/lib/gl_tail/parsers/iis.rb +47 -0
- data/lib/gl_tail/parsers/mysql.rb +29 -0
- data/lib/gl_tail/parsers/nginx.rb +46 -0
- data/lib/gl_tail/parsers/pix-fwsm.rb +50 -0
- data/lib/gl_tail/parsers/postfix.rb +119 -0
- data/lib/gl_tail/parsers/postgresql.rb +42 -0
- data/lib/gl_tail/parsers/pureftpd.rb +30 -0
- data/lib/gl_tail/parsers/qmail.rb +30 -0
- data/lib/gl_tail/parsers/rails.rb +41 -0
- data/lib/gl_tail/parsers/squid.rb +25 -0
- data/lib/gl_tail/parsers/tshark.rb +25 -0
- data/lib/gl_tail/resolver.rb +69 -0
- data/lib/gl_tail/server.rb +46 -0
- data/lib/gl_tail/sources/base.rb +44 -0
- data/lib/gl_tail/sources/local.rb +12 -0
- data/lib/gl_tail/sources/ssh.rb +112 -0
- data/test/test_gl_tail.rb +0 -0
- metadata +114 -0
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
require './lib/gl_tail.rb'
|
6
|
+
|
7
|
+
Hoe.new('gltail', GlTail::VERSION) do |p|
|
8
|
+
p.rubyforge_name = 'gltail'
|
9
|
+
p.author = 'Erlend Simonsen'
|
10
|
+
p.email = 'mr@fudgie.org'
|
11
|
+
p.summary = 'View real-time data and statistics from any logfile on any server with SSH, in an intuitive and entertaining way.'
|
12
|
+
p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
|
13
|
+
p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
|
14
|
+
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
15
|
+
p.extra_deps << ['ruby-opengl', '>= 0.40.1']
|
16
|
+
p.extra_deps << ['net-ssh', '>= 1.1.2']
|
17
|
+
end
|
18
|
+
|
19
|
+
# vim: syntax=Ruby
|
data/TODO
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
Allow more indicators (pulsing color/size, cubes, teapots, etc)
|
2
|
+
Clickable links
|
3
|
+
Drag 'n drop organizing
|
4
|
+
Hide/show blocks with keypresses
|
5
|
+
Limit display to specific host
|
6
|
+
Geolocation on IPS
|
7
|
+
Show only percentage of blobs to handle high-traffic sites
|
8
|
+
Multi-line parsing (MySQL slow-log)
|
9
|
+
Multiple activity providers (local tail, ssh, Splunk)
|
data/bin/gl_tail
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# gl_tail.rb - OpenGL visualization of your server traffic
|
3
|
+
# Copyright 2007 Erlend Simonsen <mr@fudgie.org>
|
4
|
+
#
|
5
|
+
# Licensed under the GNU General Public License v2 (see LICENSE)
|
6
|
+
|
7
|
+
$DBG=0
|
8
|
+
$VRB=1
|
9
|
+
|
10
|
+
file = 'gl_tail.yaml'
|
11
|
+
|
12
|
+
ARGV.each do |arg|
|
13
|
+
case arg
|
14
|
+
when '-help','--help','-h'
|
15
|
+
puts "gl_tail [--help|-h] [--parsers|-p] [--verbose|-v] [--debug|-d] [--debug-ssh|-ds] [configfile]",
|
16
|
+
'[--help|-h] This help screen',
|
17
|
+
'[--version] Print version information',
|
18
|
+
'[--new|-n] Initialize config specified with default options',
|
19
|
+
'[--parsers|-p] List available parsers',
|
20
|
+
'[--options|-o] List available configuration options',
|
21
|
+
'[--quiet|-q] Turn off runtime information',
|
22
|
+
'[--debug|-d] Turn on debugging',
|
23
|
+
'[--debug-ssh|-ds] Only debug SSH',
|
24
|
+
'[configfile] The YAML config file you wish to load (default = config.yaml)'
|
25
|
+
exit
|
26
|
+
when '-version', '--version'
|
27
|
+
@print = :version
|
28
|
+
when '-new', '--new', '-n'
|
29
|
+
@init_config = true
|
30
|
+
when '-parsers','--parsers', '-p'
|
31
|
+
@print = :parsers
|
32
|
+
when '-debug', '--debug', '-d'
|
33
|
+
$DBG=1
|
34
|
+
when '-quiet', '--quiet', '-q'
|
35
|
+
$VRB=0
|
36
|
+
when '-debug-ssh', '--debug-ssh', '-ds'
|
37
|
+
$DBG=2
|
38
|
+
when '--options', '-o'
|
39
|
+
@print = :options
|
40
|
+
else
|
41
|
+
if(File.exist?(arg) && File.file?(arg))
|
42
|
+
file = arg
|
43
|
+
else
|
44
|
+
if defined? @init_config
|
45
|
+
file = arg
|
46
|
+
else
|
47
|
+
file = "#{arg}.yaml"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
if defined? @init_config
|
54
|
+
require 'ftools'
|
55
|
+
|
56
|
+
if File.directory? file
|
57
|
+
puts "'#{file}' is a directory, not overwriting."
|
58
|
+
exit
|
59
|
+
end
|
60
|
+
|
61
|
+
if File.exist? file
|
62
|
+
File.move(file, file + ".bak")
|
63
|
+
puts "Existing configuration moved to '#{file + '.bak'}'"
|
64
|
+
end
|
65
|
+
|
66
|
+
File.copy(File.dirname(__FILE__) + '/../dist/config.yaml', file)
|
67
|
+
puts "Example configuration installed in '#{file}'"
|
68
|
+
puts "Please edit it and change server and login information."
|
69
|
+
exit
|
70
|
+
elsif !File.exist?(file)
|
71
|
+
puts "Configuration file not found. Either supply the path to a config file as an argument to gl_tail,",
|
72
|
+
"or create a new one with:",
|
73
|
+
" gl_tail --new #{file}"
|
74
|
+
exit
|
75
|
+
end
|
76
|
+
|
77
|
+
require File.dirname(__FILE__) + '/../lib/gl_tail.rb'
|
78
|
+
|
79
|
+
if defined? @print
|
80
|
+
case @print
|
81
|
+
when :parsers
|
82
|
+
puts "Supported Parsers [" + Parser::registry.keys.sort { |a,b| a.to_s <=> b.to_s }.collect{ |p| ":#{p.to_s}"}.join(", ") + "]"
|
83
|
+
when :options
|
84
|
+
require 'pp'
|
85
|
+
puts "Supported Configuration Options"
|
86
|
+
|
87
|
+
pp(GlTail::CONFIG_OPTIONS)
|
88
|
+
when :version
|
89
|
+
puts "gl_tail v" + GlTail::VERSION + " by Erlend Simonsen <mr@fudgie.org> - http://www.fudgie.org"
|
90
|
+
end
|
91
|
+
exit
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
######## TRAP Interrupts and exit cleanly ########
|
96
|
+
|
97
|
+
trap("HUP") { exit }
|
98
|
+
trap("INT") { exit }
|
99
|
+
trap("QUIT") { exit }
|
100
|
+
trap("ABRT") { exit }
|
101
|
+
trap("KILL") { exit }
|
102
|
+
trap("TERM") { exit }
|
103
|
+
#trap("USR1") { $VRB >= 1 ? $VRB = 0 : $VRB += 1; puts "verbose toggled" }
|
104
|
+
trap("USR2") { $DBG >= 2 ? $DBG = 0 : $DBG += 1; puts "debug level toggled" }
|
105
|
+
|
106
|
+
config = GlTail::Config.parse_yaml(file)
|
107
|
+
|
108
|
+
engine = GlTail::Engine.new(config)
|
109
|
+
engine.start
|
data/dist/config.yaml
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
servers:
|
2
|
+
site1:
|
3
|
+
host: foobar.com
|
4
|
+
user: foo
|
5
|
+
password: topsecret
|
6
|
+
command: tail -f -n0
|
7
|
+
files: /var/log/apache/access_log
|
8
|
+
parser: apache
|
9
|
+
color: 0.2, 1.0, 0.2, 1.0
|
10
|
+
rails:
|
11
|
+
host: anotherfunsite.com
|
12
|
+
user: anotherfunuser
|
13
|
+
port: 222
|
14
|
+
command: tail -f -n0
|
15
|
+
files: /var/www/apps/funapp/current/log/production.log
|
16
|
+
parser: rails
|
17
|
+
color: 0.2, 0.2, 1.0, 1.0
|
18
|
+
config:
|
19
|
+
dimensions: 1200x600
|
20
|
+
min_blob_size: 0.004
|
21
|
+
max_blob_size: 0.04
|
22
|
+
highlight_color: orange
|
23
|
+
bounce: false
|
24
|
+
left_column:
|
25
|
+
size: 25
|
26
|
+
alignment: -0.99
|
27
|
+
blocks:
|
28
|
+
info:
|
29
|
+
order: 0
|
30
|
+
size: 10
|
31
|
+
auto_clean: false
|
32
|
+
show: total
|
33
|
+
hosts:
|
34
|
+
order: 1
|
35
|
+
size: 3
|
36
|
+
sites:
|
37
|
+
order: 2
|
38
|
+
size: 10
|
39
|
+
content:
|
40
|
+
order: 3
|
41
|
+
size: 5
|
42
|
+
show: total
|
43
|
+
color: 1.0, 0.8, 0.4, 1.0
|
44
|
+
status:
|
45
|
+
order: 4
|
46
|
+
size: 10
|
47
|
+
color: 1.0, 0.8, 0.4, 1.0
|
48
|
+
types:
|
49
|
+
order: 5
|
50
|
+
size: 5
|
51
|
+
color: 1.0, 0.4, 0.2, 1.0
|
52
|
+
users:
|
53
|
+
order: 6
|
54
|
+
size: 10
|
55
|
+
smtp:
|
56
|
+
order: 7
|
57
|
+
size: 5
|
58
|
+
logins:
|
59
|
+
order: 8
|
60
|
+
size: 5
|
61
|
+
database:
|
62
|
+
order: 9
|
63
|
+
size: 10
|
64
|
+
|
65
|
+
right_column:
|
66
|
+
size: 25
|
67
|
+
alignment: 0.99
|
68
|
+
blocks:
|
69
|
+
urls:
|
70
|
+
order: 0
|
71
|
+
size: 15
|
72
|
+
slow requests:
|
73
|
+
order: 1
|
74
|
+
size: 5
|
75
|
+
show: average
|
76
|
+
referrers:
|
77
|
+
order: 2
|
78
|
+
size: 10
|
79
|
+
user agents:
|
80
|
+
order: 3
|
81
|
+
size: 5
|
82
|
+
color: 1.0, 1.0, 1.0, 1.0
|
83
|
+
mail from:
|
84
|
+
order: 4
|
85
|
+
size: 5
|
86
|
+
mail to:
|
87
|
+
order: 5
|
88
|
+
size: 5
|
89
|
+
viruses:
|
90
|
+
order: 6
|
91
|
+
size: 5
|
92
|
+
rejections:
|
93
|
+
order: 7
|
94
|
+
size: 5
|
95
|
+
color: 1.0, 0.2, 0.2, 1.0
|
96
|
+
warnings:
|
97
|
+
order: 8
|
98
|
+
size: 5
|
99
|
+
resolver:
|
100
|
+
reverse_ip_lookups: true
|
101
|
+
reverse_timeout: 0.5
|
data/lib/gl_tail.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# gl_tail.rb - OpenGL visualization of your server traffic
|
2
|
+
# Copyright 2007 Erlend Simonsen <mr@fudgie.org>
|
3
|
+
#
|
4
|
+
# Licensed under the General Public License v2 (see LICENSE)
|
5
|
+
#
|
6
|
+
|
7
|
+
module GlTail
|
8
|
+
VERSION = '0.0.7'
|
9
|
+
end
|
10
|
+
|
11
|
+
begin
|
12
|
+
require 'rubygems'
|
13
|
+
rescue LoadError
|
14
|
+
puts "Rubygems missing. Please install."
|
15
|
+
puts "Ubuntu:\n sudo apt-get install rubygems"
|
16
|
+
end
|
17
|
+
|
18
|
+
gem_version = Gem::RubyGemsVersion.split('.')
|
19
|
+
|
20
|
+
if gem_version[1].to_i < 9 || (gem_version[1].to_i >= 9 && gem_version[2].to_i < 2)
|
21
|
+
puts "rubygems too old to build ruby-opengl. Please update."
|
22
|
+
puts "Ubuntu:"
|
23
|
+
puts " sudo gem update --system"
|
24
|
+
exit
|
25
|
+
end
|
26
|
+
|
27
|
+
begin
|
28
|
+
gem 'ruby-opengl', '>= 0.40.1'
|
29
|
+
require 'gl'
|
30
|
+
require 'glut'
|
31
|
+
rescue LoadError
|
32
|
+
puts "Missing or outdated gem: ruby-opengl (>=0.40.1)"
|
33
|
+
puts "Ubuntu:"
|
34
|
+
puts " sudo apt-get install rake ruby1.8-dev libgl1-mesa-dev libglu1-mesa-dev libglut3-dev"
|
35
|
+
puts " sudo gem install -y ruby-opengl -r"
|
36
|
+
puts "\nFor more information: http://ruby-opengl.rubyforge.org/build_install.html"
|
37
|
+
exit
|
38
|
+
end
|
39
|
+
|
40
|
+
begin
|
41
|
+
gem 'net-ssh'
|
42
|
+
require 'net/ssh'
|
43
|
+
rescue LoadError
|
44
|
+
puts "Missing gem net-ssh."
|
45
|
+
puts "Ubuntu:"
|
46
|
+
puts " sudo gem install -y net-ssh -r"
|
47
|
+
exit
|
48
|
+
end
|
49
|
+
|
50
|
+
$:.unshift(File.dirname(__FILE__)) # this should be obsolete once its a gem
|
51
|
+
|
52
|
+
# load our libraries
|
53
|
+
require 'gl_tail/engine'
|
54
|
+
require 'gl_tail/config/configurable'
|
55
|
+
require 'gl_tail/config'
|
56
|
+
require 'gl_tail/config/yaml_parser'
|
57
|
+
|
58
|
+
# sources represent event sources defaults to ssh tail
|
59
|
+
# future options: JMS queue, spread.org, local tail, etc
|
60
|
+
require 'gl_tail/sources/base'
|
61
|
+
require 'gl_tail/sources/ssh'
|
62
|
+
|
63
|
+
%w( engine activity block item element parser resolver blob_store font_store).each {|f| require "gl_tail/#{f}" }
|
64
|
+
|
65
|
+
Dir.glob( "#{File.dirname(__FILE__)}/gl_tail/parsers/*.rb" ).each {|f| require f }
|
66
|
+
|
67
|
+
|
68
|
+
|
@@ -0,0 +1,145 @@
|
|
1
|
+
# gl_tail.rb - OpenGL visualization of your server traffic
|
2
|
+
# Copyright 2007 Erlend Simonsen <mr@fudgie.org>
|
3
|
+
#
|
4
|
+
# Licensed under the GNU General Public License v2 (see LICENSE)
|
5
|
+
#
|
6
|
+
|
7
|
+
class Activity
|
8
|
+
attr_accessor :x, :y, :z, :wx, :wy, :wz, :xi, :yi, :zi
|
9
|
+
attr_accessor :message, :color, :size, :type
|
10
|
+
|
11
|
+
def initialize(message, x, y, z, color, size, type = 0)
|
12
|
+
@message = message
|
13
|
+
@x, @y, @z = x, y, z
|
14
|
+
@xi, @yi, @zi = 0.012 + (rand(100)/100.0 ) * 0.0012 , 0.002 + (rand(1000)/1000.0 ) * 0.002, 0
|
15
|
+
# @xi, @yi, @zi = 0.015 , 0.0025, 0
|
16
|
+
|
17
|
+
if @x >= 0.0
|
18
|
+
@xi = -@xi
|
19
|
+
end
|
20
|
+
|
21
|
+
@xi = (rand(100)/100.0 * 0.02) - 0.01 if type == 2
|
22
|
+
|
23
|
+
@color = color
|
24
|
+
@size = size
|
25
|
+
@type = type
|
26
|
+
|
27
|
+
@rx, @ry, @rz = rand(360), rand(360), 0
|
28
|
+
end
|
29
|
+
|
30
|
+
def render(engine)
|
31
|
+
if @type != 5
|
32
|
+
if engine.screen.wanted_fps == 0
|
33
|
+
@x += @xi/2
|
34
|
+
@y += @yi/2
|
35
|
+
@yi = @yi - 0.0005/2
|
36
|
+
else
|
37
|
+
@fps_mod ||= (60.0 / engine.screen.wanted_fps)
|
38
|
+
@x += (@xi/2) * @fps_mod
|
39
|
+
@y += (@yi/2) * @fps_mod
|
40
|
+
@yi = @yi - (0.0005/2) * @fps_mod
|
41
|
+
end
|
42
|
+
|
43
|
+
# @yi = @yi * 1.01
|
44
|
+
# @xi = @xi * 0.9995
|
45
|
+
|
46
|
+
if @y - @size/2 < -engine.screen.top
|
47
|
+
@y = -engine.screen.top + @size/2
|
48
|
+
@yi = -@yi * 0.7
|
49
|
+
@x = 30.0 if(@type == 2 || (engine.screen.bounce.nil? || engine.screen.bounce == false ) )
|
50
|
+
end
|
51
|
+
else
|
52
|
+
dy = @wy - @y
|
53
|
+
if dy.abs < 0.001
|
54
|
+
@y = @wy
|
55
|
+
else
|
56
|
+
@y += dy / 20
|
57
|
+
end
|
58
|
+
|
59
|
+
dx = @wx - @x
|
60
|
+
if dx.abs < 0.001
|
61
|
+
@x = @wx
|
62
|
+
else
|
63
|
+
@x += dx / 20
|
64
|
+
end
|
65
|
+
|
66
|
+
if @x == @wx
|
67
|
+
@x = 20.0
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
glPushMatrix()
|
73
|
+
glColor(@color)
|
74
|
+
|
75
|
+
if @type == 0 || @type == 5
|
76
|
+
glTranslate(@x, @y, @z)
|
77
|
+
if engine.screen.mode == 1
|
78
|
+
glRotatef(@rx, 1.0, 0.0, 0.0)
|
79
|
+
glRotatef(@ry, 0.0, 1.0, 0.0)
|
80
|
+
@rx += 2
|
81
|
+
@ry += 1
|
82
|
+
unless BlobStore.has(@size)
|
83
|
+
list = glGenLists(1)
|
84
|
+
glNewList(list, GL_COMPILE)
|
85
|
+
|
86
|
+
glBegin(GL_QUADS)
|
87
|
+
glVertex3f(-@size, @size, 0)
|
88
|
+
glVertex3f( @size, @size, 0)
|
89
|
+
glVertex3f( @size, -@size, 0)
|
90
|
+
glVertex3f(-@size, -@size, 0)
|
91
|
+
glEnd
|
92
|
+
|
93
|
+
glEndList()
|
94
|
+
BlobStore.put(@size,list)
|
95
|
+
end
|
96
|
+
else
|
97
|
+
unless BlobStore.has(@size)
|
98
|
+
|
99
|
+
list = glGenLists(1)
|
100
|
+
glNewList(list, GL_COMPILE)
|
101
|
+
|
102
|
+
tmp = 10 + 10 * ((@size-engine.screen.min_blob_size)/engine.screen.max_blob_size)
|
103
|
+
if not tmp
|
104
|
+
puts "THIS KEEPS CRASHING FOR ME WITH tmp == NaN -- cant figure out why"
|
105
|
+
tmp = 2
|
106
|
+
end
|
107
|
+
|
108
|
+
glutSolidSphere(@size, tmp, 2)
|
109
|
+
glEndList()
|
110
|
+
BlobStore.put(@size,list)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
glCallList(BlobStore.get(@size))
|
114
|
+
elsif @type == 1
|
115
|
+
glTranslate(@x, @y, @z)
|
116
|
+
glRotatef(@rx, 1.0, 0.0, 0.0)
|
117
|
+
glRotatef(@ry, 0.0, 1.0, 0.0)
|
118
|
+
@rx += 2
|
119
|
+
@ry += 1
|
120
|
+
unless BlobStore.has(@size.to_s)
|
121
|
+
list = glGenLists(1)
|
122
|
+
glNewList(list, GL_COMPILE)
|
123
|
+
|
124
|
+
glBegin(GL_QUADS)
|
125
|
+
glVertex3f(-@size, @size, 0)
|
126
|
+
glVertex3f( @size, @size, 0)
|
127
|
+
glVertex3f( @size, -@size, 0)
|
128
|
+
glVertex3f(-@size, -@size, 0)
|
129
|
+
glEnd
|
130
|
+
|
131
|
+
glEndList()
|
132
|
+
BlobStore.put(@size.to_s,list)
|
133
|
+
end
|
134
|
+
|
135
|
+
glCallList(BlobStore.get(@size.to_s))
|
136
|
+
elsif @type == 2
|
137
|
+
glTranslate(@x, @y, @z)
|
138
|
+
glRasterPos(0.0, 0.0)
|
139
|
+
|
140
|
+
engine.render_string(@message)
|
141
|
+
end
|
142
|
+
|
143
|
+
glPopMatrix()
|
144
|
+
end
|
145
|
+
end
|