8

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?

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

4 Answers 4

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]*'):
...
2
  • Yeah, I came up with that but was hoping there is a more elegant solution within logrotate itself. But this will work. Thanks!
    – Daniel
    Commented Sep 13, 2018 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
    Commented Sep 13, 2018 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.

1

from man logrotate:

Normally, the absolute path to the log file is passed as the first argument to the script and the absolute path to the final rotated log file is passed as the second argument to the script.

I think you just need to check the second argument.

0
postrotate
  python3 /opt/myapp/test.py $1-`date '+%Y%m%d'` > /dev/null
endscript

This will work as long as it's run the same day.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .