1

I want to rotate our application logs using logrotate. After each rotation, it executes a script which moves all rotated logs to another directory. For example in /home/dev/logs/frontend, I have these log files:

webapp1-access.log webapp2-access.log anotherapp3-access.log codename-access.log ... 

And my logrotate config file:

$ cat app.daily /home/dev/logs/frontend/*access.log { rotate 1 daily copytruncate compress notifempty missingok lastaction bash /path/to/script.sh endscript } 

And what script.sh does is to create a directory based on the log file name then move the rotated log file there. The webapp1-access.log would be rotated to webapp1-access.log.1.gz then the script will move it to /x/y/webbapp1/renamed.log.gz. And so on for other rotated logs.

When I tested the logrotate using logrotate -fv /path/to/config, and It works perfectly as I expected. Then I put the logrotate config file to /etc/logrotate.d (as a symlink).

Next day I checked /x/y dir, I got:

webbapp1/ <---- created from initial logrotate -fv webbapp1-access.log/ <---- Unexpected anotherapp3/ <---- created from initial logrotate -fv anotherapp3-access.log/ <---- Unexpected codename/ <---- created from initial logrotate -fv codename-access.log/ <---- Unexpected 

The *-access.log/ dirs are created by the logrotate. But running logrotate -vf config multiple times wont produce that unexpected result. That happens when I leave logrotate do its daily rotation.

Why is this happening? How can I fix this?


script.sh

#! /usr/bin/bash exec 3>> /var/log/archived-log.log [ "${1:-}" = "-d" ] && debug=1 environment="frontend" rotateddir="/home/dev/logs/$environment" destdir="/x/y" [ "${debug:-}" ] && echo "DEST DIR: $destdir" log() { timestamp=$(date +"%Y-%m-%d %H:%M:%S") echo "$timestamp: $1" >&3 } for archive in $rotateddir/*.gz; do [ "${debug:-}" ] && echo "ARCHIVE: $archive" [ "${archive##*/}" = "*.gz" ] && continue base_name=$(basename "$archive") [ "${debug:-}" ] && echo "BASENAME: $base_name" extension="${base_name##*.}" [ "${debug:-}" ] && echo "EXT: $extension" newdir_name="${base_name%-*}" [ "${debug:-}" ] && echo "NEWDIR_NAME: $newdir_name" tanggal=$(stat -c %y "$archive" | cut -d" " -f1 | { read dat; date -d $dat +%Y%m%d; }) #jam=$(stat -c %y "$archive" | cut -d" " -f2 | { read dat; date -d $dat +%H%M; }) newdir_path="$destdir/$newdir_name" [ "${debug:-}" ] && echo "NEWDIR_PATH: $newdir_path" #dest_archive="$newdir_path/$tanggal-$jam.log.$extension" dest_archive="$newdir_path/$tanggal.log.$extension" [ "${debug:-}" ] && echo "DEST_ARCHIVE: $dest_archive" [ ! -d "$newdir_path" ] && { if [ "${debug:-}" ]; then echo "Would create $newdir_path" else mkdir -p "$newdir_path" log "Created directory: $newdir_path" fi } [ ! -f "$dest_archive" ] && { if [ "${debug:-}" ]; then echo "Would move $archive to $dest_archive" else rsync -a --no-owner --no-group --remove-source-files "$archive" "$dest_archive" #cp -u --no-preserve=mode,ownership "$archive" "$dest_archive" && rm -f "$archive" log "Relocated $archive to $dest_archive" fi } rotates=$(ls -1 "$newdir_path" | wc -l ) [ "$rotates" -ge 7 ] && { oldest=$(ls -t "$newdir_path" | tail -1) if [ "${debug:-}" ]; then echo "Would delete the oldest archive: $oldest" else rm -f "$newdir_path/$oldest" log "Deleted oldest archive of $base_name : $oldest" fi } done exit 0 

Update

I still don't know why this happens, but finally I decided to run the script by cron few minutes after rotation.

I suspect that this part of my "script.sh" newdir_name="${base_name%-*}" is not evaluated well by logrotate. But again, it worked as expected if I run it forcefully using logrotate -fv config

1
  • Shouldn't be hard to see if "newdir_name="${base_name%-*}" is not evaluated well by logrotate. " - put a set -x at the top and check the stderr. Commented Mar 10, 2020 at 2:37

1 Answer 1

0

Turns out that logrotate executes the script using sh and my script contains bashishms.

From man page:

lastaction/endscript

The lines between lastaction and endscript (both of which must appear on lines by themselves) are executed (using /bin/sh) ...

In the end, I execute my script via crontab few minutes after the logrotate.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.