json-monitor 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +10 -0
- data/TODO +7 -0
- data/bin/json_tail +55 -0
- data/lib/json_tail.rb +57 -0
- data/lib/json_tail/config.rb +12 -0
- data/lib/json_tail/couchdb.rb +50 -0
- data/lib/json_tail/engine.rb +21 -0
- data/lib/json_tail/ext/class.rb +11 -0
- data/lib/json_tail/ext/string.rb +7 -0
- data/lib/json_tail/parser.rb +22 -0
- data/lib/json_tail/parsers/disk_usage.rb +18 -0
- data/lib/json_tail/parsers/memory_usage.rb +24 -0
- data/lib/json_tail/parsers/mysql-statistics.rb +58 -0
- data/lib/json_tail/parsers/suipit_app.rb +34 -0
- data/lib/json_tail/service.rb +17 -0
- metadata +70 -0
data/README
ADDED
data/TODO
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
- agregar excepciones para casi todo. servicios, couchdb, etc.
|
2
|
+
- validaciones, validaciones, validaciones
|
3
|
+
- agregar mas parsers
|
4
|
+
** test all the fucking time
|
5
|
+
- ver cambio a couchrest
|
6
|
+
- ver el parser de suipit_app la consulta en especifico
|
7
|
+
- mejorar manejo de threads cuando se cierre json_tail abruptamente
|
data/bin/json_tail
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.dirname(__FILE__) + '/../lib/json_tail.rb'
|
4
|
+
|
5
|
+
options = {}
|
6
|
+
|
7
|
+
optparse = OptionParser.new do |opts|
|
8
|
+
# Set a banner, displayed at the top
|
9
|
+
# of the help screen.
|
10
|
+
opts.banner = "Usage: json_tail [config-file]"
|
11
|
+
|
12
|
+
opts.on("-h", "--help", "Display this screen") do
|
13
|
+
puts opts
|
14
|
+
exit
|
15
|
+
end
|
16
|
+
|
17
|
+
opts.on("-v", "--version", "Display version information") do
|
18
|
+
puts "json_tail " + JsonTail::VERSION + " by Metrik <info@metrik.cl> - http://www.metrik.cl"
|
19
|
+
exit
|
20
|
+
end
|
21
|
+
|
22
|
+
opts.on("-p", "--parsers", "List available parsers") do
|
23
|
+
puts "Supported Parsers [" + JsonTail::Parser::registry.keys.sort { |a,b| a.to_s <=> b.to_s }.collect { |p| ":#{p.to_s}" }.join(", ") + "]"
|
24
|
+
exit
|
25
|
+
end
|
26
|
+
|
27
|
+
opts.on("-n", "--new", "Initialize config specified with default options") do
|
28
|
+
puts "Not implemented yet. Sorry."
|
29
|
+
exit
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
begin
|
35
|
+
optparse.parse!(ARGV)
|
36
|
+
rescue OptionParser::ParseError => e
|
37
|
+
puts e
|
38
|
+
exit
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
file_json_tail = File.dirname(__FILE__) + '/../etc/services.yml'
|
43
|
+
file_couchdb = File.dirname(__FILE__) + '/../etc/couchdb.yml'
|
44
|
+
|
45
|
+
couchdb_config = JsonTail::Config.parse_yml(file_couchdb, 'couchdb')
|
46
|
+
|
47
|
+
@@couchdb_server = JsonTail::CouchServer.new(couchdb_config['host'], couchdb_config['port'], couchdb_config['database'],
|
48
|
+
couchdb_config['username'], couchdb_config['password'])
|
49
|
+
|
50
|
+
config = JsonTail::Config.parse_yml(file_json_tail, 'services')
|
51
|
+
|
52
|
+
engine = JsonTail::Engine.new(config)
|
53
|
+
|
54
|
+
engine.start
|
55
|
+
|
data/lib/json_tail.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# json_tail.rb - service monitoring - JSON and CouchDB
|
2
|
+
# Copyright 2009 Metrik <info@metrik.cl>
|
3
|
+
#
|
4
|
+
# Licensed under the General Public License v2 (see LICENSE)
|
5
|
+
|
6
|
+
module JsonTail
|
7
|
+
VERSION = '0.1.0'
|
8
|
+
end
|
9
|
+
|
10
|
+
begin
|
11
|
+
require 'rubygems'
|
12
|
+
rescue LoadError
|
13
|
+
puts "Missing gem rubygems. Note: please install from rubyforge."
|
14
|
+
exit
|
15
|
+
end
|
16
|
+
|
17
|
+
begin
|
18
|
+
require 'net/ssh'
|
19
|
+
rescue LoadError
|
20
|
+
puts "Missing gem net-ssh. Note: sudo gem install net-ssh"
|
21
|
+
exit
|
22
|
+
end
|
23
|
+
|
24
|
+
begin
|
25
|
+
require 'mysql'
|
26
|
+
rescue LoadError
|
27
|
+
puts "Missing gem mysql. Note: sudo gem install mysql"
|
28
|
+
exit
|
29
|
+
end
|
30
|
+
|
31
|
+
begin
|
32
|
+
require 'daemons'
|
33
|
+
rescue LoadError
|
34
|
+
puts "Missing gem daemons. Note: sudo gem install daemons"
|
35
|
+
exit
|
36
|
+
end
|
37
|
+
|
38
|
+
begin
|
39
|
+
require 'json'
|
40
|
+
rescue LoadError
|
41
|
+
puts "Missing gem json. Note: sudo gem install json"
|
42
|
+
exit
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
# loading extensions
|
47
|
+
|
48
|
+
Dir.glob(File.dirname(__FILE__) + "/../lib/json_tail/ext/*").each { |lib| require lib }
|
49
|
+
|
50
|
+
# loading libraries
|
51
|
+
|
52
|
+
libraries = ["config", "couchdb", "engine", "parser", "service"]
|
53
|
+
libraries.each { |lib| require File.dirname(__FILE__) + "/../lib/json_tail/#{lib}" }
|
54
|
+
|
55
|
+
Dir.glob(File.dirname(__FILE__) + "/../lib/json_tail/parsers/*").each { |lib| require lib }
|
56
|
+
|
57
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module JsonTail
|
4
|
+
class CouchServer
|
5
|
+
attr_reader :database
|
6
|
+
|
7
|
+
def initialize(host, port, database, username, password)
|
8
|
+
@host = host
|
9
|
+
@port = port
|
10
|
+
@database = database
|
11
|
+
@username = username
|
12
|
+
@password = password
|
13
|
+
end
|
14
|
+
|
15
|
+
def delete(uri)
|
16
|
+
send_request(Net::HTTP::Delete.new(uri))
|
17
|
+
end
|
18
|
+
|
19
|
+
def get(uri)
|
20
|
+
send_request(Net::HTTP::Get.new(uri))
|
21
|
+
end
|
22
|
+
|
23
|
+
def put(uri, json)
|
24
|
+
req = Net::HTTP::Put.new(uri)
|
25
|
+
req["content-type"] = "application/json"
|
26
|
+
req.body = json
|
27
|
+
send_request(req)
|
28
|
+
end
|
29
|
+
|
30
|
+
def post(uri, json)
|
31
|
+
req = Net::HTTP::Post.new(uri)
|
32
|
+
req["content-type"] = "application/json"
|
33
|
+
req.body = json
|
34
|
+
send_request(req)
|
35
|
+
end
|
36
|
+
|
37
|
+
def send_request(req)
|
38
|
+
begin
|
39
|
+
res = Net::HTTP.start(@host, @port) do |http|
|
40
|
+
req.basic_auth @username, @password
|
41
|
+
http.request(req)
|
42
|
+
end
|
43
|
+
rescue Errno::ECONNREFUSED => e
|
44
|
+
puts "couchdb: " + e
|
45
|
+
exit
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module JsonTail
|
2
|
+
class Engine
|
3
|
+
attr_reader :services
|
4
|
+
|
5
|
+
def initialize(config)
|
6
|
+
@services = []
|
7
|
+
config.each do |service|
|
8
|
+
@services << JsonTail::Service.new(service.shift, service.shift)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def start
|
13
|
+
thr = []
|
14
|
+
@services.each do |service|
|
15
|
+
thr << Thread.new { service.start }
|
16
|
+
end
|
17
|
+
thr.each { |t| t.join }
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# http://stackoverflow.com/questions/436159/how-to-get-all-subclasses
|
2
|
+
# thanks to Jorg W Mittag
|
3
|
+
# http://stackoverflow.com/users/2988/jorg-w-mittag
|
4
|
+
|
5
|
+
class Class
|
6
|
+
def subclasses
|
7
|
+
result = []
|
8
|
+
ObjectSpace.each_object(Class) { |klass| result << klass if klass < self }
|
9
|
+
result
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module JsonTail
|
2
|
+
class Parser
|
3
|
+
class << self
|
4
|
+
|
5
|
+
def report(parser, content = {})
|
6
|
+
@@couchdb_server.post(@@couchdb_server.database, JSON.generate({ "hostname" => `hostname`.chomp, "parser" => parser,
|
7
|
+
"timestamp" => Time.now.strftime("%Y-%m-%d %H:%M:%S"), "content" => content }))
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def self::inherited(klass)
|
12
|
+
parser_name = klass.to_s.underscore
|
13
|
+
@registry ||= {}
|
14
|
+
@registry[ parser_name ] = klass
|
15
|
+
end
|
16
|
+
|
17
|
+
def self::registry
|
18
|
+
@registry
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# cada parser debiera tener un método parse() y
|
2
|
+
# otro build_report() que devuelva un objecto de clase Hash
|
3
|
+
# para que sea transformado a JSON después.
|
4
|
+
|
5
|
+
class DiskUsage < JsonTail::Parser
|
6
|
+
|
7
|
+
class << self
|
8
|
+
|
9
|
+
def build_report(options)
|
10
|
+
content = {}
|
11
|
+
dfh = "df | grep #{options['filesystem']}"
|
12
|
+
res_dfh = `#{dfh}`.split
|
13
|
+
content = { "disk_size" => res_dfh[1], "used" => res_dfh[2], "available" => res_dfh[3], "percentage_used" => res_dfh[4] }
|
14
|
+
|
15
|
+
report(options['parser'], content)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# cada parser debiera tener un método parse() y
|
2
|
+
# otro build_report() que devuelva un objecto de clase Hash
|
3
|
+
# para que sea transformado a JSON después.
|
4
|
+
|
5
|
+
class MemoryUsage < JsonTail::Parser
|
6
|
+
|
7
|
+
class << self
|
8
|
+
|
9
|
+
def build_report(options)
|
10
|
+
content = {}
|
11
|
+
total_mem = `free | grep Mem: | awk '{print $2}'`.chomp
|
12
|
+
total_mem_used = `free | grep buffers/cache: | awk '{print $3}'`.chomp
|
13
|
+
total_mem_avai = `free | grep Mem: | awk '{print $4}'`.chomp
|
14
|
+
res_swap_info = `free | grep Swap:`.split
|
15
|
+
total_swap = res_swap_info[1]
|
16
|
+
per_swap_used = (res_swap_info[2].to_i*100)/total_swap.to_i # percentage
|
17
|
+
per_swap_avai = (res_swap_info[3].to_i*100)/total_swap.to_i # percentage
|
18
|
+
content = { "total_mem" => total_mem, "total_mem_used" => total_mem_used, "total_mem_avai" => total_mem_avai, "total_swap" => total_swap,
|
19
|
+
"total_swap_used" => total_swap_used, "total_swap_avai" => total_swap_avai }
|
20
|
+
|
21
|
+
report(options['parser'], content)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# cada parser debiera tener un método parse() y
|
2
|
+
# otro build_report() que devuelva un objecto de clase Hash
|
3
|
+
# para que sea transformado a JSON después.
|
4
|
+
|
5
|
+
require 'file/tail'
|
6
|
+
|
7
|
+
class MysqlStatistics < JsonTail::Parser
|
8
|
+
attr_accessor :com_select, :com_insert, :com_delete, :com_update
|
9
|
+
ENTRIES = ["SELECT", "INSERT", "DELETE", "UPDATE"]
|
10
|
+
|
11
|
+
def initialize(filename)
|
12
|
+
@filename = filename
|
13
|
+
@com_select = 0
|
14
|
+
@com_insert = 0
|
15
|
+
@com_delete = 0
|
16
|
+
@com_update = 0
|
17
|
+
end
|
18
|
+
|
19
|
+
def start
|
20
|
+
File.open(@filename) do |log|
|
21
|
+
log.extend(File::Tail)
|
22
|
+
log.interval = 10
|
23
|
+
log.tail do |line|
|
24
|
+
ENTRIES.each do |e|
|
25
|
+
if line.include? e
|
26
|
+
case e
|
27
|
+
when "SELECT"
|
28
|
+
@com_select += 1
|
29
|
+
when "INSERT"
|
30
|
+
@com_insert += 1
|
31
|
+
when "DELETE"
|
32
|
+
@com_delete += 1
|
33
|
+
when "UPDATE"
|
34
|
+
@com_update += 1
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def reset
|
43
|
+
@com_select = 0
|
44
|
+
@com_insert = 0
|
45
|
+
@com_delete = 0
|
46
|
+
@com_update = 0
|
47
|
+
end
|
48
|
+
|
49
|
+
class << self
|
50
|
+
|
51
|
+
def build_report(options)
|
52
|
+
mm = self.new(options['filename'])
|
53
|
+
content = { "com_select" => mm.com_select, "com_insert" => mm.com_insert, "com_delete" => mm.com_delete, "com_update" => mm.com_update }
|
54
|
+
report(options['parser'], content)
|
55
|
+
mm.start
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# cada parser debiera tener un método parse() y
|
2
|
+
# otro build_report() que devuelva un objecto de clase Hash
|
3
|
+
# para que sea transformado a JSON después.
|
4
|
+
|
5
|
+
require 'mysql'
|
6
|
+
|
7
|
+
class SuipitApp < JsonTail::Parser
|
8
|
+
|
9
|
+
class << self
|
10
|
+
|
11
|
+
def build_report(options)
|
12
|
+
previous_datetime = (Time.now.utc - options['delay']).strftime("%Y-%m-%d %H:%M:%S")
|
13
|
+
conn = Mysql.connect(options['host'], options['username'], options['password'], options['database'])
|
14
|
+
|
15
|
+
loop do
|
16
|
+
content = {}
|
17
|
+
current_datetime = Time.now.utc.strftime("%Y-%m-%d %H:%M:%S")
|
18
|
+
# mmm
|
19
|
+
query = %{SELECT (SELECT count(id) FROM mensajes WHERE created_at BETWEEN '#{previous_datetime}' AND '#{current_datetime}') as mensajes,
|
20
|
+
(SELECT count(id) FROM comentarios WHERE created_at BETWEEN '#{previous_datetime}' AND '#{current_datetime}') as comentarios,
|
21
|
+
(SELECT count(id) FROM archivos WHERE created_at BETWEEN '#{previous_datetime}' AND '#{current_datetime}') as archivos}
|
22
|
+
result = conn.query(query)
|
23
|
+
result.each do |row|
|
24
|
+
content = { "mensajes" => row[0], "comentarios" => row[1], "archivos" => row[2] }
|
25
|
+
end
|
26
|
+
|
27
|
+
report(options['parser'], content)
|
28
|
+
previous_datetime = current_datetime
|
29
|
+
sleep(options['interval'])
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module JsonTail
|
2
|
+
class Service
|
3
|
+
attr_reader :name, :options
|
4
|
+
|
5
|
+
def initialize(name, options = {})
|
6
|
+
@name = name
|
7
|
+
@options = options
|
8
|
+
end
|
9
|
+
|
10
|
+
def start
|
11
|
+
loop do
|
12
|
+
JsonTail::Parser::registry[@options['parser']].build_report(@options)
|
13
|
+
sleep(@options['interval'])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: json-monitor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- "Luis Mancilla \xC3\x81vila"
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-12-28 00:00:00 -03:00
|
13
|
+
default_executable: json_tail
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: youremail@example.com
|
18
|
+
executables:
|
19
|
+
- json_tail
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README
|
24
|
+
files:
|
25
|
+
- README
|
26
|
+
- TODO
|
27
|
+
- bin/json_tail
|
28
|
+
- lib/json_tail/parser.rb
|
29
|
+
- lib/json_tail/parsers/suipit_app.rb
|
30
|
+
- lib/json_tail/parsers/memory_usage.rb
|
31
|
+
- lib/json_tail/parsers/mysql-statistics.rb
|
32
|
+
- lib/json_tail/parsers/disk_usage.rb
|
33
|
+
- lib/json_tail/ext/class.rb
|
34
|
+
- lib/json_tail/ext/string.rb
|
35
|
+
- lib/json_tail/engine.rb
|
36
|
+
- lib/json_tail/config.rb
|
37
|
+
- lib/json_tail/couchdb.rb
|
38
|
+
- lib/json_tail/service.rb
|
39
|
+
- lib/json_tail.rb
|
40
|
+
has_rdoc: true
|
41
|
+
homepage: http://metrik.cl
|
42
|
+
licenses: []
|
43
|
+
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options:
|
46
|
+
- --main
|
47
|
+
- README
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: "0"
|
55
|
+
version:
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: "0"
|
61
|
+
version:
|
62
|
+
requirements: []
|
63
|
+
|
64
|
+
rubyforge_project: json-monitor
|
65
|
+
rubygems_version: 1.3.5
|
66
|
+
signing_key:
|
67
|
+
specification_version: 3
|
68
|
+
summary: Logs in Json to CouchDB
|
69
|
+
test_files: []
|
70
|
+
|