--- sysplogd 2009/04/10 19:12:17 2 +++ sysplogd 2009/04/11 12:17:53 13 @@ -5,51 +5,131 @@ use IO::Socket; use Data::Dump qw/dump/; -#use StoreToMongoDB; +use DBI; +use Getopt::Long; -my $port = 514; +our $port = 514; +our $MAXLEN = 1524; + +our $dsn = 'DBI:Pg:dbname=syslog'; +our $user = 'dpavlin'; +our $log = '/tmp/sysplog.log'; + +my $config = $0; +$config =~ s{/[^/]+$}{/conf.pl}; +if ( -e $config ) { + require $config; + warn "# using $config ", -s $config, $/; +} + +my $debug = 0; +my $schema = 0; + +GetOptions( + 'debug+' => \$debug, + 'schema!' => \$schema, + 'log=s' => \$log, + 'port=i' => \$port, +) || die "usage: $0 --debug --schema\n"; + +our $VERSION = '0.00'; + +my $sql_schema = q{ + +CREATE TABLE facilities ( + id serial, + name text, + + PRIMARY KEY(name) +); + +CREATE TABLE log ( + id serial, + timestamp timestamp default now(), + ip inet not null, + hostname text not null, + message text, + level int, + facility int, + program text, + pid int, + + PRIMARY KEY (id) +); + +}; -my $MAXLEN = 1524; -my @facilities = ( qw/ -kernel user mail system security internal printer news uucp clock security2 -FTP NTP audit alert clock2 local0 local1 local2 local3 local4 local5 local6 local7 -/ ); +my $dbh = DBI->connect( $dsn, $user, '', { RaiseError => 1 } ) || die $DBI::errstr; + +if ( $schema ) { + $dbh->begin_work; + + $dbh->do( $_ ) foreach split(/;/, $sql_schema); + + my $sth = $dbh->prepare( q{ + insert into facilities (name) values (?) + }); + + $sth->execute( $_ ) foreach ( qw/ + kernel user mail system security internal + printer news uucp clock + security2 + ftp ntp + audit alert + clock2 + local0 local1 local2 local3 local4 local5 local6 local7 + / ); + + warn "# created sql schema\n"; + + $dbh->commit; +} + +my $sth_log_full = $dbh->prepare(qq{ + insert into log + (ip,hostname,message,level,facility,program,pid) + values (?,?,?,?,?,?,?) +}); + +my $sth_log_unparsed = $dbh->prepare(qq{ + insert into log (ip,hostname,messsage) values (?,?,?) +}); + -# Start Listening on UDP port 514 my $sock = IO::Socket::INET->new( LocalPort => $port, Proto => 'udp' # ReuseAddr => 1, ) || die "can't listen to $port: $!"; -print "INFO: listen on $port",$/; +open(my $log_fh, '>>', $log) || die "can't open log $log: $!"; +$log_fh->autoflush(1); +sub _log { + warn 'LOG ',dump( @_ ), $/ if $debug; + print $log_fh time() . '|' . join('|', @_), $/; +} + +_log "INFO: listen on $port"; -my $rin = ''; my $buf; while(1) { $sock->recv($buf, $MAXLEN); my ($port, $ipaddr) = sockaddr_in($sock->peername); my $hostname = gethostbyaddr($ipaddr, AF_INET); my $ip = join('.', unpack('C4',$ipaddr)); - warn "# ",dump( $port, $ipaddr, $hostname, $buf ); + my @values = ( $ip, $hostname, $buf ); - if ( $buf=~/<(\d+)>(.*?):(.*)/ ) { - my $sev=$1 % 8; - my $fac=($1-$sev) / 8; - - my $log = { - ip => $ip, - port => $port, - hostname => $hostname, - - priority => $1, - severity => $sev, - facility => $fac, - header => $2, - message => $3, - }; - print dump( $log ),$/; - #StoreToMongoDB->insert( $log ); + if ( $buf =~ /<(\d+)>\s*(\S*)\s*:\s*(.*)/ ) { + $values[2] = $3; + my $level = $1 % 8; + my $facility = ( $1-$level ) / 8; + my $program = $2; + my $pid = $1 if $program =~ s/\[(\d+)\]$//; + push @values, ( $level, $facility, $program, $pid ); + $sth_log_full->execute( @values ); + } else { + $sth_log_unparsed->execute( @values ); } + _log( @values ); }