I have a program whose output I redirect to a log file:
./my_app > log
I would like to clear (i.e. empty) the log from time to time (on demand) and tried various things like
cat "" > log
However it always seems that the original pipe is then disrupted and the program doesn't redirect its output to the log file anymore.
Is there some way to do that?
Update
Note that I cannot modify the application producing the output. It just spits it out to stdout and I want to save it in a log so that I can inspect it when I need it, and clear it when I want. However I shouldn't need to restart the application.
Best Answer
Another form of this problem occurs with long running applications whose logs are periodically rotated. Even if you move the original log (e.g.,
mv log.txt log.1
) and replace it immediately with a file of the same name before any actual logging occurs, if the process is holding the file open, it will either end up writing tolog.1
(because that may still be the open inode) or to nothing.A common way to deal with this (the system logger itself works this way) is to implement a signal handler in the process which will close and reopen its logs. Then, when ever you want to move or clear (by deleting) the log, send that signal to the process immediately afterward.
Here's a simple demonstration for bash -- forgive my cruddy shell skills (but if you are going to edit this for best practices, etc., please make sure you understand the functionality first and test your revision before you edit):
Start this by forking into the background:
Notice it reports its PID to the terminal and then begins logging to
log.txt
. You now have 2 minutes to play around. Wait a few seconds and try:Just plain
kill -2 12356
may work for you here too. Signal 2 is SIGINT (it's also what Ctrl-C does, so you could try this in the foreground and move or remove the logfile from another terminal), which thetrap
should trap. To check;Now let's see if it is still writing to a
log.txt
even though we moved it:Notice it kept going right where it left off. If you don't want to keep the record simply clear the log by deleting it
Check:
Still going.
You can't do this in a shell script for an executed subprocess, unfortunately, because if it is in the foreground, bash's own signal handlers (
trap
s) are suspended, and if you fork it into the background, you can't reassign its output. I.e., this is something you have to implement in your application.However...
If you can't modify the application (e.g., because you did not write it), I have a CLI utility you can use as an intermediary. You could also implement a simple version of this in a script which serves as a pipe to the log:
Let's call this
pipetrap.sh
. Now we need a separate program to test with, mimicking the application you want to log:That will be
test.sh
:These are two separate processes with separate PIDs. To clear
test.sh
's output, which is being funnelled throughpipetrap.sh
:Check:
15858,
test.sh
, is still running and its output is being logged. In this case, no modifications to the application are needed.