Il y a 389 articles et 19 utilisateurs inscrits (ce bandeau est défini dans MediaWiki:Sitenotice)

Rotation des logs tomcat et Pleade

De AJLSM
Version datée du 7 novembre 2025 à 15:14 par Jlarvers (discussion | contributions) (Page créée avec « # 🧩 Archivage mensuel et nettoyage automatique des logs Tomcat / Java ## 🎯 Objectif Ce document présente un script Bash permettant : - D’**archiver automatique... »)
(diff) ← Version précédente | Version actuelle (diff) | Version suivante → (diff)
Aller à la navigation Aller à la recherche
  1. 🧩 Archivage mensuel et nettoyage automatique des logs Tomcat / Java
    1. 🎯 Objectif

Ce document présente un script Bash permettant :

- D’**archiver automatiquement** les fichiers journaliers et mensuels produits par des applications Java/Tomcat ; - De créer **une archive compressée `.gz` unique par mois et par type de log** ; - De **supprimer les fichiers quotidiens** une fois archivés correctement ; - De **purger les archives** plus anciennes qu’une période définie ; - De gérer **plusieurs formats de nommage** de fichiers :

 - `manager.2025-11-07.log` (format **point**)  
 - `sdx-20251107.log` (format **tiret**)  
 - `pleade-stats-202511.log` (format **tiret mensuel**).

---

    1. Paramètres à modifier selon l'installation

```

  1. ---------- PARAMÈTRES À ADAPTER ----------

DIRS=(

 "/home/ajlsm/tomcats/preprod/logs"
 "/home/ajlsm/tomcats/slecture/logs"
 "/home/ajlsm/tomcats/internet-consultation/logs"
 "/home/ajlsm/tomcats/internet-consultation/webapps/pleade/WEB-INF/logs"
 "/home/ajlsm/tomcats/slecture/webapps/pleade/WEB-INF/logs"
 "/home/ajlsm/tomcats/preprod/webapps/pleade/WEB-INF/logs"

)

RETENTION_MONTHS=6 BATCH_SIZE=0 # 0 = désactivé ; 20 = regrouper dès qu'il y a 20 fichiers DRY_RUN=0 # 1 = ne rien écrire/supprimer, juste logguer NORMALIZE_SUFFIX=1 # 1 = corriger *.txt-YYYYMMDD / *.log-YYYYMMDD avant archivage ARCHIVE_CURRENT_MONTH=0 # 1 = inclure le mois courant (ré-agrège au fil du mois)

  1. Familles par style + extensions

declare -A FAMILIES_DOT FAMILIES_DOT["manager"]="log" FAMILIES_DOT["localhost_access_log"]="txt" FAMILIES_DOT["catalina"]="log" FAMILIES_DOT["localhost"]="log" FAMILIES_DOT["host-manager"]="log"

declare -A FAMILIES_HYPH FAMILIES_HYPH["auto-publication"]="log" FAMILIES_HYPH["cocoon"]="log" FAMILIES_HYPH["oai"]="log" FAMILIES_HYPH["publication"]="log" FAMILIES_HYPH["sdx"]="log"

declare -A FAMILIES_HMTH FAMILIES_HMTH["pleade-stats"]="log" ```

    1. ⚙️ 1. Script d’archivage (`archive-logs.sh`)

Créer le fichier : `/usr/local/sbin/archive-logs.sh` et lui donner les droits d’exécution (`chmod +x /usr/local/sbin/archive-logs.sh`).

```bash

  1. !/usr/bin/env bash
  2. archive-logs.sh — regroupe les logs existants en archives mensuelles uniques (.gz)
  3. - Supporte trois styles de naming :
  4. 1) DOT  : base.YYYY-MM-DD.ext (ex: manager.2025-11-07.log)
  5. 2) HYPH : base-YYYYMMDD.ext (ex: sdx-20251107.log)
  6. 3) HMTH : base-YYYYMM.ext (ex: pleade-stats-202511.log)
  7. - Ne modifie pas les fichiers lors de la lecture ; supprime uniquement si l’archive est OK
  8. - Purge les archives plus vieilles que RETENTION_MONTHS
  9. - (Optionnel) Normalise *.txt-YYYYMMDD / *.log-YYYYMMDD avant archivage

set -euo pipefail IFS=$'\n\t' umask 022

  1. ---------- PARAMÈTRES À ADAPTER ----------

DIRS=(

 "/home/ajlsm/tomcats/preprod/logs"
 "/home/ajlsm/tomcats/slecture/logs"
 "/home/ajlsm/tomcats/internet-consultation/logs"
 "/home/ajlsm/tomcats/internet-consultation/webapps/pleade/WEB-INF/logs"
 "/home/ajlsm/tomcats/slecture/webapps/pleade/WEB-INF/logs"
 "/home/ajlsm/tomcats/preprod/webapps/pleade/WEB-INF/logs"

)

RETENTION_MONTHS=6 BATCH_SIZE=0 # 0 = désactivé ; 20 = regrouper dès qu'il y a 20 fichiers DRY_RUN=0 # 1 = ne rien écrire/supprimer, juste logguer NORMALIZE_SUFFIX=1 # 1 = corriger *.txt-YYYYMMDD / *.log-YYYYMMDD avant archivage ARCHIVE_CURRENT_MONTH=0 # 1 = inclure le mois courant (ré-agrège au fil du mois)

  1. Familles par style + extensions

declare -A FAMILIES_DOT FAMILIES_DOT["manager"]="log" FAMILIES_DOT["localhost_access_log"]="txt" FAMILIES_DOT["catalina"]="log" FAMILIES_DOT["localhost"]="log" FAMILIES_DOT["host-manager"]="log"

declare -A FAMILIES_HYPH FAMILIES_HYPH["auto-publication"]="log" FAMILIES_HYPH["cocoon"]="log" FAMILIES_HYPH["oai"]="log" FAMILIES_HYPH["publication"]="log" FAMILIES_HYPH["sdx"]="log"

declare -A FAMILIES_HMTH FAMILIES_HMTH["pleade-stats"]="log"

  1. -------------------------------------------

log() { printf "[%s] %s\n" "$(date '+%Y-%m-%d %H:%M:%S')" "$*"; }

current_month() { date +%Y-%m; }

month_from_dot_name() { sed -nE 's/.*([0-9]{4})-([0-9]{2})-[0-9]{2}\.[^.]+$/\1-\2/p'; } month_from_hyph_name() { awk 'match($0, /-[0-9]{8}\.[^.]+$/){y=substr($0,RSTART+1,4);m=substr($0,RSTART+5,2);print y"-"m}'; } month_from_hmth_name() { awk 'match($0, /-[0-9]{6}\.[^.]+$/){y=substr($0,RSTART+1,4);m=substr($0,RSTART+5,2);print y"-"m}'; }

do_mv() { (( DRY_RUN )) && log "[DRY] mv '$1' '$2'" || mv -- "$1" "$2"; } do_rm() { (( DRY_RUN )) && log "[DRY] rm -f $*" || rm -f -- "$@"; } do_gzip_f() { (( DRY_RUN )) && log "[DRY] gzip -f '$1'" || gzip -f "$1"; }

normalize_suffixes() {

 for d in "${DIRS[@]}"; do
   -d "$d"  || continue
   shopt -s nullglob
   for f in "$d"/*.txt-????????; do
     [[ "$f" =~ ^(.*\.txt)-[0-9]{8}$ ]] || continue
     new="${BASH_REMATCH[1]}"
     -e "$new"  && { log "Skip (existe déjà) : $new"; continue; }
     do_mv "$f" "$new" && log "$f → $new"
   done
   for f in "$d"/*.log-????????; do
     [[ "$f" =~ ^(.*\.log)-[0-9]{8}$ ]] || continue
     new="${BASH_REMATCH[1]}"
     -e "$new"  && { log "Skip (existe déjà) : $new"; continue; }
     do_mv "$f" "$new" && log "$f → $new"
   done
   shopt -u nullglob
 done

}

build_outname() {

 local style="$1" dir="$2" base="$3" month="$4" ext="$5"
 if "$style" == "hyph" ; then
   printf "%s/%s-%s.%s.gz" "$dir" "$base" "$month" "$ext"
 else
   printf "%s/%s.%s.%s.gz" "$dir" "$base" "$month" "$ext"
 fi

}

make_monthly_archive() {

 local style="$1"; shift
 local dir="$1"; shift
 local base="$1"; shift
 local ext="$1"; shift
 local -a list=( "$@" )
 [[ ${#list[@]} -eq 0 ]] && return 0
 local month out tmp
 case "$style" in
   dot)  month="$(basename -- "${list[0]}" | month_from_dot_name)";;
   hyph) month="$(basename -- "${list[0]}" | month_from_hyph_name)";;
   hmth) month="$(basename -- "${list[0]}" | month_from_hmth_name)";;
 esac
 -z "$month"  && { log "⚠️ Impossible d’extraire le mois pour ${list[0]}"; return 0; }
 out="$(build_outname "$style" "$dir" "$base" "$month" "$ext")"
 tmp="${out}.tmp"
 if -s "$out" ; then
   log "Archive déjà présente: $out"
   return 0
 fi
 log "Création archive mensuelle: $out"
 : > "$tmp"
 for f in "${list[@]}"; do
   (( DRY_RUN )) && log "[DRY] cat '$f' >> '$tmp'" || cat -- "$f" >> "$tmp"
 done
 (( DRY_RUN )) && log "[DRY] gzip -f '$tmp' && mv '${tmp}.gz' '$out'" || { do_gzip_f "$tmp"; do_mv "${tmp}.gz" "$out"; }
 if | ( $DRY_RUN -eq 1 ) ; then
   log "Archive OK ⇒ suppression des fichiers (${#list[@]})"
   do_rm "${list[@]}"
 else
   log "⚠️ Échec création archive: $out (aucune suppression faite)"
 fi

}

process_style() {

 local style="$1"; shift
 declare -n families="$1"
 local nowm; nowm="$(current_month)"
 for d in "${DIRS[@]}"; do
   -d "$d"  || continue
   for base in "${!families[@]}"; do
     read -r -a exts <<< "${families[$base]}"
     for ext in "${exts[@]}"; do
       shopt -s nullglob
       local -a files=()
       case "$style" in
         dot)  files=( "$d"/${base}.[0-9][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9].${ext} );;
         hyph) files=( "$d"/${base}-[0-9][0-9][0-9][0-9][0-1][0-9][0-3][0-9].${ext} );;
         hmth) files=( "$d"/${base}-[0-9][0-9][0-9][0-9][0-1][0-9].${ext} );;
       esac
       shopt -u nullglob
       [[ ${#files[@]} -eq 0 ]] && continue
       declare -A months=()
       local f m
       for f in "${files[@]}"; do
         case "$style" in
           dot)  m="$(basename -- "$f" | month_from_dot_name)";;
           hyph) m="$(basename -- "$f" | month_from_hyph_name)";;
           hmth) m="$(basename -- "$f" | month_from_hmth_name)";;
         esac
         -z "$m"  && continue
         if (( ! ARCHIVE_CURRENT_MONTH )) && "$m" == "$nowm" ; then
           continue
         fi
         months["$m"]=1
       done
       [[ ${#months[@]} -eq 0 ]] && continue
       for m in "${!months[@]}"; do
         local -a month_files=()
         y="${m%%-*}"; mm="${m##*-}"
         while IFS= read -r line; do month_files+=( "$line" ); done < <(
           printf "%s\n" "${files[@]}" |
           grep -E "/${base}[-\.](${y}${mm}|${m})" |
           LC_ALL=C sort
         )
         [[ ${#month_files[@]} -eq 0 ]] && continue
         make_monthly_archive "$style" "$d" "$base" "$ext" "${month_files[@]}"
       done
     done
   done
 done

}

purge_old_archives() {

 local days=$(( RETENTION_MONTHS * 31 ))
 for d in "${DIRS[@]}"; do
   -d "$d"  || continue
   find "$d" -maxdepth 1 -type f \
     \( -regex '.*/[^/]+\.[0-9]{4}-[0-9]{2}\.(log|txt)\.gz' \
        -o -regex '.*/[^/]+-[0-9]{4}-[0-9]{2}\.(log|txt)\.gz' \) \
     -mtime +$days -print -delete
 done

}

LOCK="/var/lock/archive-logs.lock" mkdir -p /var/lock exec 9>"$LOCK" || exit 1 flock -n 9 || { echo "Déjà en cours, abandon."; exit 0; } trap 'flock -u 9' EXIT

log "=== Début archivage logs ===" if (( NORMALIZE_SUFFIX )); then

 log "Normalisation des suffixes *.txt-YYYYMMDD / *.log-YYYYMMDD"
 normalize_suffixes

fi process_style dot FAMILIES_DOT process_style hyph FAMILIES_HYPH process_style hmth FAMILIES_HMTH purge_old_archives log "=== Fin archivage logs ===" ```

    1. 🕐 2. Cron automatique
      1. ➤ Exécution mensuelle (chaque 1er du mois à 06:10)

``` 10 6 1 * * /usr/local/sbin/archive-logs.sh >> /var/log/archive-logs.log 2>&1 ```

      1. ➤ Option quotidienne (si BATCH_SIZE > 0))

``` 5 6 * * * /usr/local/sbin/archive-logs.sh >> /var/log/archive-logs.log 2>&1 ```

    1. 🧹 3. Renommage automatique

Si certains fichiers sont mal nommés (suffixes dupliqués comme `.txt-YYYYMMDD` ou `.log-YYYYMMDD`), le script les **corrige automatiquement** grâce à `NORMALIZE_SUFFIX=1`.\ Tu peux aussi lancer cette normalisation seule : ``` bash /usr/local/sbin/archive-logs.sh ```

    1. ✅ 4. Résumé des familles gérées

| Style | Familles | Exemple fichier | Archive produite | | -------- | -------------------------------------------------------------------------- | ------------------------- | ----------------------------- | | **DOT** | `manager`, `localhost_access_log`, `catalina`, `localhost`, `host-manager` | `manager.2025-11-07.log` | `manager.2025-11.log.gz` | | **HYPH** | `auto-publication`, `cocoon`, `oai`, `publication`, `sdx` | `sdx-20251107.log` | `sdx-2025-11.log.gz` | | **HMTH** | `pleade-stats` | `pleade-stats-202511.log` | `pleade-stats-2025-11.log.gz` |

    1. 🔒 5. Sécurité & cohérence
  • Verrou via `/var/lock/archive-logs.lock` pour éviter les exécutions simultanées.
  • Test à blanc possible avec `DRY_RUN=1`.
  • Purge automatique après `RETENTION_MONTHS` mois.
  • Aucune altération des fichiers pendant la lecture : suppression uniquement après création réussie de l’archive.
    1. 🧭 Exemple avant/après
      1. Avant

``` sdx-20251101.log sdx-20251102.log sdx-20251103.log ... pleade-stats-202510.log

```

      1. Après exécution

``` sdx-2025-11.log.gz pleade-stats-2025-10.log.gz ```

    1. 📦 Résumé technique

| Élément | Valeur | | -------------------- | --------------------------------- | | **Fichier script** | `/usr/local/sbin/archive-logs.sh` | | **Logs d’exécution** | `/var/log/archive-logs.log` | | **Cron mensuel** | `10 6 1 * *` | | **Rétention** | 6 mois (`RETENTION_MONTHS=6`) | | **Mode test** | `DRY_RUN=1` | | **Verrouillage** | `/var/lock/archive-logs.lock` |