9

Ubuntu 10.4 Server.

I have a dumb non-interactive legacy service which is running constantly on my server.

It is writing its log to a file with fixed name (/var/log/something.log).

It does not handle any signals to let go of the log file. I need to rotate that log file.

Is there a way to do this properly without changing the application and without losing any data in the log?

4 Answers 4

6

Ignacio's answer intrigued me so I did some research and came up with the Perl script below. If your service will write to a named pipe it should work and be usable with logrotate.

For it to work you need to make your logfile into a named pipe. Rename the existing file then

mkfifo /var/log/something.log

and to edit the 3 filenames to meet your requirements. Run your service then this daemon which should read the named pipe and write it to a new logfile.

If you rename /var/log/somethingrotateable.log then send a HUP to the daemon it will spawn itself and create a new somethingrotateable.log to write to. If using logrotate a postrotate script of kill -HUP 'cat /var/run/yourpidfile.pid'

#!/usr/bin/perl -w
use POSIX ();
use FindBin ();
use File::Basename ();
use File::Spec::Functions;
#
$|=1;
#
# Change the 3 filenames and paths below to meet your requirements.
#
my $FiFoFile = '/var/log/something.log';
my $LogFile = '/var/log/somethingrotateable.log';
my $PidFile = '/var/run/yourpidfile.pid';

# # make the daemon cross-platform, so exec always calls the script
# # itself with the right path, no matter how the script was invoked.
my $script = File::Basename::basename($0);
my $SELF = catfile $FindBin::Bin, $script;
#
# # POSIX unmasks the sigprocmask properly
my $sigset = POSIX::SigSet->new();
my $action = POSIX::SigAction->new('sigHUP_handler',$sigset,&POSIX::SA_NODEFER);
POSIX::sigaction(&POSIX::SIGHUP, $action);

sub sigHUP_handler {
#    print "Got SIGHUP";
    exec($SELF, @ARGV) or die "Couldn't restart: $!\n";
   }

#open the logfile to write to
open(LOGFILE, ">>$LogFile") or die "Can't open $LogFile";
open(PIDFILE, ">$PidFile") or die "Can't open PID File $PidFile";
print PIDFILE "$$\n";
close PIDFILE;
readLog();

sub readLog {
sysopen(FIFO, $FiFoFile,0)  or die "Can't open $FiFoFile";
while ( my $LogLine = <FIFO>) {
    print LOGFILE $LogLine;
   }
}
8

Log to a FIFO, then run a daemon that connects to the other side of the FIFO and has signal handlers that allow you to rotate the log.

2

Send SIGSTOP to the process, copy the log to another name, truncate the log, send SIGCONT to the process, perhaps like this:

pkill -STOP legacyappname
cp /var/log/something.log /var/log/something.log.backup
cat /dev/null > /var/log/something.log
pkill -CONT legacyappname

You could also have logrotate do the magic for you with carefully crafted pre and post rotation scripts and the copytruncate option, like so:

/var/log/something {
    daily
    rotate 5
    copytruncate
    prerotate
        # This assumes you have a pid file, of course.
        # If you don't, this could instead be a pkill like above.
        kill -STOP `cat /var/run/legacyappname.pid`
    endscript
    postrotate
        kill -CONT `cat /var/run/legacyappname.pid`
    endscript
}
4
  • Interesting option, thanks. What will happen with socket connections to the app and from it during the stop? I'm worried about disconnects. Oct 11, 2010 at 19:02
  • Also, the app is being run under runit. What will its monitor do if the app process is stopped? Oct 11, 2010 at 19:03
  • The behavior of the connections would depend on the timeout they are set with and the time it takes to do the actual rotation. I wouldn't imagine that you'd run into any trouble there unless the logs are enormous. I don't have any experience with runit so I couldn't tell you how the monitor will react to stopping the process.
    – mark
    Oct 12, 2010 at 11:54
  • Seems to work perfect with systemd, the service still shows as running well before the log rotation took place. And I am assuming if the particular pid I was stopping, would the child processes of the pid continue running? Feb 23, 2017 at 3:42
1

You could try to let the application log to a named pipe and have some program (for example syslog-ng) that supports proper log rotation mechanisms read the log entries and log them to a file.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .