3

I'm rotating log files with logrotate with copytruncate, and I need to run a script with the new filename as argument. I understand I can use $1 within postrotate, but that gives me the name of the rotated file - not the one with the date extension.

So basically I have:

/var/log/myapp/server.log

When I run this logrotate config:

/var/log/myapp/server.log {
  copytruncate
  rotate 1008
  dateext
  dateformat -%s
  create 660 syslog syslog
  postrotate
    python3 /opt/myapp/test.py $1 > /dev/null
  endscript
}

I get

/var/log/myapp/server.log <-- (now empty)
/var/log/myapp/server.log-1536844088

Can I run a script on /var/log/myapp/server.log-1536844088 in postrotate somehow?

  • without testing, it seems like you'd have to use the dateformat knowledge and have the script glob for "$1"${dateformat} – Jeff Schaller Sep 13 '18 at 13:37
  • Interesting approach. Unfortunately it doesn't work. – Daniel Sep 13 '18 at 13:43
  • I'm curious what you tried and how it didn't work. – Jeff Schaller Sep 13 '18 at 13:58
2

It's my understanding that logrotate will pass the name of the log file to the script in postrotate; you could use the script and the first parameter and the knowledge that logrotate has created rotated files using the -%s dateformat to generate a list of those files:

import sys
import fnmatch
import os

for file in os.listdir(os.path.dirname(sys.argv[1])):
        if fnmatch.fnmatch(file, os.path.basename(sys.argv[1]) + '-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'):
                print(file)

This is my first python script, so it may not be idiomatic, but hopefully shows the idea. The fnmatch() function uses a glob that should cover you for several years (until late November of 2286), when 9,999,999,999 seconds will roll over to 10,000,000,000. You could "widen" the glob so that it "just" requires "10 digits and then anything":

...
if fnmatch.fnmatch(file, os.path.basename(sys.argv[1]) + '-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]*'):
...
  • Yeah, I came up with that but was hoping there is a more elegant solution within logrotate itself. But this will work. Thanks! – Daniel Sep 13 '18 at 14:06
  • According to the docs, logrotate passes the base log name (given before the curly braces, possibly a wildcarded list), not the rotated names, so you have to come up with them yourself. A fun experiment may be to pass a wildcard on the python3 postrotate line. – Jeff Schaller Sep 13 '18 at 14:08
2

You could add a suffix to your dateformat -%s, like X, then you should be able to find a unique file *X and after renaming it without the X, hand it to your python:

dateformat -%sX
postrotate
  for f in *X; do mv "$f" "${f%X}" && test.py "${f%X}"; done
endscript

I used a for loop to make it a bit less fragile. You may need to check this passes through your /bin/sh correctly.

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.