#!/usr/bin/perl -w # # $Id: logmirror,v 1.9 2004/02/05 17:47:31 nugget Exp $ # (c) Copyright 2004 David C. McNett. All Rights Reserved. # # Author: David McNett # Current Version: http://www.slacker.com/~nugget/stuff/logmirror # # logmirror daemon -- this will mirror remote logfiles to local files in a # bandwidth-friendly manner. This allows you to monitor those logfiles with # native OSX tools such as the "Logger" widget by Todd Harris for Konfabulator. # # Logger widget is here: http://www.widgetgallery.com/view.php?widget=26399 # # This script assumes that you have ssh working with public key auth and that # your SSH_AUTH_SOCKET is available to jobs run from crontab. If you use # SSHKeyChain by Bart Matthaei, this should work without any additional # tweaks. # # SSHKeyChain is here: http://www.sshkeychain.org/ # # First, edit this @logs array to contain one or more remote logs which # you want to mirror locally. Each line is in the format: # # {remote hostname or ip}:{command to run on remote host}:{local filename} my @logs = ( 'dazed.slacker.com:weblog:/tmp/dazed_access_log', 'dazed.slacker.com:tail -f /var/log/messages:/tmp/dazed_messages', ); # Once you've edited the above, edit your personal crontab to run this script # periodically. I run it every minute with the line: # # */1 * * * * /Users/nugget/bin/logmirror # # You can edit your crontab with the command "crontab -e" # # The script attempts to be as smart as possible, not trying to spawn # the mirroring if no networks are available (common with roaming laptops). # # There are a few configuration setting you may wish to tweak: my $control_widget = 0; # Setting this to 1 will cause the script to start # and stop the Logger widget in coordination with # the mirroring of remote logfiles. Set this to 0 # to disable this control. # The $widget variable should store the command which will be run to restart # the widget if $control_widget is set to 1. The setting below will work if # you have installed the widget to the default location: my $login = `whoami`; chomp $login; my $widget = "/Applications/Konfabulator.app/Contents/MacOS/Konfabulator /Users/$login/Documents/Widgets/Logger.widget --child &"; # # You shouldn't have to edit anything below this point # $ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin'; $ENV{'BASH_ENV'} = ''; use strict; use Sys::Syslog; sub debug { my ($level,$buf) = @_; # print "$buf" . "\n"; Sys::Syslog::syslog($level,$buf); } Sys::Syslog::openlog('logmirror','pid','daemon'); Sys::Syslog::setlogsock('unix'); my $nethash = `ifconfig | grep inet | md5`; chomp $nethash; my $lasthash = `cat /tmp/nethash`; chomp $lasthash; if($nethash ne $lasthash) { debug('notice',"Network configuration has changed, recycling mirrors."); open PROCS, 'ps auxwww | egrep "([s]sh -natt)" |'; while() { debug('debug',$_); if($_ =~ /^([^ ]+) +(\d+)/) { debug('notice',"Killing Process $2"); system "kill -TERM $2"; } } close PROCS; system "echo $nethash > /tmp/nethash"; } my $uid = int `id -u`; if(!($ENV{'SSH_AUTH_SOCK'})) { debug('debug',"No SSH_AUTH_SOCK, assuming SSHKeychain value."); $ENV{'SSH_AUTH_SOCK'} = "/tmp/$uid/SSHKeychain.socket"; } my $netactive = int `ifconfig | grep -c "status: active"`; if($netactive == 0) { debug('info',"No networks are active."); if($control_widget == 1) { open PROCS, 'ps auxwww | egrep "([s]sh -natt |[L]ogger.widget)" |'; } else { open PROCS, 'ps auxwww | egrep "([s]sh -natt)" |'; } while() { debug('notice',$_); if($_ =~ /^([^ ]+) (\d+)/) { debug('notice',"Killing Process $2"); system "kill -TERM $2"; } } close PROCS; } else { debug('debug',"Looking for logs to mirror"); my $widget_running = int `ps auxwww | egrep -c "[L]ogger.widget"`; if($control_widget == 1) { if($widget_running != 1) { debug('debug',"Logger.widget is not running"); system $widget; } } debug('debug',"Logger.widget is running"); foreach my $log (@logs) { my ($host, $command, $destfile) = split /:/, $log; debug('debug',"Evaluating $host:$command for mirroring"); my $isrunning = int `ps auxwww | egrep -c "[s]sh -natt $host.*$command"`; if($isrunning == 0) { debug('debug',"No existing tail running for $host:$command"); if(`ping -c 1 $host`) { debug('notice',"I can reach $host and mirroring is currently off for $command. Launching an ssh tail now."); system "ssh -natt $host \"$command\" > $destfile & # logmirror"; } else { debug('info',"Unable to ping $host. No mirroring is possible at this time."); } } } }