Some FTP servers, like ProFTP doesn't have option of logging to remote hosts (or there is, but I couldn't find it).
So if you have more instances of FTP server, it's convenient to log in one central log server.
And probably the most important is transfer logging, which is the file xfer.log
(you know, you can put software for customers on your FTP and later when you want to charge them, they say "we didn't download anything",
so first place you check is transfer log file).
So here is the Perl script, that in real time reads xfer.log file and copy lines to local syslog file (example on Solaris).
And syslog.conf is then configured to log to central server.
SMF : xfer2syslog (copy proftpd xfer.log entries to syslog file on local machine)
Required packages
From Blastwave:
pm_filetail (CSWpmfiletail)
pm_unixsyslog (CSWpmunixsyslog)
------------------
The SMF service should have next entities:
1. Executable
Example: /usr/ups/bin/xfer2syslog.pl
2. Method (usually executable shell script) to define how service start/stop
Default location is directory /lib/svc/method/
Example: /lib/svc/method/svc-xfer2syslog
3. Fault Management Resource Identifier (FMRI) to identify name/instance
Example: application/xfer2syslog or xfer2syslog
4. Log file (usually created automatically on its own, in directory /var/svc/log/ )
Example: /var/svc/log/xfer2syslog:default.log
5. Manifest (XML file) to define service's properties
Default location is directory /var/svc/manifest/
Example: /var/svc/manifest/application/xfer2syslog.xml
-----------------
Roll out the service
1. Validate service's manifest (xml file)
example:
> svccfg validate /var/svc/manifest/application/xfer2syslog.xml
2.Import service into SMF
example:
> svccfg import /var/svc/manifest/application/xfer2syslog.xml
3.Enable service
example:
> svcadm enable application/xfer2syslog
4. Verify service
example: list service information and associated processes
> svcs -lp application/xfer2syslog
example:list explanation for service's state
> svcs -xv application/xfer2syslog
|
#!/opt/csw/bin/perl -w
use strict;
use File::Tail;
use Unix::Syslog;
# define log file to be read
my $logfile="/var/log/proftpd/xfer.log" ;
# check if xfer.log exist
if ( ! -e $logfile ) {
die "EXIT : Cannot read $logfile: $! ";
}
# maxinterval = max number of sec that script sleeps, default = 60s
my $readfile=File::Tail->new(
name=>$logfile,
maxinterval=>3
);
# variables for Unix::Syslog
#my $ident="ftp_transfer";
my $ident="xfer";
my $option="1"; # LOG_PID
my $facility="0"; # no affect so far?
my $priority=6; # info
# read ftp transfer file and log to syslog
while (my $line=$readfile->read) {
# test : print on STDOUT
# print "${line}";
Unix::Syslog::openlog($ident, $option, $facility);
Unix::Syslog::syslog($priority, $line);
# don't close syslog file
#closelog();
}
|
#!/sbin/sh
#set -x
#
# Start method script for the service xfer2syslog
# -- zdudic : December 8, 2010
#. /lib/svc/share/smf_include.sh
# die funcion
die() {
echo "\n ERROR: $* \n"
exit 1
}
# Check if argument (stop/start) is provided
if [ $# != 1 ]
then
die "Usage : `/usr/bin/basename $0` [stop|start] "
fi
SCRIPT=/usr/ups/bin/xfer2syslog.pl
GREP=/usr/sfw/bin/gegrep
# ---- number of running scripts in background
PROCNUM=`ps -ef | ${GREP} xfer2syslog.pl$ | wc -l`
case "$1" in
'start')
# --- exit if more than one ( > 1 ) script is running
if [ ${PROCNUM} -gt 1 ]
then
die " \n${PROCNUM} scripts are already running, which causes multiplications of logs.
The additional xfer2syslog processes can be killed manually. "
fi
# --- exit if one ( = 1 )script is running
if [ ${PROCNUM} -eq 1 ]
then
die " The script is already running in background. Exit without doing anything."
fi
# ---- if script is not running ( = 0 ), run it once in background
if [ ${PROCNUM} -eq 0 ]
then
/opt/csw/bin/perl ${SCRIPT} &
echo "The script xfer2syslog.pl has been started in background."
exit 0
fi
;;
'stop')
# do nothing and exit if script doesn't run
if [ ${PROCNUM} -eq 0 ]
then
die "Nothing to stop. The script xfer2syslog.pl doesn't run at all."
fi
# if one script runs, kill it
if [ ${PROCNUM} -eq 1 ]
then
PROCID=`ps -ef | ${GREP} xfer2syslog.pl$ | awk '{print $2}'`
kill ${PROCID} || die "Script xfer2syslog.pl cannot be killed."
echo "Script xfer2syslog.pl - PID ${PROCID} has been killed."
fi
# if there are more running scripts, kill them all
if [ ${PROCNUM} -gt 1 ]
then
PROCID=`ps -ef | ${GREP} xfer2syslog.pl$ | awk '{print $2}'`
for i in ${PROCID}
do
kill ${i} || die "Process ${i} cannot be killed."
echo "Killed : Process ${i}"
done
fi
;;
*)
die "Usage : `/usr/bin/basename $0` [stop|start] "
;;
esac
exit 0
|
<?xml version='1.0'?>
<!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'>
<!--
Service manifest for xfer2syslog
by zdudic
-->
<!--
The Service bundle possesses two attributes:
type How this file is to be understood by the framework.
Standard types are: 'archive', 'manifest', and 'profile'.
name A name for the bundle.
-->
<service_bundle type='manifest' name='xfer2syslog'>
<service
name='xfer2syslog'
type='service'
version='1'>
<create_default_instance enabled='false' />
<!-- regardless of method configuration, restarter will not
start multiple instances simultaneously
-->
<single_instance />
<!-- service requires xfer.log file -->
<dependency
name='proftpd_transfer_log_file'
grouping='require_all'
restart_on='refresh'
type='path'>
<service_fmri value='file://localhost/var/log/proftpd/xfer.log' />
</dependency>
<dependency
name='proftpd'
grouping='require_all'
restart_on='refresh'
type='service'>
<service_fmri value='svc:/network/ftp/tcp' />
</dependency>
<dependency
name='system-log'
grouping='require_all'
restart_on='refresh'
type='service'>
<service_fmri value='svc:/system/system-log' />
</dependency>
<!-- start method -->
<exec_method
type='method'
name='start'
exec='/lib/svc/method/svc-xfer2syslog start'
timeout_seconds='10'>
<method_context>
<method_credential user='root' group='root' />
</method_context>
</exec_method>
<!-- stop method -->
<exec_method
type='method'
name='stop'
exec='/lib/svc/method/svc-xfer2syslog stop'
timeout_seconds='10'>
<method_context>
<method_credential user='root' group='root' />
</method_context>
</exec_method>
</service>
</service_bundle>
|