Yes. What he said is what I do too.
I took a couple of minutes and fleshed it out a bit more for you. In
reality I keep stats on my queues and handle shutdowns gracefully. I took
most of that out here and also cleaned up your code a bit. It's untested
but does compile :)
use warnings;
use strict;
use POE;
use POE::Component::Server::Syslog;
use DBI; # library for performing database functions
use DBD::DB2;
use DBD::DB2::Constants;
# use Mail::SendMail;
sub QUEUE_FLUSH_TIME () { 10 }
our $DEBUG = 1;
# The queue
POE::Session->create(
inline_states => {
_start => sub {
my ( $kernel, $heap ) = @_[ KERNEL, HEAP ];
$heap->{queue} = [];
$kernel->alias_set("queue_handler");
$kernel->delay_set("process_queue",
QUEUE_FLUSH_TIME);
},
add_message => sub {
my ( $kernel, $heap, $message ) = @_[ KERNEL, HEAP,
ARG0 ];
push( @{ $heap->{queue} }, $message );
},
process_queue => sub {
my ( $kernel, $heap ) = @_[ KERNEL, HEAP ];
if ( scalar( @{$heap->{queue}} ) ) {
my $child = POE::Wheel::Run->new
( Program => sub {
handle_queue($heap->{queue});
},
StdoutFilter =>
POE::Filter::Line->new(),
StderrFilter =>
POE::Filter::Line->new(),
StdoutEvent => "queue_stdout",
StderrEvent => "queue_stderr",
CloseEvent => "queue_done",
);
$heap->{children}->{ $child->ID } = $child;
warn("qid[". $child->ID ."]: started
queue\n") if $DEBUG;
# zero the queue because we just handed the
old one off
@{$heap->{queue}} = ();
}
# This keeps the queue going
$kernel->delay_set("process_queue",
QUEUE_FLUSH_TIME);
},
}
);
POE::Component::Server::Syslog->spawn(
BindAddress => '129.37.2.201',
InputState => \&client_input,
ErrorState => \&client_error,
);
$poe_kernel->run();
######################################
# PoCo::Server::Syslog event handlers
sub client_input {
my ($kernel,$msg) = @_[KERNEL, ARG0];
$kernel->post( "queue_handler" => "add_message" => $msg );
}
sub client_error {
# Something went wrong with the syslog message
# Figure out what to do, if anything, in this case later
warn "BAD MESSAGE: $_[ARG0]";
}
#####################################
# queue_handler Session events
sub queue_stdout {
my ($line, $id) = @_[ ARG0, ARG1 ];
warn("qid[$id]: $line\n");
}
sub queue_stderr {
my ($line, $id) = @_[ ARG0, ARG1 ];
warn("qid[$id](err): $line\n");
}
sub queue_done {
my ($heap, $id) = @_[ HEAP, ARG0 ];
warn("qid[$id]: finished queue\n") if $DEBUG;
delete $heap->{children}->{$id};
}
# Not a POE event handler but runs in a forked process using
POE::Wheel::Run
sub handle_queue {
my $queue = shift;
my $dbName = "vpn";
my $dbh = DBI->connect("DBI:DB2:$dbName","xxxxx","xxxxxx")
or die "can't connect: " . $DBI::errstr;
my $sth = $dbh->prepare(<<'END_SQL');
INSERT INTO VPN.SYSLOG_C3K (DATE_TIME, DEVICE, SEV, MSG)
VALUES(?,?,?,?)
END_SQL
foreach my $msg ( @$queue ) {
# Parse the data for DB entry
# Check this pattern because my mail client
probably screwed up the format
# Also you should handle the case when the pattern
match below doesn't match
# but that's up to you.
$msg->{'msg'} =~ /^(.*?) (\d+)\/(\d+)\/(\d+)
(\d+):(\d+):(\d+)\.(\d+) SEV=. (.*?)$/;
$sth->execute("$4-$2-$3-$5.$6.$7.$8",
$msg->{'host'}, $msg->{'severity'},$9);
print " Host: ".$msg->{'host'}."\n";
print "Severity: ".$msg->{'severity'}."\n";
print " Msg: ".$msg->{'msg'}."\n";
}
$sth->finish;
$dbh->disconnect;
}
-
Lance Braswell - + 1 469 357 6112
Bas Schulte
<[EMAIL PROTECTED]
net.nl> To
"Jim" <[EMAIL PROTECTED]>
03/31/2005 03:20 cc
PM poe@perl.org
Subject
Re: Syslog child on Windows
Jim,
On donderdag, maa 31, 2005, at 21:06 Europe/Amsterdam, Jim wrote:
> If you feel like giving me an example that accomplishes what I want to
> do
> below, I'd be glad to use yours too. :-)
The concept is fairly simple: instead of connecting to your database in
your 'client_input' state, push the input data at the end of a global
list:
sub client_input {
# Get the syslog hash
my $msg = $_[ARG0];
my $databaseHandle;
my $connectFailureFlag = 0;
my $search;
my $sth;
my $dbName = "vpn";
# Parse the data for DB entry
$msg->{'msg'} =~ /^(.*?) (\d+)\/(\d+)\/(\d+)
(\d+):(\d+):(\d+)\.(\d+)SEV=. (.*?)$/;
## Don't connect to db, just push it on the queue
push @$queue, $msg;
}
And before the 'spawn' of POE::Component::Server::Syslog, create a new
session:
my $queue; ## global, holds queue elements
POE::Session->create(
inline_states =>
{ _start => sub {
$_[KERNEL]->delay( tick => 5 );
},
tick => 'doTick'
);
);
sub doTick
{
my ($kernel) = @_[KERNEL];
## connect to db
## write all elements in the queue to the database
foreach my $element (@$queue) {
## $element->{msg} holds your message
}
## disconnect from db
## All done now, empty queue
undef $queue;
$_[KERNEL]->delay(doTick => 5);
}
The delay will cause your doTick to be called every 5 seconds, so you
only connect once every 5 seconds instead of connecting on each request.
You might just as well open the db connection when your tick session
starts, and hold a reference to it in the heap of that session. Then
you'd have to be prepared for the connection getting lost, and
reconnect when it is lost.
Cheers,
Bas.
ps. read about delay here:
http://poe.perl.org/?POE_Cookbook/Recurring_Alarms