#!/usr/bin/perl use strict; use warnings; use Net::IRC; use File::Tail; use Time::HiRes qw/usleep/; use Getopt::Long; use Pod::Usage; my $man; my $help; my $prefix = '\w+ [ 123]\d \d\d:\d\d:\d\d '; my $irc_server = $ENV{IRC_SERVER}; # insert your default here my $irc_channel = '#syslog'; my $irc_nick = 'syslog'; GetOptions ('channel=s' => \$irc_channel, 'nick=s' => \$irc_nick, 'prefix=s' => \$prefix, 'man' => \$man, 'help' => \$help, ); pod2usage(-exitval=>0, -verbose=>0) if ($help); pod2usage(-exitval=>0, -verbose=>1) if ($man); $irc_server ||= shift; pod2usage("No IRC server given - don't know where to connect\n") unless ($irc_server); my $file = shift; pod2usage(-msg=>"Excess arguments ignored\n", -verbose=>0, -exitval=>'NOEXIT') if (@ARGV); $irc_channel = "#$irc_channel" unless ($irc_channel =~ /^\#/); #print STDERR "file $file server $irc_server channel $irc_channel nick $irc_nick\n"; if ($file) { my $ircpipe = irc_login ($irc_server, $irc_channel, $irc_nick, $prefix); $SIG{PIPE} = sub { die "IRC writer died"; undef $ircpipe; }; my $tail = new File::Tail (name=>$file, maxinterval=>1); my $line; while (defined($line = $tail->read)) { print $ircpipe $line; } } else { irc_loop ($irc_server, $irc_channel, $irc_nick, $prefix); } exit 0; sub irc_login { my ($server, $channel, $nick, $prefix) = @_; my $fd; my $pid = open($fd, '|-'); return undef unless (defined $pid); # parent process if ($pid) { my $ofd = select ($fd); $| = 1; select ($ofd); return $fd; } # child process logins to irc and listen for messages irc_loop ($server, $channel, $nick, $prefix); exit 0; } sub irc_loop { my ($server, $channel, $nick, $prefix) = @_; $prefix ||= ''; my $irc = new Net::IRC; my $ircconn = $irc->newconn(Server => $server, Port => 6667, Nick => $nick, Ircname => $nick, ); $ircconn->add_global_handler(376, sub { my ($this) = @_; $this->join($channel); $irc->addfh (fileno (STDIN), sub { my $line = ; exit unless (defined $line); #chomp $line; $line =~ s/^$prefix//; $ircconn->privmsg ($channel, $line); usleep (500_000); # max 2 lines/sec. }); }); $irc->start; } __END__ =head1 NAME irctail - Track a file on an IRC channel =head1 SYNOPSIS irctail [ -c channel ] [ -n nick ] [ -p regex ] host [ file ] irctail [ --man | --help ] =head1 OPTIONS =over 8 =item B<--channel> chan Join the given IRC channel for the output. The channel can be given without the leading # which will be added automatically. =item B<--nick> name Use the give nick on the IRC channel. =item B<--prefix> regex Remove matches for regex before the line is sent to the IRC server. The default matches the date and time in the format used by syslog(8). =back =head1 DESCRIPTION B will read the given input file or standard input and send the data line by line to an IRC channel on I. It is useful when keeping an eye on alerts and other messages from many different sources. =head1 REQUIREMENTS The following modules are needed to use B: NET::IRC File::Tail Time::HiRes =head1 BUGS B doesn't handle being kicked or disconnected. B doesn't reconnect automatically. B can't connect to non-standard ports. B tends to be disconnected for excessive flood if too much data is sent. It is better used for less copious data. =cut