Compare commits

...

75 Commits

Author SHA1 Message Date
Denis Knauf 76a05892db Inspector added (loganinc --inspector) 2010-04-14 11:36:25 +02:00
Denis Knauf b76953f57d AutoKeyConvertHash added 2010-04-08 13:13:43 +02:00
Denis Knauf a819b9b0e8 New Hash-function! UNIX-Timestamps as hash-values. Incompatible to older databases! 2010-04-03 21:03:51 +02:00
Denis Knauf 7aa766163a Initialize Analyse-Console 2010-04-03 20:52:57 +02:00
Denis Knauf 338daed210 status: fixed 2010-04-03 13:04:47 +02:00
Denis Knauf 7a244cd465 LogAn::Inc::Fileparser::Line#event_line added and modified #event_read 2010-04-02 16:49:45 +02:00
Denis Knauf b7d6689225 Status: ready 2010-04-02 00:37:48 +02:00
Denis Knauf bc097f8532 Status: smarter... 2010-04-01 23:32:24 +02:00
Denis Knauf f562f25d82 Status: smarter... 2010-04-01 15:57:18 +02:00
Denis Knauf 10f9550059 Status: smaller... 2010-04-01 15:51:15 +02:00
Denis Knauf 5926b94e68 Status: smaller... 2010-04-01 15:38:48 +02:00
Denis Knauf b0b9e6e4ed Status: smaller... 2010-04-01 15:37:43 +02:00
Denis Knauf fa8f42940e Loglines: Counter; status every 5s with counter. 2010-04-01 14:42:39 +02:00
Denis Knauf 9cee5add9e Loglines: Queue enabled and DB-Name-cache 2010-04-01 14:38:59 +02:00
Denis Knauf d3b1d12a12 FileParser::Base: emit fixed 2010-04-01 14:35:24 +02:00
Denis Knauf 4910930b2b FileParser::Base: emit fixed 2010-04-01 14:33:53 +02:00
Denis Knauf 25e650c14c FileParser::Base: emit fixed 2010-04-01 14:32:30 +02:00
Denis Knauf 56a9ae930a FileParser::Base: setter/getter for logdb and store 2010-04-01 14:15:24 +02:00
Denis Knauf b53a39d991 FileParser::Line: include not extend B 2010-04-01 14:12:56 +02:00
Denis Knauf 49b31f2333 FileParser::*#event_line -> #event_read 2010-04-01 14:10:40 +02:00
Denis Knauf f370dcf52d SID0: flatten before pack 2010-04-01 14:07:52 +02:00
Denis Knauf 975769e03d encode/decode-problems 2010-04-01 14:05:29 +02:00
Denis Knauf 61c013ea38 define_method -> define_singleton_method 2010-04-01 14:01:16 +02:00
Denis Knauf 8989f3c559 define_method -> define_singleton_method 2010-04-01 13:56:40 +02:00
Denis Knauf ff2a4aa040 fileparser: Safebox-usage fixed. 2010-04-01 13:51:25 +02:00
Denis Knauf 261d0ddc5f LogAn::AutoValueConvertHash: encode-bug fixed. encode and decode now are methods. 2010-04-01 13:45:43 +02:00
Denis Knauf 19929f069b Logging extended 2010-03-31 00:59:22 +02:00
Denis Knauf 3b8cae9ca4 Logging-Usage fixed 2010-03-31 00:52:34 +02:00
Denis Knauf adbf24bcdc LogAn::Logging for logging added. 2010-03-31 00:51:39 +02:00
Denis Knauf a314bd8d9a Status-informations every 5 seconds added (flush cache, not db) 2010-03-31 00:37:34 +02:00
Denis Knauf 0de5632516 Status-informations every 5 seconds added (fix) 2010-03-31 00:36:00 +02:00
Denis Knauf c8d68f41b1 bin/bos* removed. Status-informations every 5 seconds added 2010-03-31 00:31:00 +02:00
Denis Knauf c4d3e75223 String-based config for files and hosts. Safebox-eval for fileparser 2010-03-30 17:31:35 +02:00
Denis Knauf 3fa3ac495d Cache#each -> AVCH#each_keys 2010-03-30 11:43:59 +02:00
Denis Knauf 694d2a22fa Cache#each added. 2010-03-30 01:23:37 +02:00
Denis Knauf 8b77d3811b Cache#each added. 2010-03-30 01:22:48 +02:00
Denis Knauf 3e9022a677 sid0-problem 2010-03-30 01:19:45 +02:00
Denis Knauf e901e7a991 fileparser-problem 2010-03-30 01:18:09 +02:00
Denis Knauf cc8f758f15 sid0-problem 2010-03-30 01:16:52 +02:00
Denis Knauf 3f267e2ca2 sid0-problem 2010-03-30 01:15:03 +02:00
Denis Knauf 53bf167fd1 stores (seeks) rewritten 2010-03-30 00:37:02 +02:00
Denis Knauf 3c86d43bcf stores (seeks) rewritten 2010-03-30 00:32:50 +02:00
Denis Knauf 7a26a9dfad Cache: vars renamed 2010-03-29 23:12:43 +02:00
Denis Knauf fb987eb461 the fileparser-problem 2010-03-29 22:36:57 +02:00
Denis Knauf 492d9f6dff Server: ArgumentError detected... 2010-03-29 22:15:06 +02:00
Denis Knauf fb5f7dfc47 a={}; abc *a will convert {} to [] 2010-03-29 19:59:34 +02:00
Denis Knauf 9a31e65fa3 Loglines: did not close databases on #close. fixed -> No segv anymore :) 2010-03-29 19:56:16 +02:00
Denis Knauf 877e350d64 Loglines: did not close databases on #close. fixed -> No segv anymore :) 2010-03-29 19:54:29 +02:00
Denis Knauf 928d89f6b3 Main: typo 2010-03-29 19:30:25 +02:00
Denis Knauf fdd16d05e1 Cache: symbol to method 2010-03-29 19:22:43 +02:00
Denis Knauf d1d48ea4f9 Cache: typo 2010-03-29 19:20:52 +02:00
Denis Knauf 584c0014ed Cleaner exit on exception 2010-03-29 19:19:11 +02:00
Denis Knauf cf83e98162 Cleaner exit on exception 2010-03-29 19:16:27 +02:00
Denis Knauf d6c23172a9 Main-Cache fixed 2010-03-29 18:51:36 +02:00
Denis Knauf 14abcfeb5b Cache fixed 2010-03-29 18:50:04 +02:00
Denis Knauf 763800a04f LogAn::Inc::Main: needs Cache 2010-03-29 18:48:16 +02:00
Denis Knauf 9fb86ef146 LogAn::Inc::Main: uses new SBDB::Env#[]-API 2010-03-29 18:46:39 +02:00
Denis Knauf d49ab73666 LogAn::Inc::Main: uses new SBDB::Env#[]-API 2010-03-29 18:44:04 +02:00
Denis Knauf 58c0849d2b store: first try. not ready! 2010-03-29 16:00:55 +02:00
Denis Knauf 952f417170 Fileparser::Base: typo 2010-03-29 15:53:51 +02:00
Denis Knauf 9706b5d991 Safebox-dependency added and Fileparser::Base#logdb/#store added 2010-03-29 15:51:50 +02:00
Denis Knauf 3300e7dec5 typo 2010-03-29 15:37:16 +02:00
Denis Knauf 520a70fa53 conf with Usage 2010-03-29 15:32:37 +02:00
Denis Knauf 8c35b1d646 gemspec fixed 2010-03-29 13:51:46 +02:00
Denis Knauf a5aaab685e still buggy 2010-03-29 11:50:59 +02:00
Denis Knauf 313be57c1d config-inc: @config[db,sid] => @config[db][sid]. Only opened dbs supported. 2010-03-29 01:12:22 +02:00
Denis Knauf 2eb887d9cc Cache added, Main created 2010-03-28 14:33:49 +02:00
Denis Knauf 9f9b6b63a2 Inc: files moved and splitted 2010-03-25 10:39:30 +01:00
Denis Knauf 64a715a1b6 Rotation and Listener (LogAn::Inc) importet 2010-03-23 11:06:05 +01:00
Denis Knauf fc04254b8e metafiles changed; Sandbox has an own repository: Safebox 2010-03-20 23:33:14 +01:00
Denis Knauf 31cf25c5ab TODO markdown 2010-03-17 13:23:53 +01:00
Denis Knauf b9cb56b673 TODO ergaenzt. loganinc mit anfaenglicher Verarbeitung. 2010-03-17 13:22:00 +01:00
Denis Knauf c289c1e9bc TODO hinzugefuegt 2010-03-12 18:02:52 +01:00
Denis Knauf b82ce54d60 $SAFE=4 and persistent storage! That is what i want. 2010-03-02 00:51:15 +01:00
Denis Knauf 4d4978d3ac $SAFE=4 is good, but if you can not modify an array... taint or untaint is unimportand. it must be created after $SAFE=4 2010-03-01 01:28:13 +01:00
19 changed files with 780 additions and 209 deletions

View File

View File

@ -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

44
TODO.md Normal file
View File

@ -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

View File

@ -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

34
bin/conf.rb Executable file
View File

@ -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

View File

@ -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

33
bin/loganinc Executable file
View File

@ -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

12
bin/logansh Executable file
View File

@ -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

51
lib/logan/analyse.rb Normal file
View File

@ -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

134
lib/logan/cache.rb Normal file
View File

@ -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

10
lib/logan/inc.rb Normal file
View File

@ -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

47
lib/logan/inc/command.rb Normal file
View File

@ -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

View File

@ -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

136
lib/logan/inc/main.rb Normal file
View File

@ -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

115
lib/logan/inc/server.rb Normal file
View File

@ -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

97
lib/logan/loglines.rb Normal file
View File

@ -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

View File

@ -1,3 +1,3 @@
require 'logan'
Logan.add CStruct.new( :line)
LogAn.add CStruct.new( :line)

View File

@ -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

View File

@ -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