#!/usr/bin/env bash # # Archive old log files into compressed tarballs. # # This script is useful when logrotate is unavailable or when application logs # need custom archival handling. It does not delete active logs by default. # # Usage: # bash log_rotate_archive.sh --source /var/log/myapp --archive /backup/logs # bash log_rotate_archive.sh --source ./logs --archive ./archives --older-than-days 3 --delete-originals # # Options: # --source DIR Directory containing log files. # --archive DIR Directory where archives will be stored. # --older-than-days N Archive files older than N days. Default: 7. # --delete-originals Delete original files after a successful archive. # --help Show this help message. set -Eeuo pipefail source_dir="" archive_dir="" older_than_days="7" delete_originals=false usage() { sed -n '2,21p' "$0" | sed 's/^# \{0,1\}//' } log() { printf '[%s] %s\n' "$(date -Is)" "$*" } while [[ "$#" -gt 0 ]]; do case "$1" in --source) source_dir="${2:-}" shift 2 ;; --archive) archive_dir="${2:-}" shift 2 ;; --older-than-days) older_than_days="${2:-}" [[ "$older_than_days" =~ ^[0-9]+$ ]] || { printf 'ERROR: --older-than-days must be an integer.\n' >&2; exit 1; } shift 2 ;; --delete-originals) delete_originals=true shift ;; --help|-h) usage exit 0 ;; *) printf 'ERROR: unknown option: %s\n' "$1" >&2 usage >&2 exit 1 ;; esac done [[ -d "$source_dir" ]] || { printf 'ERROR: source directory does not exist: %s\n' "$source_dir" >&2; exit 1; } [[ -n "$archive_dir" ]] || { printf 'ERROR: --archive is required.\n' >&2; exit 1; } mkdir -p "$archive_dir" timestamp="$(date +%Y%m%d-%H%M%S)" manifest="$(mktemp)" archive_file="${archive_dir}/logs-${timestamp}.tar.gz" find "$source_dir" -type f -name '*.log' -mtime "+${older_than_days}" -print > "$manifest" if [[ ! -s "$manifest" ]]; then log "No log files older than ${older_than_days} days were found." rm -f "$manifest" exit 0 fi log "Creating archive: ${archive_file}" tar -czf "$archive_file" --files-from "$manifest" if [[ ! -s "$archive_file" ]]; then printf 'ERROR: archive was not created or is empty: %s\n' "$archive_file" >&2 rm -f "$manifest" exit 1 fi if [[ "$delete_originals" == true ]]; then log "Deleting archived original files." xargs -r rm -f < "$manifest" fi rm -f "$manifest" log "Log archive completed successfully."