3

I have the following logrotate script

/path/to/folder {
   daily
   rotate 30
   notifempty
   sharedscripts
   copytruncate
   compress
   dateext


   preremove
     if file --mime-type "$1" | grep -q gzip$; then
          mkdir -p /path/to/archive/folder && cp $1 $_
     fi
   endscript
}

  • What I am trying to achieve:-

    Before removal of a log file after a retention of 30 days, copy to another folder.

I am running this logstash config on debug mode

logrotate -d $CONFIG_FILE

By the looks of the logs, the rotation is working fine, but it does not even run the preremove script. I have not run this config on live yet, as I wanted to test it before doing that.

logrotate version 3.8.6

RPT
  • 728
  • 1
  • 10
  • 29
  • 1
    Notice that `preremove` runs `/bin/sh`, where you might have no `$_` available (at least [POSIX sh](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html) doesn't seem to require it). Also, make sure to quote `"$1"` everywhere, and single quote `'gzip$'`. Try adding debug output like `echo blah >> /tmp/debug` to see if the script gets run. – Benjamin W. Apr 29 '19 at 13:12
  • @BenjaminW. I tried replacing `$_` with the `path/to/archived/folder` - still did not work. I also tried `echo "testing"` in the preremove script. It does not seem to be running. – RPT Apr 29 '19 at 13:59
  • I'm not sure where standard output for `logrotate` goes – did you try redirecting it to a file for the `echo` debug statement? – Benjamin W. Apr 29 '19 at 14:37
  • @BenjaminW. It does not seem to be going into the `preremove` script. Putting an echo outside the `preremove` block throws an error `unknown option 'echo'`. But when it is inside `preremove` block it does not throw that error. – RPT Apr 29 '19 at 14:49
  • @BenjaminW. Has the `preremove` not running issue have to do something with running it on debug mode? I cannot use this script without dry running it and testing it. – RPT Apr 29 '19 at 15:00
  • 1
    I'm not sure, to be honest. I'd try running it in non-debug mode on some test files instead of the real logs. – Benjamin W. Apr 29 '19 at 15:01

3 Answers3

2

I'm not sure whether you're asking why preremove isn't running, or whether your script looks OK.

Preremove, and how to test

I don't believe that logrotate will ever run a preremove script if it's not removing files (per -d). I set up a test case and ran it under strace. The logrotate -d found the files that needed to be removed and wrote that it would have removed them, but did not run the preremove code. Honestly this makes sense to me, and is what I expect, since the preremove could do things as damaging as the deletion itself.

To perform a test, I think you need to reproduce your live environment in another directory and just actually run it. Don't use full size files, just use dummy files with a few lines. Create a script to build your test folder, so you can reproduce the test easily. Use touch to set timestamps. For example:

for n in $(seq 1 30); do
    cp test.log test.log.$n
    gzip test.log.$n
    touch -d "now - $n day" test.log.$n.gz
done

The script itself

  • grep -q gzip$ is wrong. The $ will disappear in the shell parse. You need to enclose this in single quotes.
  • As someone else wrote, I would not expect $_ to work. Repeat the directory name, or use a variable in the script.
  • I don't think you need the \ escapes at EOL, as suggested.
  • You probably want cp -p, as someone suggested.
  • If your files are large, the cp will be slow. If your archive is on the same filesystem, consider using ln (not ln -s!) instead. This will be instant.
  • Using file --mime-type probably works fine, but frankly I'd just base it on the file name in this case, since logrotate will reliably append .gz on any file for which file would return gzip. expr "$1" : '.*gz$' will give a nonzero number as standard output for any $1 that ends in .gz. It will give exactly the number 0 as standard output for a filename that does not end in .gz.
dgc
  • 555
  • 3
  • 7
0

You might be missing line continuation escapes as seen in some examples

preremove
    # debug line
    systemd-cat -t "rot-pre-rm" echo "preremove block, file: $1"
    if file --mime-type "$1" | grep -q gzip$; then \
        cp -p "$1" /path/to/archive/syslog/; \
    fi; \
endscript
LMC
  • 10,453
  • 2
  • 27
  • 52
  • Does not seem to be working running them in the `-d` mode – RPT May 02 '19 at 03:16
  • you can also put the code is a shell script and invoke it. – LMC May 02 '19 at 03:18
  • It seems as though the `preremove` block is not even run. I tried invoking the snippet within `preremove` putting it another shell script with some `echo`. Does not seem to run. – RPT May 02 '19 at 03:25
  • Add `systemd-cat echo "preremove block"` *outside* the if-else, then check with `journalctl`. If systemd is not pesent on your host, use just an echo. May be the `if`conditions are not met. – LMC May 04 '19 at 15:58
0

I think your condition itself is not coming true can you put echo before preremove to debug. Try to execute your if condition manually and see.

# file --mime-type * | grep -i *.1
audit.log.1: text/plain
# file --mime-type * | grep -i *.1$
# file --mime-type * | grep -q *.1$
# file --mime-type * | grep -q *.1
asktyagi
  • 111
  • 1
  • 1
  • 4