Compare commits
75 Commits
Author | SHA1 | Date |
---|---|---|
Denis Knauf | 76a05892db | |
Denis Knauf | b76953f57d | |
Denis Knauf | a819b9b0e8 | |
Denis Knauf | 7aa766163a | |
Denis Knauf | 338daed210 | |
Denis Knauf | 7a244cd465 | |
Denis Knauf | b7d6689225 | |
Denis Knauf | bc097f8532 | |
Denis Knauf | f562f25d82 | |
Denis Knauf | 10f9550059 | |
Denis Knauf | 5926b94e68 | |
Denis Knauf | b0b9e6e4ed | |
Denis Knauf | fa8f42940e | |
Denis Knauf | 9cee5add9e | |
Denis Knauf | d3b1d12a12 | |
Denis Knauf | 4910930b2b | |
Denis Knauf | 25e650c14c | |
Denis Knauf | 56a9ae930a | |
Denis Knauf | b53a39d991 | |
Denis Knauf | 49b31f2333 | |
Denis Knauf | f370dcf52d | |
Denis Knauf | 975769e03d | |
Denis Knauf | 61c013ea38 | |
Denis Knauf | 8989f3c559 | |
Denis Knauf | ff2a4aa040 | |
Denis Knauf | 261d0ddc5f | |
Denis Knauf | 19929f069b | |
Denis Knauf | 3b8cae9ca4 | |
Denis Knauf | adbf24bcdc | |
Denis Knauf | a314bd8d9a | |
Denis Knauf | 0de5632516 | |
Denis Knauf | c8d68f41b1 | |
Denis Knauf | c4d3e75223 | |
Denis Knauf | 3fa3ac495d | |
Denis Knauf | 694d2a22fa | |
Denis Knauf | 8b77d3811b | |
Denis Knauf | 3e9022a677 | |
Denis Knauf | e901e7a991 | |
Denis Knauf | cc8f758f15 | |
Denis Knauf | 3f267e2ca2 | |
Denis Knauf | 53bf167fd1 | |
Denis Knauf | 3c86d43bcf | |
Denis Knauf | 7a26a9dfad | |
Denis Knauf | fb987eb461 | |
Denis Knauf | 492d9f6dff | |
Denis Knauf | fb5f7dfc47 | |
Denis Knauf | 9a31e65fa3 | |
Denis Knauf | 877e350d64 | |
Denis Knauf | 928d89f6b3 | |
Denis Knauf | fdd16d05e1 | |
Denis Knauf | d1d48ea4f9 | |
Denis Knauf | 584c0014ed | |
Denis Knauf | cf83e98162 | |
Denis Knauf | d6c23172a9 | |
Denis Knauf | 14abcfeb5b | |
Denis Knauf | 763800a04f | |
Denis Knauf | 9fb86ef146 | |
Denis Knauf | d49ab73666 | |
Denis Knauf | 58c0849d2b | |
Denis Knauf | 952f417170 | |
Denis Knauf | 9706b5d991 | |
Denis Knauf | 3300e7dec5 | |
Denis Knauf | 520a70fa53 | |
Denis Knauf | 8c35b1d646 | |
Denis Knauf | a5aaab685e | |
Denis Knauf | 313be57c1d | |
Denis Knauf | 2eb887d9cc | |
Denis Knauf | 9f9b6b63a2 | |
Denis Knauf | 64a715a1b6 | |
Denis Knauf | fc04254b8e | |
Denis Knauf | 31cf25c5ab | |
Denis Knauf | b9cb56b673 | |
Denis Knauf | c289c1e9bc | |
Denis Knauf | b82ce54d60 | |
Denis Knauf | 4d4978d3ac |
7
Rakefile
7
Rakefile
|
@ -10,8 +10,11 @@ begin
|
|||
gem.email = "Denis.Knauf@gmail.com"
|
||||
gem.homepage = "http://github.com/DenisKnauf/logan"
|
||||
gem.authors = ["Denis Knauf"]
|
||||
gem.files = ["README", "VERSION", "lib/**/*.rb", "test/**/*.rb"]
|
||||
gem.require_paths = ["lib"]
|
||||
gem.files = %w[AUTHORS README.md VERSION lib/**/*.rb test/**/*.rb]
|
||||
gem.require_paths = %w[bin lib]
|
||||
gem.add_dependency 'robustserver'
|
||||
gem.add_dependency 'sbdb'
|
||||
gem.add_dependency 'Safebox'
|
||||
end
|
||||
Jeweler::GemcutterTasks.new
|
||||
rescue LoadError
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
|
||||
* BDB/SBDB
|
||||
+ Enthaelt noch einen fiesen Fehler.
|
||||
Kann aber auch an falscher Benutzung liegen.
|
||||
-> TXN-Logging-Overflow
|
||||
|
||||
* Sandbox (90%)
|
||||
|
||||
* Persistenter Speicher
|
||||
+ BDB
|
||||
|
||||
* Transactionsuche
|
||||
+ Sandbox
|
||||
+ Pers. Speicher
|
||||
|
||||
+ Config
|
||||
+ BDB
|
||||
+ String in Object umwandeln
|
||||
- Sandbox
|
||||
+ Objectcache
|
||||
- Hash
|
||||
|
||||
* LogAn
|
||||
+ Ablauf (siehe Bild) (0%)
|
||||
+ Sandbox
|
||||
+ Dequeue
|
||||
- SBDB
|
||||
+ Pers. Speicher
|
||||
+ Config
|
||||
+ emit
|
||||
- SBDB
|
||||
|
||||
* File2LogAn
|
||||
+ Server (50%)
|
||||
- select (100%)
|
||||
+ emit (0%)
|
||||
* SBDB
|
||||
+ Sandbox
|
||||
+ Config
|
||||
|
||||
* push2mysql
|
||||
+ Dequeue
|
||||
- SBDB
|
||||
+ SQL-Insert
|
40
bin/box.rb
40
bin/box.rb
|
@ -1,40 +0,0 @@
|
|||
#!/usr/bin/ruby
|
||||
|
||||
require 'thread'
|
||||
|
||||
class Queue
|
||||
attr_reader :que, :waiting
|
||||
end
|
||||
|
||||
Thread.abort_on_exception = true
|
||||
q, o = Queue.new, Queue.new
|
||||
puts q.inspect
|
||||
|
||||
t = Thread.new( q, o) do |q, o|
|
||||
begin
|
||||
o << 3
|
||||
o.que.taint
|
||||
q.que.taint
|
||||
o.waiting.taint
|
||||
q.waiting.taint
|
||||
$SAFE = 3
|
||||
loop do
|
||||
i = q.pop
|
||||
begin
|
||||
o.push eval(i)
|
||||
rescue Object
|
||||
o.push [$!.class, $!, $!.backtrace].inspect
|
||||
end
|
||||
end
|
||||
rescue Object
|
||||
o.push [$!.class, $!, $!.backtrace].inspect
|
||||
end
|
||||
end
|
||||
|
||||
Thread.new( o) {|o| loop{$stdout.puts "=> #{o.pop.inspect}"} }
|
||||
|
||||
STDIN.each_with_index do |l,i|
|
||||
l.untaint
|
||||
q.push l
|
||||
$stdout.print "(#{i})> "
|
||||
end
|
|
@ -0,0 +1,34 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require 'sbdb'
|
||||
|
||||
conf = {}
|
||||
%w[etc sids].each {|key| conf[key.to_sym] = key }
|
||||
conf[:sids] = File.basename( conf[:sids], ".cnf")+".cnf"
|
||||
|
||||
if ARGV[0].nil? or ARGV[0].empty?
|
||||
$stderr.puts "Usage: #{$0} DATABASE [SID [VALUE]]"
|
||||
exit 1
|
||||
end
|
||||
|
||||
Dir.mkdir conf[:etc] rescue Errno::EEXIST
|
||||
SBDB::Env.open( conf[:etc], SBDB::CREATE | SBDB::Env::INIT_TXN | Bdb::DB_INIT_MPOOL,
|
||||
log_config: SBDB::Env::LOG_IN_MEMORY | SBDB::Env::LOG_AUTO_REMOVE) do |etc|
|
||||
etc.recno( conf[:sids], ARGV[0], flags: SBDB::CREATE | SBDB::AUTO_COMMIT) do |db|
|
||||
if ARGV[2]
|
||||
db[ ARGV[1].to_i] = ARGV[2].empty? ? nil : ARGV[2]
|
||||
end
|
||||
if ARGV[1]
|
||||
$stdout.puts "#{ARGV[0].inspect} #{ARGV[1].to_i} #{db[ ARGV[1].to_i].inspect}"
|
||||
else
|
||||
db.each do |k, v|
|
||||
begin
|
||||
$stdout.puts "#{ARGV[0].inspect} #{k} #{v.inspect}"
|
||||
rescue Bdb::DbError
|
||||
next if 22 == $!.code
|
||||
raise $!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
60
bin/logan
60
bin/logan
|
@ -1,60 +0,0 @@
|
|||
#!/usr/bin/ruby
|
||||
|
||||
require 'sbdb'
|
||||
|
||||
class Emit
|
||||
def initialize env
|
||||
@env = env
|
||||
end
|
||||
|
||||
def emit f, k, v
|
||||
env[ "#{f}/"][ k] = v
|
||||
end
|
||||
end
|
||||
|
||||
class Worker
|
||||
class Box
|
||||
def initialize e
|
||||
@emit = e
|
||||
end
|
||||
|
||||
def emit f, k, v
|
||||
@emit.emit f, k, v
|
||||
end
|
||||
end
|
||||
|
||||
def emit f, k, v
|
||||
@out.push [f, k, v]
|
||||
end
|
||||
|
||||
def initalize i, o
|
||||
@in, @out = i, o
|
||||
Thread.new do
|
||||
$SAFE = 3
|
||||
@in.each do |o|
|
||||
o.data
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
SBDB::Env.new 'conf' do |conf|
|
||||
SBDB::Env.new 'logs' do |logs|
|
||||
SBDB::Env.new 'cache' do |cache|
|
||||
begin
|
||||
wn = conf['worker','conf',flags: SBDB::READONLY]['worker']
|
||||
inq, outq = SizedQueue.new( 1), SizedQueue.new( 1)
|
||||
@worker = wn.times.map{ Worker.new inq, outq }
|
||||
Thread.new( oq) do |oq|
|
||||
cache[ "#{oq[0]}/#{}"][ oq[]]
|
||||
end
|
||||
emit = Emit.new cache
|
||||
box = Box.new emit
|
||||
while line = logs['newids'].get nil, "\0\0\0\0", nil, SBDB::CONSUME_WAIT
|
||||
box.map line
|
||||
end
|
||||
ensure
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,33 @@
|
|||
#!/usr/bin/ruby
|
||||
|
||||
require 'logan'
|
||||
require 'logan/inc'
|
||||
|
||||
opts = {}
|
||||
opts[:inspector] = ARGV[0] == '--inspector' ? ARGV.shift : false
|
||||
opts[:server] = if ARGV[1]
|
||||
ARGV
|
||||
elsif ARGV[0]
|
||||
['localhost', ARGV[1]]
|
||||
else %w[localhost 1087]
|
||||
end
|
||||
opts[:server][1] = opts[:server][1].to_i
|
||||
|
||||
logan = LogAn::Inc::Main.new opts
|
||||
begin
|
||||
logan.instance_eval do
|
||||
@inspector_server = UNIXServer.new 'loganinc.inspector.sock'
|
||||
Thread.new do
|
||||
loop do
|
||||
sock = @inspector_server.accept
|
||||
sock.each_line do |line|
|
||||
sock.puts eval( line).inspect
|
||||
end
|
||||
end
|
||||
end
|
||||
end if opts[:inspector]
|
||||
logan.main
|
||||
rescue Object
|
||||
logan.at_exit
|
||||
raise $!
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require 'logan/analyse'
|
||||
require 'active_support'
|
||||
require 'irb'
|
||||
|
||||
$logan = LogAn::Analyse.new 'logs'
|
||||
begin
|
||||
IRB.start __FILE__
|
||||
ensure
|
||||
$logan.close
|
||||
end
|
|
@ -0,0 +1,51 @@
|
|||
|
||||
require 'logan/loglines'
|
||||
require 'time'
|
||||
|
||||
class LogAn::Analyse
|
||||
attr_reader :lines
|
||||
|
||||
def close
|
||||
@lines.close
|
||||
end
|
||||
|
||||
def initialize lines
|
||||
@lines = String === lines ? LogAn::Loglines.new( lines) : lines
|
||||
end
|
||||
|
||||
def extremum val
|
||||
val = case val
|
||||
when String then Time.parse val
|
||||
when Integer then Time.at val
|
||||
when Time then val
|
||||
else raise ArgumentError, "Unknwon type: #{val}", caller[ 1..-1]
|
||||
end
|
||||
end
|
||||
|
||||
def timerange min, max = nil
|
||||
exend = false
|
||||
min, max, exend = min.min, min.max, min.exclude_end? if Range === min
|
||||
Range.new extremum( min), extremum( max), exend
|
||||
end
|
||||
|
||||
def dbs min, max = nil, &exe
|
||||
return Enumerator.new( self, :dbs, min, max) unless exe
|
||||
range = timerange min, max
|
||||
@lines.rdb.each do |time, db|
|
||||
exe.call db
|
||||
end
|
||||
end
|
||||
|
||||
def search min, max = nil, &exe
|
||||
dbs = @lines.dbs
|
||||
range = timerange min, max
|
||||
@lines.rdb.each do |time, db|
|
||||
dbs[ UUIDTools::UUID.parse_raw( db)].each &exe if range === Time.at( *time.unpack( 'N'))
|
||||
end
|
||||
end
|
||||
alias [] search
|
||||
|
||||
def each min, max = nil, &exe
|
||||
exe ? search( min, max, &exe) : Enumerator.new( self, :search, min, max)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,134 @@
|
|||
|
||||
class LogAn::Cache
|
||||
READ = 1
|
||||
WRITE = 2
|
||||
attr_reader :source, :data
|
||||
|
||||
def initialize source, type = nil, data = nil
|
||||
type ||= READ | WRITE
|
||||
@source, @data, self.type = source, data || {}, type
|
||||
end
|
||||
|
||||
def close
|
||||
@source.close
|
||||
end
|
||||
|
||||
def flush!
|
||||
@data.each {|k,v| @source[k] = v }
|
||||
@data = {}
|
||||
end
|
||||
|
||||
def dget k
|
||||
@data[k] ||= @source[k]
|
||||
end
|
||||
|
||||
def oget k
|
||||
@data[k] || @source[k]
|
||||
end
|
||||
|
||||
def dset k, v
|
||||
@data[k] ||= v
|
||||
end
|
||||
|
||||
def oset k, v
|
||||
@source[k] = v
|
||||
end
|
||||
|
||||
def type= type
|
||||
self.read_cache, self.write_cache = type & 1 > 0, type & 2 > 0
|
||||
type
|
||||
end
|
||||
|
||||
def read_cache= type
|
||||
@type &= ~ (type ? 0 : 1)
|
||||
define_singleton_method :[], method( type ? :oget : :dget)
|
||||
end
|
||||
|
||||
def write_cache= type
|
||||
@type &= ~ (type ? 0 : 2)
|
||||
define_singleton_method :[]=, method( type ? :oset : :dset)
|
||||
end
|
||||
|
||||
include Enumerable
|
||||
def each *paras
|
||||
return Enumerator.new self, :each unless block_given?
|
||||
flush! if @type&2 == 2
|
||||
@source.each_keys( *paras) do |key|
|
||||
yield key, self[key]
|
||||
end
|
||||
self
|
||||
end
|
||||
end
|
||||
|
||||
class LogAn::AutoValueConvertHash
|
||||
include Enumerable
|
||||
attr_reader :source
|
||||
|
||||
def initialize source, encode = nil, each = nil, &decode
|
||||
@source, @encode = source, encode || ( decode.nil? && Marshal.method( :dump) )
|
||||
@each, @decode = each, decode || Marshal.method( :restore)
|
||||
@each ||= source.method( :each) rescue NameError
|
||||
define_singleton_method :encode, &@encode if @encode
|
||||
define_singleton_method :decode, &@decode if @decode
|
||||
LogAn::Logging.debug encode: @encode, decode: @decode, each: @each
|
||||
end
|
||||
|
||||
def close
|
||||
@source.close
|
||||
end
|
||||
|
||||
def [] k
|
||||
decode @source[k]
|
||||
end
|
||||
|
||||
def []= k, v
|
||||
@source[k] = encode v
|
||||
end
|
||||
|
||||
def each *paras
|
||||
return Enumerator.new self, :each unless block_given?
|
||||
@each.call *paras do |k, v|
|
||||
yield k, decode( v)
|
||||
end
|
||||
end
|
||||
|
||||
def each_keys *paras
|
||||
return Enumerator.new self, :each_keys unless block_given?
|
||||
@each.call *paras do |k, v|
|
||||
yield k
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class LogAn::AutoKeyConvertHash
|
||||
include Enumerable
|
||||
attr_reader :source
|
||||
|
||||
def initialize source, encode = nil, each = nil, &decode
|
||||
@source, @encode = source, encode || ( decode.nil? && Marshal.method( :dump) )
|
||||
@each, @decode = each, decode || Marshal.method( :restore)
|
||||
@each ||= source.method( :each) rescue NameError
|
||||
define_singleton_method :encode, &@encode if @encode
|
||||
define_singleton_method :decode, &@decode if @decode
|
||||
LogAn::Logging.debug encode: @encode, decode: @decode, each: @each
|
||||
end
|
||||
|
||||
def close
|
||||
@source.close
|
||||
end
|
||||
|
||||
def [] k
|
||||
@source[ encode( k)]
|
||||
end
|
||||
|
||||
def []= k, v
|
||||
@source[ encode( k)] = v
|
||||
end
|
||||
|
||||
def each *paras
|
||||
return Enumerator.new self, :each unless block_given?
|
||||
@each.call *paras do |k, v|
|
||||
yield decode( k), v
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
require 'logan/inc/server'
|
||||
require 'logan/inc/fileparser'
|
||||
require 'logan/inc/command'
|
||||
require 'logan/inc/main'
|
||||
|
||||
module LogAn
|
||||
module Inc
|
||||
end
|
||||
end
|
|
@ -0,0 +1,47 @@
|
|||
|
||||
module LogAn
|
||||
module Inc
|
||||
class Command < ::Array
|
||||
attr_reader :sid
|
||||
def initialize sid = 0
|
||||
@sid = sid
|
||||
end
|
||||
|
||||
def event_read line, sock
|
||||
cmd, l = line.unpack 'na*'
|
||||
self[cmd].call( l, sock) if self[cmd]
|
||||
end
|
||||
end
|
||||
|
||||
class SID0 < Command
|
||||
class <<self
|
||||
def config=( db) @@config = db end
|
||||
def config() @@config end
|
||||
def store=( db) @@store = db end
|
||||
def store() @@store end
|
||||
end
|
||||
|
||||
def initialize sid = 0
|
||||
super sid
|
||||
self[9] = method :event_hostname
|
||||
self[10] = method :event_filerotated
|
||||
end
|
||||
|
||||
def event_filerotated line, sock
|
||||
sid, inode, seek = line.unpack 'NNN'
|
||||
@@store[ :seeks][ sid] = [inode, seek]
|
||||
end
|
||||
|
||||
def event_hostname line, sock
|
||||
@@config[ :hosts].each do |sid, host|
|
||||
next unless line == host
|
||||
file = @@config[ :files][ sid]
|
||||
next unless file
|
||||
# command, SID, (inode, seek), file
|
||||
pc = [1, sid, @@store[ :seeks][ sid], file].flatten.pack 'nNNNa*'
|
||||
sock.write [pc.length, pc].pack( 'Na*')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,61 @@
|
|||
|
||||
module LogAn
|
||||
module Inc
|
||||
module FileParser
|
||||
module Base
|
||||
class <<self
|
||||
def logdb=( var) @@logdb = var end
|
||||
def logdb() @@logdb end
|
||||
def store=( var) @@store = var end
|
||||
def store() @@store end
|
||||
end
|
||||
|
||||
def emit line
|
||||
@@logdb.emit line, @sid
|
||||
end
|
||||
|
||||
def seeks read
|
||||
inode, seek = @@store[ :seeks][@sid]
|
||||
@@store[ :seeks][@sid] = [inode, read + seek]
|
||||
end
|
||||
end
|
||||
|
||||
class Line
|
||||
include Base
|
||||
attr_reader :sid, :delimiter, :buffer, :linebuffer
|
||||
|
||||
def initialize sid, delimiter = nil
|
||||
@sid, @delimiter = sid, delimiter || "\n"
|
||||
@delimiter = Regexp.new "^.*?#{@delimiter}"
|
||||
@buffer, @linebuffer = Select::Buffer.new( ''), Select::Buffer.new( '')
|
||||
end
|
||||
|
||||
def event_read str, sock = nil
|
||||
@buffer += str
|
||||
@buffer.each! @delimiter, &method( :event_line)
|
||||
end
|
||||
|
||||
def event_line line
|
||||
emit line
|
||||
seeks line.length
|
||||
end
|
||||
end
|
||||
|
||||
class Multiline < Line
|
||||
def initialize sid, delimiter = nil, multiline = nil
|
||||
super sid, delimiter
|
||||
@multiline = multiline || /^\d\d-\d\d-\d\d:/
|
||||
end
|
||||
|
||||
def event_line line
|
||||
if line =~ @multiline
|
||||
emit @linebuffer.to_s
|
||||
seeks @linebuffer.length
|
||||
@linebuffer.replace line
|
||||
else @linebuffer += line
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,136 @@
|
|||
|
||||
require 'sbdb'
|
||||
require 'safebox'
|
||||
require 'robustserver'
|
||||
require 'socket'
|
||||
require 'logan/inc'
|
||||
require 'logan/loglines'
|
||||
require 'logan/cache'
|
||||
|
||||
module LogAn::Logging
|
||||
class << self
|
||||
def log lvl, *txt
|
||||
$stderr.puts( ([Time.now, lvl]+txt).inspect)
|
||||
end
|
||||
alias method_missing log
|
||||
end
|
||||
def method_missing *paras
|
||||
self.class.log *paras
|
||||
end
|
||||
end
|
||||
|
||||
module LogAn::Inc
|
||||
class Main < RobustServer
|
||||
def cache ret, type, &e
|
||||
type ||= 1+4
|
||||
ret = LogAn::AutoValueConvertHash.new ret, &e if type&4 > 0 or e
|
||||
ret = LogAn::Cache.new ret, type&3 if type&3 > 0
|
||||
ret
|
||||
end
|
||||
|
||||
# Open Store.
|
||||
def store env, db, type = nil, flags = nil, &e
|
||||
LogAn::Logging.info :store, :open, "sids.cnf", db, type
|
||||
cache env[ 'sids.cnf', db, :flags => flags || SBDB::CREATE | SBDB::AUTO_COMMIT], type, &e
|
||||
end
|
||||
|
||||
# Open Config.
|
||||
def config env, db, type = nil, flags = nil, &e
|
||||
LogAn::Logging.info :config, :open, "sids.cnf", db, type
|
||||
cache env[ 'sids.cnf', db, :flags => flags || SBDB::RDONLY], type, &e
|
||||
end
|
||||
|
||||
# Prepare Server.
|
||||
#
|
||||
# * conf:
|
||||
# logs
|
||||
# : Where to store log-databases? default: ./logs
|
||||
# etc
|
||||
# : Where to find config-databases? default: ./etc
|
||||
# server
|
||||
# : Server-Configuration. default { port: 1087 }
|
||||
def initialize conf
|
||||
super
|
||||
|
||||
# Copy config - changes possible
|
||||
@conf = {}
|
||||
conf.each {|key, val| @conf[key]= val }
|
||||
|
||||
# Default directories
|
||||
%w[logs etc].each {|key| @conf[key.to_sym] = key }
|
||||
|
||||
# Open Loglines-databases
|
||||
@logs = LogAn::Loglines.new @conf[:logs]
|
||||
LogAn::Inc::FileParser::Base.logdb = @logs
|
||||
|
||||
# Open config-databases
|
||||
Dir.mkdir @conf[:etc] rescue Errno::EEXIST
|
||||
@etc = SBDB::Env.new( @conf[:etc],
|
||||
log_config: SBDB::Env::LOG_IN_MEMORY | SBDB::Env::LOG_AUTO_REMOVE,
|
||||
flags: SBDB::CREATE | SBDB::Env::INIT_TXN | Bdb::DB_INIT_MPOOL)
|
||||
|
||||
# Open configs
|
||||
begin
|
||||
configs = @conf[:configs] = {}
|
||||
%w[hosts files].each {|key| configs[key.to_sym] = config( @etc, key) {|l| l } }
|
||||
configs[:fileparser] = config @etc, 'fileparser', &Safebox.method( :eval)
|
||||
LogAn::Inc::SID0.config = configs
|
||||
end
|
||||
|
||||
# Open seeks-database
|
||||
begin
|
||||
stores = @conf[:stores] = {}
|
||||
db = @etc[ 'sids.store', 'seeks', SBDB::Recno, SBDB::CREATE | SBDB::AUTO_COMMIT]
|
||||
db = LogAn::AutoValueConvertHash.new( db, lambda {|val| val.pack( 'NN') }) {|val|
|
||||
(val||0.chr*8).unpack( 'NN')
|
||||
}
|
||||
stores[:seeks] = LogAn::Cache.new db
|
||||
LogAn::Inc::FileParser::Base.store = LogAn::Inc::SID0.store = stores
|
||||
end
|
||||
|
||||
# Select-framework
|
||||
@select = LogAn::Inc::Select.new
|
||||
@status = method :status
|
||||
status # Init Status
|
||||
|
||||
# Prepare Inc-server - create server
|
||||
@serv = LogAn::Inc::Server.new :sock => TCPServer.new( *@conf[:server]),
|
||||
:config => @conf[:configs], :select => @select
|
||||
LogAn::Logging.debug @serv
|
||||
|
||||
# Shutdown on signals
|
||||
@sigs[:INT] = @sigs[:TERM] = method( :shutdown)
|
||||
|
||||
rescue Object
|
||||
# It's better to close everything, because BDB doesn't like unexpected exits
|
||||
self.at_exit
|
||||
raise $!
|
||||
end
|
||||
|
||||
def status
|
||||
@select.at Time.now+5, &@status
|
||||
LogAn::Logging.info :recv_lines => @logs.counter,
|
||||
:connections => @serv && @serv.clients.map {|cl| cl.sock.peeraddr }
|
||||
@conf[ :stores].each {|key, db| db.flush!}
|
||||
end
|
||||
|
||||
# Will be called at exit. Will close all opened BDB::Env
|
||||
def at_exit
|
||||
LogAn::Logging.info :at_exit
|
||||
@logs and @logs.close
|
||||
@etc and @etc.close
|
||||
end
|
||||
|
||||
# Shutdown Server cleanly. First shutdown TCPServer.
|
||||
def shutdown signal = nil
|
||||
LogAn::Logging.info :signal, signal, Signal[ signal] if signal
|
||||
@serv.close
|
||||
exit 0
|
||||
end
|
||||
|
||||
# Runs server. Don't use it! Use #main.
|
||||
def run
|
||||
@serv.run
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,115 @@
|
|||
|
||||
require 'select'
|
||||
|
||||
module LogAn
|
||||
module Inc
|
||||
end
|
||||
end
|
||||
|
||||
class LogAn::Inc::Select <::Select
|
||||
attr_reader :entries
|
||||
def initialize *p
|
||||
super *p
|
||||
@entries=[]
|
||||
end
|
||||
|
||||
def run
|
||||
until @exit || (@exit_on_empty && self.empty?)
|
||||
cron
|
||||
run_once 1
|
||||
end
|
||||
end
|
||||
|
||||
def cron
|
||||
@entries.each do |e|
|
||||
return if e > Time.now
|
||||
e.call
|
||||
@entries.shift
|
||||
end
|
||||
end
|
||||
|
||||
class Entry < Time
|
||||
attr_reader :do
|
||||
def do &e
|
||||
@do = e
|
||||
end
|
||||
|
||||
def call *p
|
||||
@do.call *p
|
||||
end
|
||||
|
||||
def self.new *a, &e
|
||||
x = self.at *a
|
||||
x.do &e
|
||||
x
|
||||
end
|
||||
end
|
||||
|
||||
def at a, &e
|
||||
a = Entry.new a, &e if e
|
||||
@entries << a
|
||||
@entries.sort!
|
||||
end
|
||||
end
|
||||
|
||||
class LogAn::Inc::Socket <::Select::Socket
|
||||
def initialize *p
|
||||
super( *p)
|
||||
LogAn::Logging.info :connected, self
|
||||
end
|
||||
|
||||
def event_read sock = @sock, event = :read
|
||||
begin
|
||||
@linebuf += sock.readpartial( @bufsize)
|
||||
rescue EOFError
|
||||
self.event_eof sock
|
||||
rescue Errno::EPIPE
|
||||
self.event_errno $!, sock, event
|
||||
rescue IOError
|
||||
self.event_ioerror sock, event
|
||||
rescue Errno::ECONNRESET => e
|
||||
self.event_errno e, sock, event
|
||||
end
|
||||
loop do
|
||||
return if @linebuf.size < 4
|
||||
l = @linebuf.unpack( 'N')[0]
|
||||
return if l > @linebuf.length
|
||||
@linebuf.remove 4
|
||||
event_cmd @linebuf.remove( l)
|
||||
end
|
||||
end
|
||||
|
||||
def close
|
||||
LogAn::Logging.info :disconnect, self
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
class LogAn::Inc::Server < ::Select::Server
|
||||
attr_reader :config, :clients
|
||||
|
||||
def init opts
|
||||
super opts
|
||||
@config = opts[:config] or raise( ArgumentError, "#{self.class} needs a Config!")
|
||||
end
|
||||
|
||||
def event_new_client sock
|
||||
{ :clientclass => LogAn::Inc::Server::Socket, :config => @config }
|
||||
end
|
||||
|
||||
class Socket < LogAn::Inc::Socket
|
||||
attr_reader :config
|
||||
|
||||
def init opts
|
||||
super opts
|
||||
@sid0 = LogAn::Inc::SID0.new
|
||||
@config = opts[:config] or raise( ArgumentError, "#{self.class} needs a Config!")
|
||||
end
|
||||
|
||||
def event_cmd cmd
|
||||
sid, line = cmd.unpack 'Na*'
|
||||
fp = sid == 0 ? @sid0 : @config[:fileparser][sid]
|
||||
fp.event_read line, self if fp
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,97 @@
|
|||
#!/usr/bin/ruby
|
||||
|
||||
require 'sbdb'
|
||||
require 'uuidtools'
|
||||
require 'logan'
|
||||
|
||||
module LogAn
|
||||
class Loglines
|
||||
attr_reader :env, :rdb, :dbs, :counter
|
||||
|
||||
def self.new *paras
|
||||
ret = obj = super( *paras)
|
||||
begin ret = yield obj
|
||||
ensure
|
||||
SBDB.raise_barrier &obj.method( :close)
|
||||
end if block_given?
|
||||
ret
|
||||
end
|
||||
|
||||
def initialize env = nil
|
||||
env ||= 'logs'
|
||||
@env = if String === env
|
||||
Dir.mkdir env rescue Errno::EEXIST
|
||||
SBDB::Env.new env,
|
||||
log_config: SBDB::Env::LOG_IN_MEMORY | SBDB::Env::LOG_AUTO_REMOVE,
|
||||
flags: SBDB::CREATE | SBDB::Env::INIT_TXN | Bdb::DB_INIT_MPOOL
|
||||
else env
|
||||
end
|
||||
@rdb = AutoValueConvertHash.new(
|
||||
AutoKeyConvertHash.new(
|
||||
@env[ 'rotates.db', :type => SBDB::Btree, :flags => SBDB::CREATE | SBDB::AUTO_COMMIT],
|
||||
lambda {|key| [key.to_i].pack 'N' }) {|key| Time.at key.unpack( 'N') },
|
||||
lambda {|val| String === val ? val : val.raw }) {|val| val && UUIDTools::UUID.parse_raw( val) }
|
||||
@queue = @env[ "newids.queue", :type => SBDB::Queue,
|
||||
:flags => SBDB::CREATE | SBDB::AUTO_COMMIT, :re_len => 16]
|
||||
@dbs, @counter = {}, 0
|
||||
self.hash_func = lambda {|k|
|
||||
n = k.timestamp.to_i
|
||||
n -= n % 3600
|
||||
}
|
||||
end
|
||||
|
||||
def close
|
||||
@env.close
|
||||
end
|
||||
|
||||
def hash_func= exe
|
||||
hash_func &exe
|
||||
end
|
||||
|
||||
def hash_func &exe
|
||||
@hash_func = exe if exe
|
||||
@hash_func
|
||||
end
|
||||
|
||||
def hashing key
|
||||
@hash_func.call key
|
||||
end
|
||||
|
||||
def db_name id
|
||||
hash = hashing id
|
||||
name = @rdb[ hash]
|
||||
if name
|
||||
name = UUIDTools::UUID.parse_raw name
|
||||
else
|
||||
name = UUIDTools::UUID.timestamp_create
|
||||
@rdb[ hash] = name.raw
|
||||
end
|
||||
name
|
||||
end
|
||||
|
||||
def db name
|
||||
@dbs[name] ||= @env[ name.to_s, :type => SBDB::Btree,
|
||||
:flags => SBDB::CREATE | SBDB::AUTO_COMMIT]
|
||||
end
|
||||
|
||||
def sync
|
||||
@dbs.each {|name, db| db.sync }
|
||||
@rdb.sync
|
||||
end
|
||||
|
||||
def put val, sid = nil
|
||||
id = UUIDTools::UUID.timestamp_create
|
||||
dat = [sid || 0x10, val].pack 'Na*'
|
||||
name = db_name id
|
||||
db( name)[ id.raw] = dat
|
||||
@counter += 1
|
||||
@queue.push id.raw
|
||||
end
|
||||
alias emit put
|
||||
|
||||
def get key
|
||||
name = db_name id
|
||||
db( name)[ id.raw]
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,3 +1,3 @@
|
|||
require 'logan'
|
||||
|
||||
Logan.add CStruct.new( :line)
|
||||
LogAn.add CStruct.new( :line)
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
#!/usr/bin/ruby
|
||||
|
||||
require 'sbdb'
|
||||
require 'uuidtools'
|
||||
|
||||
class Rotate
|
||||
def initialize db, env = db.home, &e
|
||||
@rdb, @env, @dbs = db, env, {}
|
||||
self.hash = e || lambda {|k|
|
||||
[k.timestamp.to_i/60/60/24].pack 'N'
|
||||
}
|
||||
end
|
||||
|
||||
def hash= e
|
||||
self.hash &e
|
||||
end
|
||||
|
||||
def hash &e
|
||||
@hash_func = e if e
|
||||
@hash_func
|
||||
end
|
||||
|
||||
def hashing k
|
||||
@hash_func.call k
|
||||
end
|
||||
|
||||
def db_name id
|
||||
h = hashing id
|
||||
n = @rdb[ h]
|
||||
if n
|
||||
n = UUIDTools::UUID.parse_raw n
|
||||
else
|
||||
n = UUIDTools::UUID.timestamp_create
|
||||
@rdb[ h] = n.raw
|
||||
info :create => n.to_s
|
||||
end
|
||||
n
|
||||
end
|
||||
|
||||
def db n
|
||||
@env[ n.to_s, :type => SBDB::Btree, :flags => SBDB::CREATE | SBDB::AUTO_COMMIT]
|
||||
end
|
||||
|
||||
def sync
|
||||
@dbs.each{|n,db|db.sync}
|
||||
@rdb.sync
|
||||
end
|
||||
|
||||
def close
|
||||
@dbs.each{|n,db|db.close 0}
|
||||
@rdb.close 0
|
||||
end
|
||||
|
||||
def put k, v, f = k
|
||||
id = UUIDTools::UUID.timestamp_create
|
||||
s = [0x10, v].pack 'Na*'
|
||||
n = db_name id
|
||||
db( n)[ id.raw] = s
|
||||
end
|
||||
alias emit put
|
||||
|
||||
def get k
|
||||
n = db_name id
|
||||
db( n)[ id.raw] = s
|
||||
end
|
||||
end
|
|
@ -1,40 +0,0 @@
|
|||
# Generated by jeweler
|
||||
# DO NOT EDIT THIS FILE DIRECTLY
|
||||
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = %q{logan}
|
||||
s.version = "0.0.0"
|
||||
|
||||
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
||||
s.authors = ["Denis Knauf"]
|
||||
s.date = %q{2010-02-24}
|
||||
s.description = %q{}
|
||||
s.email = %q{Denis.Knauf@gmail.com}
|
||||
s.extra_rdoc_files = [
|
||||
"LICENSE"
|
||||
]
|
||||
s.files = [
|
||||
"VERSION",
|
||||
"lib/cstruct.rb",
|
||||
"lib/logan.rb",
|
||||
"lib/logan/types/syslog.rb"
|
||||
]
|
||||
s.homepage = %q{http://github.com/DenisKnauf/logan}
|
||||
s.rdoc_options = ["--charset=UTF-8"]
|
||||
s.require_paths = ["lib"]
|
||||
s.rubygems_version = %q{1.3.5}
|
||||
s.summary = %q{Logdata analysing database}
|
||||
|
||||
if s.respond_to? :specification_version then
|
||||
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
||||
s.specification_version = 3
|
||||
|
||||
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
||||
else
|
||||
end
|
||||
else
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue