8

I'm currently redirecting the output of a monitoring tool to a file, however what I'd like to do, is to redirect this output to a new file on my request (using a keybinding), without stopping the said tool.

Something like

monitor_program | handle_stdout

Where handle_stdout allows me to define a new file where to put the log at certain point.

I know I could easily write it, but I'm wondering if there's any tool that already allows this.

  • You could probably run logrotate with a custom config file manually, depending on the behaviour of your monitor_program, but that's somewhat hackish. – Ulrich Schwarz May 4 '16 at 12:31
  • It seems like your edit is actually an answer to the question. In that case, please post it as an answer (self-answers are encouraged!) and remove the answer from your question. – cat May 4 '16 at 16:07
9

I'll suggest a named pipe.

  1. Create a pipe mkfifo p (call it whatever you want, if not 'p')

  2. Create a "reader" script that reads from the pipe and writes wherever you like

  3. Tell the monitoring program to write its logs to the named pipe

Here's a sample reader script that reads from a named pipe 'p' and writes the data to an indexed 'mylog' file:

#!/bin/sh

INDEX=0

switchlog() {
  read INDEX < newindex
  echo now writing to "mylog.$INDEX"
}

trap switchlog USR1

while :
do
  cat p >> mylog."$INDEX"
done
  • 2
    You could also trap a signal (USR1 for example) in the reader script as the signal to switch logs. – Jeff Schaller May 4 '16 at 13:09
  • This starts to be something I'd need... However the reader script should be able to change the output based on a my kebinding. And potentially ask me for a new file name to use (although this is optional, even having sequential log names would be fine) – Treviño May 4 '16 at 13:14
  • I edited the sample script to show an example of log-switching with kill -USR1. echo a new number into the 'newindex' file for it to pick up. – Jeff Schaller May 4 '16 at 13:19
  • 1
    just another idea -- if you keep a window open for the running "reader" script, you could trap 'INT' instead of USR1 and just hit Control-C in that window to notify it of a new log filename. – Jeff Schaller May 4 '16 at 13:22
  • 1
    Why read and printf instead of just cat <p >> mylog."$INDEX"? – Wildcard May 4 '16 at 16:01
7

Building up on your SIGINT idea, here using SIGQUIT (Ctrl+\) to you can still use Ctrl+C to stop the whole thing:

(trap '' QUIT; monitor_command) | (
   trap : QUIT
   ulimit -c 0 # prevent core dump so SIGQUIT behaves like SIGINT
               # for cat
   n=0; while n=$((n+1)); file=output.$n.log; do
     printf 'Outputting to "%s"\n' "$file"
     cat > "$file"
   done)

That assumes cat is not a builtin in your shell (so it does get interrupted by you press Ctrl+\).

Note that like in your approach, there's a chance that the SIGQUIT be delivered at the wrong time (in the write system call) causing some data to be lost.

1

You could probably use less and save from there by typing s then the file name you want to save to, then Enter. From How do I write all lines from less to a file?.

  • Unfortunately it's not possible to user more log files, once you've set one you can't redefine a new one. Also you can't clear the log once done. So... Good starting point (thanks), but no enough yet. – Treviño May 4 '16 at 13:24
0

Without knowing more about your "request" its not really possible to answer. If it were based on file size or interval, then rotatelogs (which should come bundled with Apache httpd) would work.

  • Sorry, I didn't say that explicitly, I'm assuming a keybinding that would allow to change the log name. – Treviño May 4 '16 at 13:11
0

Thanks to Jeff Schaller's answer, I ended up with something like this, which basically does what I need, let's call it reader.sh:

#!/bin/sh

INDEX=0
LOGNAME="$INDEX.log"

switchlog() {
  local custom_name
  read -p "Add log name: " custom_name
  INDEX=$((INDEX+1))
  LOGNAME="$(printf "%03d" $INDEX).$custom_name.log"
  echo now writing to $LOGNAME
}

trap switchlog INT
switchlog

while :
do
  read foo < p
  printf "%s\n" "$foo" >> "$LOGNAME"
done

Then it's just about creating a named pipe with mkfifo p, and using two terminals where monitor_program > p and reader.sh are running. I can then stop the reader to set a new log by using Ctrl+C, and enter a new name. Ctrl+Z, as usual then to stop and kill it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.