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



Reply via email to