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> |