Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Log rotating with a Bash script

Tags:

I have the following issue:

I have an application, which continuously produces output to stderr and stdout. The output of this application is captured in a logfile (the app is redirected as: &> log.txt ). I don't have any options to produce a proper logging to file for this.

Now, I have a cron job, which runs every hour and beside of doing other things, it also tries to rotate this logfile above, by copying it to log.txt.1 and then creates an empty file and copies it to log.txt

It looks like:

cp log.txt log.txt.1 touch /tmp/empty cp /tmp/empty log.txt 

The problem is, that the application is still writing to it, and because of this I get some very strange stuff in the log.txt.1, it starts with a lot of garbage characters, and the actual log file is somewhere at the end.

Do you have any idea, how to make a correct log rotating for this specific situation (I also tried cat log.txt > log.txt.1, does not work)? Using logrotate for this specific application not an option, there is a whole mechanism behind the scenes that I may not change.

Thanks, f.

like image 731
Ferenc Deak Avatar asked Apr 26 '11 11:04

Ferenc Deak


People also ask

How do you rotate a log file in Linux?

A number of log files are set up for rotation as soon as a Linux system is installed. In addition, certain applications add their own log files and rotation specs when they are installed on the system. The configuration files for log-file rotations can be found in the /etc/logrotate.

Which command is used to rotate logs?

System log files are rotated by the logadm command from an entry in the root crontab file.

How use logrotate command in Linux?

Tells logrotate which command to use when mailing logs. This command should accept two arguments: 1) the subject of the message, and 2) the recipient. The command must then read a message on standard input and mail it to the recipient. The default mail command is /bin/mail -s.

How do you write logs in bash?

To write output of Bash Command to Log File, you may use right angle bracket symbol (>) or double right angle symbol (>>). Right angle braketsymbol (>) : is used to write output of a bash command to a disk file. If the file is not already present, it creates one with the name specified.


1 Answers

Okay, here's an idea, inspired by http://en.wikibooks.org/wiki/Bourne_Shell_Scripting/Files_and_streams

  1. make a named pipe:

    mkfifo /dev/mypipe 
  2. redirect stdout and stderr to the named pipe:

    &> /dev/mypipe 
  3. read from mypipe into a file:

    cat < /dev/mypipe > /var/log/log.txt & 
  4. when you need to log-rotate, kill the cat, rotate the log, and restart the cat.

Now, I haven't tested this. Tell us how it goes.

Note: you can give the named pipe any name, like /var/tmp/pipe1 , /var/log/pipe , /tmp/abracadabra , and so on. Just make sure to re-create the pipe after booting before your logging-script runs.


Alternatively, don't use cat, but use a simple script file:

#!/bin/bash  while : ; do   read line   printf "%s\n" "$line" done 

This script guarantees an output for every newline read. (cat might not start outputting until its buffer is full or it encounters an EOF)


Final -- and TESTED -- attempt

IMPORTANT NOTE: Please read the comments from @andrew below. There are several situations which you need to be aware of.

Alright! Finally got access to my Linux box. Here's how:

Step 1: Make this recorder script:

#!/bin/bash  LOGFILE="/path/to/log/file" SEMAPHORE="/path/to/log/file.semaphore"  while : ; do   read line   while [[ -f $SEMAPHORE ]]; do     sleep 1s   done   printf "%s\n" "$line" >> $LOGFILE done 

Step 2: put the recorder into work:

  1. Make a named pipe:

    mkfifo $PIPENAME 
  2. Redirect your application's STDOUT & STDERR to the named pipe:

    ...things... &> $PIPENAME 
  3. Start the recorder:

    /path/to/recorder.sh < $PIPENAME & 

    You might want to nohup the above to make it survive logouts.

  4. Done!

Step 3: If you need to logrotate, pause the recorder:

touch /path/to/log/file.semaphore mv /path/to/log/file /path/to/archive/of/log/file rm /path/to/log/file.semaphore 

I suggest putting the above steps into its own script. Feel free to change the 2nd line to whatever log-rotating method you want to use.


Note : If you're handy with C programming, you might want to make a short C program to perform the function of recorder.sh. Compiled C programs will certainly be lighter than a nohup-ed detached bash script.


Note 2: David Newcomb provided a helpful warning in the comments: While the recorder is not running then writes to the pipe will block and may cause the program to fail unpredictably. Make sure the recorder is down (or rotating) for as short time as possible.

So, if you can ensure that rotating happens really quickly, you can replace sleep (a built-in command which accepts only integer values) with /bin/sleep (a program that accepts float values) and set the sleep period to 0.5 or shorter.

like image 168
pepoluan Avatar answered Sep 23 '22 06:09

pepoluan