loghandler 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in loghandler.gemspec
4
+ gemspec
5
+ gem 'eventmachine'
6
+ gem 'eventmachine-rtail'
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Olivier Gosse-Gardet
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Loghandler
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'loghandler'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install loghandler
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env ruby
2
+ require "rubygems"
3
+
4
+ require "loghandler"
5
+ require "optparse"
6
+ require "pry"
7
+
8
+ def main(args)
9
+
10
+ url = "127.0.0.1"
11
+ port = 9526
12
+ filename = nil
13
+ log_type = nil
14
+ node_name = nil
15
+ uid = nil
16
+
17
+ opts = OptionParser.new do |opt|
18
+ opt.banner = "loghandler client"
19
+ opt.on("-f FILENAME","--filename FILENAME") do |v|
20
+ filename=v
21
+ end
22
+ opt.on("-u URL","--url URL") do |v|
23
+ url=v
24
+ end
25
+ opt.on("-p PORT","--port PORT") do |v|
26
+ port=v
27
+ end
28
+ opt.on("-t LOG_TYPE","--log_type LOG_TYPE") do |v|
29
+ log_type=v
30
+ end
31
+ opt.on("-n NODE_NAME","--node NODE_NAME") do |v|
32
+ node_name=v
33
+ end
34
+ opt.on("--uid ID") do |v|
35
+ uid=v
36
+ end
37
+
38
+
39
+ end
40
+ opts.parse!(args)
41
+ Loghandler::Client.run(url:url,port:port,file:filename,log_type:log_type,node_name:node_name,uid:uid)
42
+ return 0
43
+ end
44
+
45
+
46
+ exit(main(ARGV))
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+ require "rubygems"
3
+
4
+ require "loghandler"
5
+ require "optparse"
6
+ require "pry"
7
+
8
+ def main(args)
9
+ filename = ""
10
+ log_type = ""
11
+
12
+ url = "127.0.0.1"
13
+ port = 9526
14
+
15
+ opts = OptionParser.new do |opt|
16
+ opt.banner = "loghandler server"
17
+ opt.on("-u URL","--url URL") do |v|
18
+ url=v
19
+ end
20
+ opt.on("-p PORT","--port PORT") do |v|
21
+ port=v
22
+ end
23
+ end
24
+ opts.parse!(args)
25
+ Loghandler::Server.run(url:url,port:port)
26
+ return 0
27
+ end
28
+
29
+
30
+ exit(main(ARGV))
@@ -0,0 +1,53 @@
1
+ require 'SecureRandom'
2
+ class Loghandler::Client < EM::Connection
3
+ def initialize(args)
4
+ super
5
+ @options = args
6
+ @reconnect_try = 0
7
+ end
8
+
9
+ def hostname
10
+ Socket.gethostname
11
+ end
12
+
13
+ def local_ip
14
+ orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true # turn off reverse DNS resolution temporarily
15
+
16
+ UDPSocket.open do |s|
17
+ s.connect '64.233.187.99', 1
18
+ s.addr.last
19
+ end
20
+ ensure
21
+ Socket.do_not_reverse_lookup = orig
22
+ end
23
+
24
+ def connection_completed
25
+ @reconnect_try = 0
26
+ end
27
+
28
+ def unbind
29
+ @reconnect_try+=1
30
+ raise "Connection Lost - Max Try Reconnect #{@options[:max_reconnect]}" if @reconnect_try > @options[:max_reconnect]
31
+ EM.add_timer(1) do reconnect @options[:url], @options[:port] end
32
+ end
33
+
34
+ def self.run(options)
35
+ EM.run do
36
+ # EM.error_handler{ |e|
37
+ # puts "Error raised during event loop: #{e.message} "
38
+ # }
39
+ Signal.trap("INT") { EM.stop }
40
+ options.merge!({max_reconnect:10})
41
+ options.merge!({uid:SecureRandom.hex(10)}) if options[:uid].nil?
42
+ channel = EventMachine::Channel.new
43
+
44
+ client = EventMachine.connect options[:url], options[:port], Loghandler::Client, options
45
+ # TODO : move into Loghandler::Client
46
+ channel.subscribe do |data|
47
+ to_send={content:data,logged_at:Time.now}.merge(options)
48
+ client.send_data "#{to_send.to_json}\n"
49
+ end
50
+ Loghandler::Tailer.new(options,channel)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,6 @@
1
+ class Loghandler::LogDetail
2
+ include MongoMapper::Document
3
+ key :content, String
4
+ timestamps!
5
+
6
+ end
@@ -0,0 +1,21 @@
1
+ module Loghandler
2
+ module Rules
3
+ class AbstractRule
4
+ def initialize(log_detail)
5
+ raise "initialize is abstract. Provide an implementation"
6
+ end
7
+ def match?
8
+ raise "match? is abstract. Provide an implementation"
9
+ end
10
+ def apply!
11
+ raise "convert is abstract. Provide an implementation"
12
+ end
13
+ def loggable?
14
+ true
15
+ end
16
+ def persist?
17
+ raise "persist is abstract. Provide an implementation"
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+ module Loghandler
2
+ module Rules
3
+
4
+ class GenericLogRule < AbstractRule
5
+ def initialize(log_detail)
6
+ @log_detail=log_detail
7
+ end
8
+ def match?
9
+ return true if "generic_log" == @log_detail[:log_type]
10
+ # return true if (@log_detail[:content].match(/RTL2/))
11
+ return false
12
+ end
13
+ def apply!
14
+ end
15
+ def log
16
+ @log_detail.to_json
17
+ end
18
+ def loggable?
19
+ true
20
+ end
21
+ def persist?
22
+ false
23
+ end
24
+ def showable?
25
+ true
26
+ end
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,27 @@
1
+ module Loghandler
2
+ module Rules
3
+
4
+ class OnRadioLogRule < AbstractRule
5
+ def initialize(log_detail)
6
+ @log_detail=log_detail
7
+ end
8
+ def match?
9
+ # return true if (filename == "./log/access.log")
10
+ return true if (@log_detail[:content].match(/Nouveau scan de page/))
11
+ return false
12
+ end
13
+ def apply!
14
+ @log_detail.merge!({converted:true})
15
+ end
16
+ def log
17
+ @log_detail.to_json
18
+ end
19
+ def persist?
20
+ false
21
+ end
22
+ def showable?
23
+ true
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,43 @@
1
+ module Loghandler
2
+ module Rules
3
+
4
+ class ThinAccessLogRule < AbstractRule
5
+ def initialize(log_detail)
6
+ @log_detail=log_detail
7
+ end
8
+ def match?
9
+ return true if "thin_access_log"==@log_detail[:log_type]
10
+ # return true if (@log_detail[:content].match(/RTL2/))
11
+ return false
12
+ end
13
+ def apply!
14
+ log_detail = {}
15
+ tmp = CSV.parse(@log_detail[:content],col_sep:" ")
16
+ tmp = tmp[0]
17
+ log_detail[:ip] = tmp[0]
18
+ log_detail[:date] = tmp[3]+tmp[4]
19
+ log_detail[:url]=tmp[5]
20
+ log_detail[:status]=tmp[6]
21
+ log_detail[:length]=tmp[7]
22
+ log_detail[:referer]=tmp[8]
23
+ log_detail[:user_agent]=tmp[9]
24
+ #p [log_detail[:url],log_detail[:status]]
25
+
26
+ @log_detail.merge!(log_detail)
27
+ end
28
+ def log
29
+ @log_detail.to_json
30
+ end
31
+ def loggable?
32
+ true
33
+ end
34
+ def persist?
35
+ false
36
+ end
37
+ def showable?
38
+ true
39
+ end
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,83 @@
1
+ require 'csv'
2
+ class Loghandler::Server < EM::Connection
3
+
4
+ include MongoMapper
5
+
6
+ MongoMapper.connection = Mongo::Connection.new()
7
+ MongoMapper.database = "loghandler"
8
+
9
+ def post_init
10
+ @rules=Loghandler::Rules.constants.select {|c| Class === Loghandler::Rules.const_get(c)}
11
+ @rules.delete(:AbstractRule)
12
+ @tmp_line = []
13
+ end
14
+
15
+ def detect_matching_rules(log_detail)
16
+ matching_rules = []
17
+
18
+ @rules.each do |rule_name|
19
+ rule_class = Loghandler::Rules.const_get(rule_name)
20
+ rule = rule_class.new(log_detail)
21
+ matching_rules << rule if rule.match?
22
+ end
23
+
24
+ return matching_rules
25
+ end
26
+
27
+ def apply_rules(log_detail)
28
+ detect_matching_rules(log_detail).each do |rule|
29
+ rule.apply!
30
+ # puts "logging: #{rule.log}" if !rule.loggable?
31
+ @@ws_channel.push(rule.log) if rule.loggable?
32
+ end
33
+
34
+ end
35
+
36
+ def receive_data(rawdata)
37
+ rawdata.each_line do |data|
38
+ if (!@tmp_line.empty?)
39
+ data = [@tmp_line,data].join
40
+ end
41
+ begin
42
+ # TODO : Risk of infinite loop + Memory Leak. Find a better test than an Error on parsing.
43
+ # => What's happen if one json is invalid ? At this time, the process can't detect anything
44
+ data=JSON.parse(data)
45
+ rescue => e
46
+ # ligne incomplete
47
+ @tmp_line << data
48
+ next
49
+ end
50
+ @tmp_line = []
51
+ data = Hash[data.map{|(k,v)| [k.to_sym,v]}]
52
+ data[:content].strip!
53
+ apply_rules(data)
54
+ end
55
+ end
56
+
57
+ def self.run(options)
58
+ EM.run do
59
+ @@ws_channel = EventMachine::Channel.new
60
+
61
+ Signal.trap("INT") do
62
+ EM.stop
63
+ end
64
+ EventMachine.start_server options[:url], options[:port], Loghandler::Server
65
+
66
+ EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 8080) do |ws|
67
+ @@ws_channel.subscribe do |msg|
68
+ ws.send msg
69
+ end
70
+ # ws.onopen {
71
+ # puts "WebSocket connection open"
72
+ # }
73
+ # ws.onclose { puts "Connection closed" }
74
+ # ws.onmessage { |msg|
75
+ # puts "Recieved message: #{msg}"
76
+ # ws.send "Pong: #{msg}"
77
+ # }
78
+ end
79
+
80
+ end # EM
81
+ end
82
+
83
+ end
@@ -0,0 +1,16 @@
1
+ class Loghandler::Tailer < EventMachine::FileTail
2
+ def initialize(options,channel)
3
+ @options = options
4
+ @channel = channel
5
+ super(options[:file])
6
+ end
7
+
8
+ def receive_data(data)
9
+ data.each_line do |line|
10
+ line.split("\n").each do |sline|
11
+ @channel.push sline
12
+ end
13
+ end
14
+ end
15
+
16
+ end
@@ -0,0 +1,3 @@
1
+ module Loghandler
2
+ VERSION = "0.0.2"
3
+ end
data/lib/loghandler.rb ADDED
@@ -0,0 +1,20 @@
1
+ require 'eventmachine'
2
+ require 'em-websocket'
3
+ require 'eventmachine-tail'
4
+ require 'socket'
5
+ require 'json'
6
+ require 'mongo_mapper'
7
+
8
+ require "loghandler/version"
9
+ require "loghandler/tailer"
10
+ require "loghandler/client"
11
+ require "loghandler/server"
12
+ require "loghandler/log_detail"
13
+
14
+ require "loghandler/rules/abstract_rule"
15
+ require "loghandler/rules/thin_access_log_rule"
16
+ require "loghandler/rules/on_radio_log_rule"
17
+ require "loghandler/rules/generic_log_rule"
18
+
19
+ module Loghandler
20
+ end
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'loghandler/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "loghandler"
8
+ gem.version = Loghandler::VERSION
9
+ gem.authors = ["Olivier Gosse-Gardet"]
10
+ gem.email = ["olivier.gosse.gardet@gmail.com"]
11
+ gem.description = %q{a demo process for handling log with eventmachine}
12
+ gem.summary = %q{a demo process for handling log with eventmachine}
13
+ gem.homepage = ""
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+ # gem.add_dependency('eventmachine', '>= 1.0.0')
20
+ # gem.add_dependency('eventmachine-tail')
21
+ # gem.add_dependency('json')
22
+ # gem.add_dependency('mongo_mapper')
23
+ # gem.add_dependency('bson_ext')
24
+ # gem.add_dependency('em-websocket')
25
+
26
+
27
+ gem.bindir = "bin"
28
+ gem.executables << "loghandler_client"
29
+ gem.executables << "loghandler_server"
30
+
31
+ end
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: loghandler
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Olivier Gosse-Gardet
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-24 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: a demo process for handling log with eventmachine
15
+ email:
16
+ - olivier.gosse.gardet@gmail.com
17
+ executables:
18
+ - loghandler_client
19
+ - loghandler_server
20
+ extensions: []
21
+ extra_rdoc_files: []
22
+ files:
23
+ - .gitignore
24
+ - Gemfile
25
+ - LICENSE.txt
26
+ - README.md
27
+ - Rakefile
28
+ - bin/loghandler_client
29
+ - bin/loghandler_server
30
+ - lib/loghandler.rb
31
+ - lib/loghandler/client.rb
32
+ - lib/loghandler/log_detail.rb
33
+ - lib/loghandler/rules/abstract_rule.rb
34
+ - lib/loghandler/rules/generic_log_rule.rb
35
+ - lib/loghandler/rules/on_radio_log_rule.rb
36
+ - lib/loghandler/rules/thin_access_log_rule.rb
37
+ - lib/loghandler/server.rb
38
+ - lib/loghandler/tailer.rb
39
+ - lib/loghandler/version.rb
40
+ - loghandler.gemspec
41
+ homepage: ''
42
+ licenses: []
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ! '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ! '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ requirements: []
60
+ rubyforge_project:
61
+ rubygems_version: 1.8.22
62
+ signing_key:
63
+ specification_version: 3
64
+ summary: a demo process for handling log with eventmachine
65
+ test_files: []